PlagueHO / CosmosDB

PowerShell Module for working with Azure Cosmos DB databases, collections, documents, attachments, offers, users, permissions, triggers, stored procedures and user defined functions.
http://dscottraynsford.com
MIT License
156 stars 46 forks source link

Error when creating Collection in Emulator #206

Closed redoz closed 6 years ago

redoz commented 6 years ago

I'm trying to script the creation of a collection in the emulator like so:

param(
    [Switch]$Emulator,
    [string]$Database = 'DevDb',
    [string]$Collection = 'DevCollection'
)

Set-StrictMode -Version Latest

Import-Module -Name CosmosDB

if ($Emulator.IsPresent) {
    $context = New-CosmosDbContext -Emulator -Database $Database
} else {
    throw "not supported yet"
}

try {
    $db = Get-CosmosDbDatabase -Context $context -Id $Database
} catch {
    $db = $null
}

if ($null -eq $db) {
    $db = New-CosmosDbDatabase -Context $context -Id $Database
}

$indexingPolicy = New-CosmosDbCollectionIndexingPolicy -Automatic $true -IndexingMode Consistent

$col = New-CosmosDbCollection -Context $context -Database $db -Id $Collection -IndexingPolicy $indexingPolicy -OfferThroughput 1000 

But I get an error on the creation of the collection: 400 Bad Request, am I missing some required parameter here, or am I using the API wrong?

For what it's worth I'm trying to create a Graph/Gremlin based database, but I also haven't seen any parameter for that?

PlagueHO commented 6 years ago

Hi @redoz - if you add the -Verbose parameter to the New-CosmosDbCollection do you get more detail in the error message?

I suspect though the problem might be with the Indexing Policy - so I'm just creating some new tests to validate that type of index works.

PlagueHO commented 6 years ago

I've tested the Indexing Policy and added some new integration tests to make sure it does work. However, I haven't yet tested this against the emulator. So I'll get that done tonight.

redoz commented 6 years ago

This is the output from New-CosmosDbCollection using -Verbose:

VERBOSE: Creating authorization token: Method = 'Post', ResourceType = 'colls', ResourceId = 'dbs/@{id=DevDb; _rid=HoFNAA==; _self=dbs/HoFNAA==/; _etag="00000000-0000-0000-7105-45a6f64f01d4"; _colls=colls/; _users=users/; _ts=1540982055; Etag=System.Management.Automation.PSScriptProperty; ResourceId=HoFNAA==; Timestamp=System.Management.Automation.PSScriptProperty; Uri=dbs/HoFNAA==/; Collections=colls/; Users=users/}', Date = '31/10/2018 11:51:00'.
VERBOSE: POST https://localhost:8081/dbs/@{id=DevDb; _rid=HoFNAA==; _self=dbs/HoFNAA==/; _etag="00000000-0000-0000-7105-45a6f64f01d4"; _colls=colls/; _users=users/; _ts=1540982055; Etag=System.Management.Automation.PSScriptProperty; ResourceId=HoFNAA==; Timestamp=System.Management.Automation.PSScriptProperty; Uri=dbs/HoFNAA==/; Collections=colls/; Users=users/}/colls with 168-byte payload
VERBOSE: received -byte response of content type application/json
VERBOSE: {"code":"BadRequest","message":"Request url is invalid.\r\nActivityId: a19cd87e-bb80-4a7b-bed4-b61b8d8fea9d, Microsoft.Azure.Documents.Common/2.1.0.0"}
Invoke-WebRequest : {"code":"BadRequest","message":"Request url is invalid.\r\nActivityId: a19cd87e-bb80-4a7b-bed4-b61b8d8fea9d, Microsoft.Azure.Documents.Common/2.1.0.0"}
At C:\Users\patrik.husfloen\Documents\PowerShell\Modules\CosmosDB\2.1.12.137\lib\utils.ps1:565 char:30
+ ...        $requestResult = Invoke-WebRequest @invokeWebRequestParameters
+                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (Method: POST, R...ication/json
}:HttpRequestMessage) [Invoke-WebRequest], HttpResponseException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

And if I inspect the exception using $Error[0].Exception.RequestMessage | fc -depth 3 I get this:


