首页 > 解决方案 > 在 AzureDevOpps (VSTS) 内的 Cosmos Db (SQL API) 上创建数据库和集合

问题描述

我们有一个业务需求,我们必须在 AzureDevOps 中创建数据库和集合作为 CD 步骤的一部分。据我的研究表明,这是不可能通过 ARM 实现的。

MS 的支持票确认这在 ARM 中是不可能的,必须在您的应用程序中完成。如前所述,业务需求阻止我们这样做。

基本选项是编程方式或 Cosmos Db 的 REST API。

标签: azure-devopsazure-cosmosdbazure-pipelines

解决方案


我最终使用 PowerShell 脚本完成了这项工作!在这篇文章和这篇文章的帮助下,我能够开始使用 - 他们特别帮助了身份验证令牌。

然后我参考了 Cosmos Db SQL REST API 上的 MS 文档:创建数据库创建集合

这是我的 PS 脚本(发帖时在 AzureDevOps/VSTS 中工作):

param($endpoint, $masterKey, $databaseName, $collectionName, $collectionRUs)
Add-Type -AssemblyName System.Web

Add-Type -TypeDefinition @"
public enum CosmosResourceType
{
  Database,
  Collection
}
"@

Function Create-Resource
{
[CmdletBinding()]
Param
(
    [Parameter(Mandatory=$true)][String]$endPoint,
    [Parameter(Mandatory=$true)][String]$masterKey,
    [Parameter(Mandatory=$true)][String]$dataBaseName,
    [Parameter(Mandatory=$true)][String]$collectionName,
    [Parameter(Mandatory=$true)][CosmosResourceType]$cosmosResourceType
)

$verb = "POST";
$resourceType = "dbs";
$resourceLink = "dbs";
$header = "";
$idValue = "";
$contentType = "application/json";
$queryUri = "$endPoint$resourceLink"

if($cosmosResourceType -eq "Database")
{
    $header = Generate-Headers -verb $verb -resourceType $resourceType -key $masterKey
    $idValue = $dataBaseName        
}
elseif($cosmosResourceType -eq "Collection")
{
    $resourceType = "colls";
    $resourceLink = "dbs/$dataBaseName" 
    $header = Generate-Headers -verb $verb -resourceType $resourceType -resourceLink $resourceLink -key $masterKey

    # Not sure why but at this moment Cosmos Db ignores this setting
    $header | Add-Member -Name 'x-ms-offer-throughput' -Type NoteProperty -Value $collectionRUs

    $idValue = $collectionName
    $queryUri = "$endPoint$resourceLink/colls"
}
else
{
    Write-Host "Invalid Cosmos Resource Type:"$cosmosResourceType -ForeGroundColor Red 
}

$jsonDoc = [pscustomobject]@{ id = $idValue }
$jsonDoc = $jsonDoc | ConvertTo-Json

$response = InvokeRest -verb $Verb -ContentType $contentType -uri $queryUri -headers $header -body $jsonDoc

if($response.code.ToLowerInvariant() -eq "Conflict".ToLowerInvariant())
{
    Write-Host "Warning: $cosmosResourceType already existing" -ForeGroundColor Yellow  
}
elseif($response.code.ToLowerInvariant() -eq "Ok".ToLowerInvariant())
{
    Write-Host "$cosmosResourceType Created" -ForeGroundColor Green 
}
else
{
    Write-Host "response:"$response -ForeGroundColor Red 
}    
}

