在AzureDevOpps(VSTS)内的Cosmos Db(SQL API)上创建数据库和集合

时间:2018-10-09 13:33:16

标签: azure-devops azure-cosmosdb azure-pipelines

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

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

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

1 个答案:

答案 0 :(得分:1)

我最终使用PowerShell脚本完成了这项工作! 在thisthis帖子的帮助下,我得以上手-他们特别为身份验证令牌提供了帮助。

然后,我在Cosmos Db SQL REST API上引用了MS文档:Create DatabaseCreate Collection

这是我的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

希望这对其他人有帮助。