Open TimothyWatkins opened 6 years ago
Hi @TimothyWatkins, The only other option we have right now for publishing extensions is by using the Publish-NavApp Powershell command as part of the management module. https://docs.microsoft.com/en-us/powershell/module/microsoft.dynamics.nav.apps.management/publish-navapp?view=dynamicsnav-ps-2018
Yes, correct, but not to a remote server right?
Sent from my iPhone
On 27 Jun 2018, at 00:13, Thomas Pedersen notifications@github.com<mailto:notifications@github.com> wrote:
Hi @TimothyWatkinshttps://github.com/TimothyWatkins, The only other option we have right now for publishing extensions is by using the Publish-NavApp Powershell command as part of the management module. https://docs.microsoft.com/en-us/powershell/module/microsoft.dynamics.nav.apps.management/publish-navapp?view=dynamicsnav-ps-2018
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/Microsoft/AL/issues/2734#issuecomment-400323889, or mute the threadhttps://github.com/notifications/unsubscribe-auth/ASyWAjcJnpJuIj5bkHVTqXR1XVA0oM2mks5uAkF1gaJpZM4U39V_.
You can. Create a powershell session to the remote server. Copy the File to the remote server. Invoke your publish script on remote server session
$PSServerSession = New-PSSession $RemoteServer Copy-Item -ToSession $PSServerSession -Path $AppFilePath -Destination "$($ServerFilePath)"
Invoke-Command -Session $PSServerSession -ScriptBlock { Import-Module 'C:\Program Files (x86)\Microsoft Dynamics NAV\110\RoleTailored Client\Microsoft.Dynamics.Nav.Model.Tools.psd1' -WarningAction SilentlyContinue | out-null Import-Module 'C:\Program Files\Microsoft Dynamics NAV\110\Service\NavAdminTool.ps1' -WarningAction SilentlyContinue | out-null Import-Module 'C:\Program Files (x86)\Microsoft Dynamics NAV\110\RoleTailored Client\Microsoft.Dynamics.Nav.Apps.Tools.psd1' -WarningAction SilentlyContinue | out-null Publish-NAVApp -ServerInstance $($Using:ServerInstance) -Path "$($Using:ServerFilePath)" -SkipVerification }
You can use the WebDeploy.exe that sits in the same directory as the alc compiler (vs code extension directory), it requires dev port of course.
%userprofile%\.vscode\extensions\ms-dynamics-smb.al-2.1.69331\bin\webdeploy.exe
Here part of some c# code for a standalone installer that uses webdeploy.exe:
var argsBuilder = new List<string>();
argsBuilder.Add("publish");
argsBuilder.Add($"--Directory \"{workingDir}\"");
argsBuilder.Add($"--PackageFileName \"{packageFile}\"");
argsBuilder.Add($"--Authentication {Authentication}");
argsBuilder.Add($"--Server {Server}");
argsBuilder.Add($"--ServerInstance {Instance}");
var args = string.Join(" ", argsBuilder);
var startInfo = new ProcessStartInfo("webdeploy.exe", args);
Note: Authentication with Windows is easy, but UserPassword ist not... But it can be done
@DennisReinecke: you would Need to be admin on the remote machine though, wouldn't you?
Sorry I dont know. I'm an Inhouse-Dev and I got Admin rights on our Server.
You dont have to provide admin rights to every developer. you can run the Powershell Session with different Credentials or with SSH. Check New-PSSession Docu
Have a look at this script:
https://github.com/microsoft/navcontainerhelper/blob/master/AppHandling/Publish-NavContainerApp.ps1
Look at the variable "useDevEndpoint", that part of the code can easily be extracted for your purpose and used outside of docker. Though, it does not handle an upgrade of an app, so it would require you to use "SchemaUpdateMode=recreate", eg not suitable for production environments. If you find a way to do an upgrade, please tell me.
As far as i know the only way to do CD in Production (or anywhere with real data upgrades) is by using the regular PS commands at least that is what we do in our pipeline (open a pssession on the service tier and execute the required commands)
To use the dev endpoint for this would be a lot easier and more robust...
@TimothyWatkins @DennisReinecke @marknitek @mattiasboustedt what advantages do you see to using the DEV endpoint for publishing extensions vs using the management commandlets?
@atoader The powershell cmdlets only work if you are on the same machine as the service tier. If i want to do deployment with an Azure DevOps Agent i need to open a pssession to the service tier machine and invoke the cmdlets there. This is not a great Solution. In fact in our scenario we use docker containers and therefore need to open another pssession to the container to invoke the cmdlets. (=> pssession in a pssession) This is a lot of extra work just for a simple publish/install task.
If we could use the dev endpoints for that it would be a simple http call that works from anywhere and also from a machine without powershell access (lets say a non windows machine for example).
There is also a security impact if you need access to the service tier machine. It is common practice to not allow access to these machines for regular developers. If we can use the endpoint for that, no access rights to the machine would be required to make deployments.
I dont know if this will help our development and deployments - but we are inhouse and have full access on all our servers. I was playing around with all this powershell possibilities alot. Now we only need 1 powershell function to:
if i cannot handle all this steps via DEV endpoint, i dont see any advantages and i will stick to powershell.
I've posted an idea to Microsoft regarding this (more or less, at least), though it seems like it is currently not in their roadmap.
https://experience.dynamics.com/ideas/idea/?ideaid=58a25895-668b-e911-80e7-0003ff68e84c
@mattiasboustedt upgrade is automatically ran if the extension you publish has a higher version than the extension installed on the server. This feature is available in the latest development preview. Please try it out and let us know if you encounter any problems by opening an issue here.
That's great news @atoader, thank you for the information. I will definitely try it out!
I really do not understand why do we need to have access to the Service tier, have to use Power-shell and be admin to publish an app on prem. On cloud there is a page 2507 "Upload And Deploy Extension" which is used for remote deployment. Why can't we use the same thing onprem ?
One of our customer does not want developers to have access on the service tier, because of security reasons e.g. financial data exchanged via Service Tier. Currently we are facing a misery every time when we need to update the extension. As we need to send the app to the IT manager so he can publish it.
I agree with most of the points above. if VS Code can publish an app to a remote server (via dev endpoint), why isn't there a way to do it from the command line?
@mattiasboustedt upgrade is automatically ran if the extension you publish has a higher version than the extension installed on the server. This feature is available in the latest development preview. Please try it out and let us know if you encounter any problems by opening an issue here.
Haven't had a chance to try this until now, works great so far. Will do some further and more thorough testing.
Here's a one-liner for those of you who would like to try (tried on a UNIX system, but the principle is the same):
curl -u username:password -X POST -F file='@yourApp.app' http://containerName:7049/DevServerInstance/dev/apps?SchemaUpdateMode=synchronize -v
I've used freddies aproach in the Publish-AppInBcContainer Script and put that into a function:
function Publish-AppToDevEndpoint {
param(
[Parameter(Mandatory = $true)]
[ValidateScript( { Test-Path "$_" })]
[String]
$appFile,
[Parameter(Mandatory = $true)]
[PSCredential]
$credential,
[Parameter(Mandatory=$true)]
[ValidatePattern('http[s]?://.*')]
[String]
$devEndpointUri,
[Parameter(Mandatory=$true)]
[int]
$devPort,
[Parameter(Mandatory=$true)]
[string]
$instanceName
)
Add-Type -AssemblyName System.Net.Http
$handler = New-Object System.Net.Http.HttpClientHandler
$HttpClient = [System.Net.Http.HttpClient]::new($handler)
$pair = ("$($Credential.UserName):" + [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($credential.Password)))
$bytes = [System.Text.Encoding]::ASCII.GetBytes($pair)
$base64 = [System.Convert]::ToBase64String($bytes)
$HttpClient.DefaultRequestHeaders.Authorization = New-Object System.Net.Http.Headers.AuthenticationHeaderValue("Basic", $base64);
$HttpClient.Timeout = [System.Threading.Timeout]::InfiniteTimeSpan
$HttpClient.DefaultRequestHeaders.ExpectContinue = $false
$url = "$($devEndpointUri):$port/$instanceName/dev/apps?SchemaUpdateMode=forcesync"
$appName = [System.IO.Path]::GetFileName("$appFile")
$multipartContent = [System.Net.Http.MultipartFormDataContent]::new()
$FileStream = [System.IO.FileStream]::new("$appFile", [System.IO.FileMode]::Open)
try {
$fileHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
$fileHeader.Name = "$AppName"
$fileHeader.FileName = "$appName"
$fileHeader.FileNameStar = "$appName"
$fileContent = [System.Net.Http.StreamContent]::new($FileStream)
$fileContent.Headers.ContentDisposition = $fileHeader
$multipartContent.Add($fileContent)
Write-Host "Publishing $appName to $url"
$result = $HttpClient.PostAsync($url, $multipartContent).GetAwaiter().GetResult()
if (!$result.IsSuccessStatusCode) {
$message = "Status Code $($result.StatusCode) : $($result.ReasonPhrase)"
try {
$resultMsg = $result.Content.ReadAsStringAsync().Result
try {
$json = $resultMsg | ConvertFrom-Json
$message += "`n$($json.Message)"
}
catch {
$message += "`n$resultMsg"
}
}
catch {}
throw $message
}
else {
Write-Host "Success: $appName was published and installed"
}
}
finally {
$FileStream.Close()
}
}
Usage:
$cedential = New-Object System.Management.Automation.PSCredential ("navaccount", ("navaccount" | ConvertTo-SecureString -AsPlainText -Force))
Publish-AppToDevEndPoint -appFile "Path\to\my.app" -credential $credential -devEndpointUri "http:\\localhost" -devPort 7049 -instanceName BC
NOTE:
http://localhost
-devport 7049
-instanceName BC
to the ScriptYou can use the WebDeploy.exe that sits in the same directory as the alc compiler (vs code extension directory), it requires dev port of course.
%userprofile%\.vscode\extensions\ms-dynamics-smb.al-2.1.69331\bin\webdeploy.exe
Here part of some c# code for a standalone installer that uses webdeploy.exe:
var argsBuilder = new List<string>(); argsBuilder.Add("publish"); argsBuilder.Add($"--Directory \"{workingDir}\""); argsBuilder.Add($"--PackageFileName \"{packageFile}\""); argsBuilder.Add($"--Authentication {Authentication}"); argsBuilder.Add($"--Server {Server}"); argsBuilder.Add($"--ServerInstance {Instance}"); var args = string.Join(" ", argsBuilder); var startInfo = new ProcessStartInfo("webdeploy.exe", args);
Note: Authentication with Windows is easy, but UserPassword ist not... But it can be done
Hi, How use userpassword with webdeploy ? I saw a userpasswordcache.dat but how generate it ? Thanks
Is there a method of publishing a compiled nav app file to a remote host? VSCode does it so neatly with AL:Publish which uses a variety of parameters from the launch.json file.
Using the alc.exe is a good tool to compile AL code locally but I'm missing a method of publishing and installing the compiled app remotely to the server. Specifically, this could allow an automatic build and release process in VSTS to dev and test environments...
Any ideas would be appreciated.