Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Import-BcConfigurationPackage function #2719

Closed
wants to merge 2 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions BcSaaS/Import-BcConfigurationPackage.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
<#
.Synopsis
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move to the SaaS folder instead of BcSaaS (I might have renamed the folder)
Also please rename to Import-ConfigPackageToBcEnvironment

Function for importing and applying configuration package to online tenant
.Parameter environment
Name of the environment inside the tenant in which you want to publish the Per Tenant Extension Apps
.Parameter companyName
Company Name to import the package to
.Parameter packageFile
File with a package to import. Package code inside file must be equal to packageCode parameter
.Parameter packageCode
Package will be created with specified code
.Parameter packageName
Package will be created with specified name
.Parameter packageLang
Package will be created with specified language id, en-US (1033) by default.
.Parameter importPackage
Enable the switch to import the package after upload
.Parameter applyPackage
Enable the switch to apply the package after import
.Parameter useNewLine
Add this switch to add a newline to progress indicating periods during wait.
Azure DevOps doesn't update logs until a newline is added.

#>
function Import-BcConfigurationPackage {
Param(
[Parameter(Mandatory=$true)]
[Hashtable] $bcAuthContext,
[Parameter(Mandatory=$true)]
[string] $environment,
[Parameter(Mandatory=$false)]
[string] $companyName,
[Parameter(Mandatory=$true)]
$packageFile,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is called configPackage in the corresponding function for containers
It would be OK to add an alias called packageFile (to both functions)

[Parameter(Mandatory=$true)]
$packageCode,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The packageCode, is that the same as is called packageId in the similar function on containers?
I think parameters should be called the same in both

[Parameter(Mandatory=$false)]
$packageName = "",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

packageName is auto-calculated in the other function using something like this:

            if (!$packageIdSpecified) {
                $packageInfo = Get-PackageInfoFromRapidStartFile $configPackage
                if ($packageInfo) {
                    $packageId = $packageInfo.Code
                }
                else {
                    $packageId = [System.IO.Path]::GetFileNameWithoutExtension($configPackage)
                    $packageId = $packageId.SubString(0, [System.Math]::Min(20, $packageId.Length))
                }
             }

and then the packageId is used as both name and code.
Is this wrong?

[Parameter(Mandatory=$false)]
$packageLang = 1033,
[switch] $importPackage,
[switch] $applyPackage,
[switch] $useNewLine
)

$telemetryScope = InitTelemetryScope -name $MyInvocation.InvocationName -parameterValues $PSBoundParameters -includeParameters @()
try {

$newLine = @{}
if (!$useNewLine -and !$VerbosePreference) {
$newLine = @{ "NoNewLine" = $true }
}

$bcAuthContext = Renew-BcAuthContext -bcAuthContext $bcAuthContext

try {
$automationApiUrl = "$($bcContainerHelperConfig.apiBaseUrl.TrimEnd('/'))/v2.0/$environment/api/microsoft/automation/v2.0"

$authHeaders = @{ "Authorization" = "Bearer $($bcauthcontext.AccessToken)" }
$companies = Invoke-RestMethod -Headers $authHeaders -Method Get -Uri "$automationApiUrl/companies" -UseBasicParsing
$company = $companies.value | Where-Object { ($companyName -eq "") -or ($_.name -eq $companyName) } | Select-Object -First 1
if (!($company)) {
throw "No company $companyName"
}
$companyId = $company.id
Write-Host "Company $companyName has id $companyId"


Write-Host "Creating configuration package:"
$body = @{
"code" = $packageCode
"packageName" = $packageName
"languageId" = $packageLang
}
$body | ConvertTo-Json | Out-Host

$confPackage = Invoke-RestMethod -Headers $authHeaders -Method Post -Uri "$automationApiUrl/companies($companyId)/configurationPackages" -Body ($Body | ConvertTo-Json) -ContentType 'application/json' -Verbose:$VerbosePreference

$confPackageId = $confPackage.id
$confPackageCode = $confPackage.code
Write-Host "Created configuration package $confPackageCode with id $confPackageId"


Write-Host @newLine "Uploading package file $packageFile..."
$response = Invoke-WebRequest -Headers ($authHeaders+(@{"If-Match" = "*"})) -Method Patch -UseBasicParsing -Uri "$automationApiUrl/companies($companyId)/configurationPackages($confPackageId)/file('$confPackageCode')/content" -ContentType 'application/octet-stream' -InFile $packageFile -Verbose:$VerbosePreference
if ($response.StatusCode -eq 204) {
Write-Host "Success"
} else {
Write-Host "Response was:"
Write-Host $response
}


if ($importPackage) {
Write-Host @newLine "Importing package"
Invoke-RestMethod -Headers $authHeaders -Method Post -Uri "$automationApiUrl/companies($companyId)/configurationPackages($confPackageId)/Microsoft.NAV.import" -ContentType 'application/json' -Verbose:$VerbosePreference
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If uploading the configuration package could take more than 60 minutes, then you should renew the authcontext and create a new authHeaders before invoking the next webrequest as the accesstoken has a max. duration of 60 minutes.


$completed = $false
$sleepSeconds = 5
while (!$completed)
{
Start-Sleep -Seconds $sleepSeconds

$packageStatus = Invoke-RestMethod -Headers $authHeaders -Method Get -Uri "$automationApiUrl/companies($companyId)/configurationPackages($confPackageId)" -Verbose:$VerbosePreference

if ($packageStatus.importStatus -eq "InProgress") {
Write-Host @newLine "."
$completed = $false
}
elseif ($packageStatus.importStatus -eq "Completed") {
Write-Host $packageStatus.importStatus
$completed = $true
}
elseif ($packageStatus.importStatus -eq "Error") {
Write-Host $packageStatus.importStatus
throw $packageStatus.importError
}
}
}

if ($importPackage -and $applyPackage) {
Write-Host @newLine "Applying package"
Invoke-RestMethod -Headers $authHeaders -Method Post -Uri "$automationApiUrl/companies($companyId)/configurationPackages($confPackageId)/Microsoft.NAV.apply" -ContentType 'application/json' -Verbose:$VerbosePreference
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Importing the configuration package could take more than 60 minutes, then you should renew the authcontext and create a new authHeaders before invoking the next webrequest as the accesstoken has a max. duration of 60 minutes.


$completed = $false
$sleepSeconds = 5
while (!$completed)
{
Start-Sleep -Seconds $sleepSeconds

$packageStatus = Invoke-RestMethod -Headers $authHeaders -Method Get -Uri "$automationApiUrl/companies($companyId)/configurationPackages($confPackageId)" -Verbose:$VerbosePreference

if ($packageStatus.applyStatus -eq "InProgress") {
Write-Host @newLine "."
$completed = $false
}
elseif ($packageStatus.applyStatus -eq "Completed") {
Write-Host $packageStatus.applyStatus
$completed = $true
}
elseif ($packageStatus.applyStatus -eq "Error") {
Write-Host $packageStatus.applyStatus
throw $packageStatus.applyError
}
}
}
}
catch [System.Net.WebException] {
Write-Host "ERROR $($_.Exception.Message)"
throw (GetExtendedErrorMessage $_)
}
}
catch {
TrackException -telemetryScope $telemetryScope -errorRecord $_
throw
}
finally {
TrackTrace -telemetryScope $telemetryScope
}
}
Export-ModuleMember -Function Import-BcConfigurationPackage