class HttpRequestMessage
{
  Version = 
    class Version
    {
      Major = 2
      Minor = 0
      Build = -1
      Revision = -1
      MajorRevision = -1
      MinorRevision = -1
    }
  Content = 
    class ByteArrayContent
    {
      Headers = 
        [
          class 0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
          {
            Key = Content-Length
            Value = 
              [
                168
              ]

          }
          class 0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
          {
            Key = Content-Type
            Value = 
              [
                application/json
              ]

          }
        ]

    }
  Method = 
    class HttpMethod
    {
      Method = POST
    }
  RequestUri = 
    class Uri
    {
      AbsolutePath = /dbs/@%7Bid=DevDb;%20_rid=HoFNAA==;%20_self=dbs/HoFNAA==/;%20_etag=%2200000000-0000-0000-7105-45a6f64f01d4%22;%20_colls=colls/;%20_users=users/;%20_ts=1540982055;%20Etag=System.Management.Automation.PSScriptProperty;%20ResourceId=HoFNAA==;%20Timestamp=System.Management.Automation.PSScriptProperty;%20Uri=dbs/HoFNAA==/;%20Collections=colls/;%20Users=users/%7D/colls
      AbsoluteUri = https://localhost:8081/dbs/@%7Bid=DevDb;%20_rid=HoFNAA==;%20_self=dbs/HoFNAA==/;%20_etag=%2200000000-0000-0000-7105-45a6f64f01d4%22;%20_colls=colls/;%20_users=users/;%20_ts=1540982055;%20Etag=System.Management.Automation.PSScriptProperty;%20ResourceId=HoFNAA==;%20Timestamp=System.Management.Automation.PSScriptProperty;%20Uri=dbs/HoFNAA==/;%20Collections=colls/;%20Users=users/%7D/colls
      LocalPath = /dbs/@{id=DevDb; _rid=HoFNAA==; _self=dbs/HoFNAA==/; _etag="00000000-0000-0000-7105-45a6f64f01d4"; _colls=colls/; _users=users/; _ts=1540982055; Etag=System.Management.Automation.PSScriptProperty; ResourceId=HoFNAA==; Timestamp=System.Management.Automation.PSScriptProperty; Uri=dbs/HoFNAA==/; Collections=colls/; Users=users/}/colls
      Authority = localhost:8081
      HostNameType = Dns
      IsDefaultPort = False
      IsFile = False
      IsLoopback = True
      PathAndQuery = /dbs/@%7Bid=DevDb;%20_rid=HoFNAA==;%20_self=dbs/HoFNAA==/;%20_etag=%2200000000-0000-0000-7105-45a6f64f01d4%22;%20_colls=colls/;%20_users=users/;%20_ts=1540982055;%20Etag=System.Management.Automation.PSScriptProperty;%20ResourceId=HoFNAA==;%20Timestamp=System.Management.Automation.PSScriptProperty;%20Uri=dbs/HoFNAA==/;%20Collections=colls/;%20Users=users/%7D/colls
      Segments = 
        [
          /
          dbs/
          @%7Bid=DevDb;%20_rid=HoFNAA==;%20_self=dbs/
          HoFNAA==/
          ...
        ]

      IsUnc = False
      Host = localhost
      Port = 8081
      Query = 
      Fragment = 
      Scheme = https
      OriginalString = https://localhost:8081/dbs/@{id=DevDb; _rid=HoFNAA==; _self=dbs/HoFNAA==/; _etag="00000000-0000-0000-7105-45a6f64f01d4"; _colls=colls/; _users=users/; _ts=1540982055; Etag=System.Management.Automation.PSScriptProperty; ResourceId=HoFNAA==; Timestamp=System.Management.Automation.PSScriptProperty; Uri=dbs/HoFNAA==/; Collections=colls/; Users=users/}/colls
      DnsSafeHost = localhost
      IdnHost = localhost
      IsAbsoluteUri = True
      UserEscaped = False
      UserInfo = 
    }
  Headers = 
    [
      class 0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
      {
        Key = Authorization
        Value = 
          [
            type%3dmaster%26ver%3d1.0%26sig%3duGRQfbEAd%2btc1Rjs0nhMdRTsihXI%2fI9utrlxk2ApKnU%3d
          ]

      }
      class 0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
      {
        Key = x-ms-date
        Value = 
          [
            Wed, 31 Oct 2018 10:51:00 GMT
          ]

      }
      class 0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
      {
        Key = x-ms-offer-throughput
        Value = 
          [
            1000
          ]

      }
      class 0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
      {
        Key = x-ms-version
        Value = 
          [
            2017-02-22
          ]

      }
      ...
    ]

  Properties = 
    [
    ]

}

And it seems like the URL it ends up posting it to is https://localhost:8081/dbs/@{id=DevDb; _rid=HoFNAA==; _self=dbs/HoFNAA==/; _etag="00000000-0000-0000-7105-45a6f64f01d4"; _colls=colls/; _users=users/; _ts=1540982055; Etag=System.Management.Automation.PSScriptProperty; ResourceId=HoFNAA==; Timestamp=System.Management.Automation.PSScriptProperty; Uri=dbs/HoFNAA==/; Collections=colls/; Users=users/}/colls and that doesn't look right to me.

Edit: This was the output from PSCore 6.1:

Name                           Value
----                           -----
PSVersion                      6.1.0
PSEdition                      Core
GitCommitId                    6.1.0
OS                             Microsoft Windows 10.0.17763
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
redoz commented 6 years ago

I figured it out, I was passing the database object to the -Database parameter but I should've just provided the name.

Apologies for the noise.

PlagueHO commented 6 years ago

Ah!!! Looking at the URI in the request, that definitely makes sense with how you were using it. That said, my plan is to actually enable this type of use as it really isn't that difficult to do.

E.g. This is what I'd like to enable in future (paraphrasing here):

$database = New-CosmosDbDatabase -Id 'mydata'
$collection = New-CosmosDbCollection -Database $database -Id 'mycollection'
New-CosmosDbDocument -Collection $collection -Id 'mydocument' -Body @{ Whatever = 'Something' }

And eventually:

New-CosmosDbDatabase -Id 'abcd' | New-CosmosDbCollection -Id 'mycollection' | New-CosmosDbDocument -Id 'mydocument' -Body @{ Whatever = 'Something' }
redoz commented 6 years ago

@PlagueHO Maybe it could be an option to apply a regex validation on the string parameter to ensure it adheres to the naming restrictions for databases and collections in Azure? That would've caught this implicit "convert object to string" behavior.

PlagueHO commented 6 years ago

Thanks @redoz - that is a really great idea! I'll implement this!

PlagueHO commented 6 years ago

Reopening to remind me to create a new issue to add this.

PlagueHO commented 6 years ago

Closing now because I've created issues to add better parameter validation.