Function InvokeRest
{
[CmdletBinding()]
Param
(
    [Parameter(Mandatory=$true)]$verb,
    [Parameter(Mandatory=$true)]$contentType,
    [Parameter(Mandatory=$true)]$uri,    
    [Parameter(Mandatory=$true)]$headers,
    [Parameter(Mandatory=$false)]$body    
)

Try {
    $result = Invoke-RestMethod -Method $Verb -ContentType $contentType -Uri $uri -Headers $headers -Body $body
    Write-Host "InvokeRest: "$result -ForeGroundColor Green 

    $response = [pscustomobject]@{
        code = "OK"
        body = $result
    }

    return $response
}
Catch {        
    # Check if there is a response.
    if ($_.Exception.Response -eq $null) {
        $expMessage = $_.Exception.Message
        $failedItem = $_.Exception.Source
        $line = $_.InvocationInfo.ScriptLineNumber
        Write-Host "At $($line):`r`n$expMessage `r`n$failedItem" -ForeGroundColor Red   
        throw $_.Exception         
    }
    else {
        # Get the response body with more error detail.
        $respStream = $_.Exception.Response.GetResponseStream()
        $reader = New-Object System.IO.StreamReader($respStream)
        $response = $reader.ReadToEnd() | ConvertFrom-Json
        return $response
    } 
}
}

Function Generate-Headers
{
[CmdletBinding()]
Param
(
    [Parameter(Mandatory=$true)][String]$verb,
    [Parameter(Mandatory=$false)][String]$resourceLink,
    [Parameter(Mandatory=$true)][String]$resourceType,    
    [Parameter(Mandatory=$true)][String]$key    
)

$dateTime = [DateTime]::UtcNow.ToString("r")
$authHeader = Generate-MasterKeyAuthorizationSignature -verb $verb -resourceLink $resourceLink -resourceType $resourceType -key $masterKey -keyType "master" -tokenVersion "1.0" -dateTime $dateTime
Write-Host $authHeader
$header = @{authorization=$authHeader;"x-ms-version"="2017-02-22";"x-ms-date"=$dateTime}

return $header
}

Function Generate-MasterKeyAuthorizationSignature
{
[CmdletBinding()]
Param
(
    [Parameter(Mandatory=$true)][String]$verb,
    [Parameter(Mandatory=$false)][String]$resourceLink,
    [Parameter(Mandatory=$true)][String]$resourceType,    
    [Parameter(Mandatory=$true)][String]$key,
    [Parameter(Mandatory=$true)][String]$keyType,
    [Parameter(Mandatory=$true)][String]$tokenVersion,
    [Parameter(Mandatory=$true)][String]$dateTime
)

$hmacSha256 = New-Object System.Security.Cryptography.HMACSHA256
$hmacSha256.Key = [System.Convert]::FromBase64String($key)

$payLoad = Generate-Payload -verb $verb -resourceLink $resourceLink -resourceType $resourceType -dateTime $dateTime
$hashPayLoad = $hmacSha256.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($payLoad))
$signature = [System.Convert]::ToBase64String($hashPayLoad);

[System.Web.HttpUtility]::UrlEncode("type=$keyType&ver=$tokenVersion&sig=$signature")
}

Function Generate-Payload
{
[CmdletBinding()]
Param
(
    [Parameter(Mandatory=$true)][String]$verb,
    [Parameter(Mandatory=$false)][String]$resourceLink,
    [Parameter(Mandatory=$true)][String]$resourceType,
    [Parameter(Mandatory=$true)][String]$dateTime
)

$payLoad = ""

if ( [string]::IsNullOrEmpty($resourceLink) ) 
{ 
    $payLoad = "$($verb.ToLowerInvariant())`n$($resourceType.ToLowerInvariant())`n`n$($dateTime.ToLowerInvariant())`n`n"
}    
else 
{
    $payLoad = "$($verb.ToLowerInvariant())`n$($resourceType.ToLowerInvariant())`n$resourceLink`n$($dateTime.ToLowerInvariant())`n`n"
} 


return $payLoad
}

# Create Database
$cosmosResourceType =  [CosmosResourceType]::Database
Create-Resource -endPoint $endpoint -masterKey $masterKey -dataBaseName $databaseName -collectionName $collectionName -cosmosResourceType $cosmosResourceType

# Create Collection
$cosmosResourceType =  [CosmosResourceType]::Collection
Create-Resource -endPoint $endpoint -masterKey $masterKey -dataBaseName $databaseName -collectionName $collectionName -cosmosResourceType $cosmosResourceType

我希望这对其他人有帮助。


推荐阅读