Создание и обновление именованных кэшей в управляемом кэше Azure с помощью Management API

Я пытаюсь создать управляемый кэш Azure с помощью PowerShell и службы управления Azure. API, этот двухсторонний подход необходим, поскольку официальные командлеты Azure PowerShell имеют очень ограниченную поддержку Создание и обновление управляемого кэша Azure. Однако существует ссылка установленный шаблон для вызова API управления Azure из PowerShell.

Моим попыткам найти правильный API для вызова несколько помешал ограниченная документация по API управляемого кэша Azure. Однако, проработав командлеты с использованием как исходного кода, так и параметра -Debug в PowerShell, я смог найти то, что кажется правильными конечными точками API, поэтому я разработал некоторый код для доступа к этим конечным точкам.

Однако я застрял после того, как запрос PUT был принят в API Azure, поскольку последующие вызовы к конечной точке API/операций управления показывают, что результатом этой операции был Internal Server Error.

Я использовал Joseph Alabarhari LinqPad для изучения API, поскольку он позволяет мне быстро перебирать решение, используя минимум возможный код, поэтому для выполнения следующих фрагментов кода вам потребуются как LinqPad, так и следующее расширение в скрипте "Мои расширения" :

public static X509Certificate2 GetCertificate(this StoreLocation storeLocation, string thumbprint) {
    var certificateStore = new X509Store(StoreName.My, storeLocation);
    certificateStore.Open(OpenFlags.ReadOnly);
    var certificates = certificateStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
    return certificates[0];
}

Полный исходный код, включая включения, доступен ниже:

  • Мои расширения — вы можете заменить "Мои расширения" щелкнув правой кнопкой мыши «Мои расширения» в нижней левой панели и выбрав «Открыть расположение сценария в проводнике Windows», а затем заменив выделенный файл этим. В качестве альтернативы вы можете объединить мои расширения со своими.
  • Сценарий управляемого кэша Azure — вы должны просто иметь возможность загрузите и дважды щелкните по нему, после открытия и установки вышеуказанных расширений и сертификатов вы сможете выполнить скрипт.

В сценарии используются следующие параметры. Следующие переменные потребуются всем, кто использует собственный идентификатор подписки Azure и сертификат управления:

var cacheName = "amc551aee";
var subscriptionId = "{{YOUR_SUBSCRIPTION_ID}}";
var certThumbprint = "{{YOUR_MANAGEMENT_CERTIFICATE_THUMBPRINT}}";
var endpoint = "management.core.windows.net";
var putPayloadXml = @"{{PATH_TO_PUT_PAYLOAD}}\cloudService.xml"

Сначала я выполнил некоторые настройки на HttpClient:

var handler = new WebRequestHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ClientCertificates.Add(StoreLocation.CurrentUser.GetCertificate(certThumbprint));
var client = new HttpClient(handler);
client.DefaultRequestHeaders.Add("x-ms-version", "2012-08-01");

Это настраивает HttpClient для использования как сертификата клиента, так и заголовка x-ms-version, первый вызов API извлекает существующую службу CloudService, содержащую управляемый кэш Azure. Обратите внимание, что в противном случае используется пустая подписка Azure.

var getResult = client.GetAsync("https://" + endpoint + "/" + subscriptionId + "/CloudServices");
getResult.Result.Dump("GET " + getResult.Result.RequestMessage.RequestUri);

Этот запрос выполнен успешно, поскольку он возвращает StatusCode: 200, ReasonPhrase: 'OK', затем я анализирую некоторую ключевую информацию из запроса: имя CloudService, имя кеша и ETag кеша:

var cacheDataReader = new XmlTextReader(getResult.Result.Content.ReadAsStreamAsync().Result);
var cacheData = XDocument.Load(cacheDataReader);
var ns = cacheData.Root.GetDefaultNamespace();
var nsManager = new XmlNamespaceManager(cacheDataReader.NameTable);
nsManager.AddNamespace("wa", "http://schemas.microsoft.com/windowsazure");

var cloudServices = cacheData.Root.Elements(ns + "CloudService");
var serviceName = String.Empty;
var ETag = String.Empty;
foreach (var cloudService in cloudServices) {
    if (cloudService.XPathSelectElements("//wa:CloudService/wa:Resources/wa:Resource/wa:Name", nsManager).Select(x => x.Value).Contains(cacheName)) {
        serviceName = cloudService.XPathSelectElement("//wa:CloudService/wa:Name", nsManager).Value;
        ETag = cloudService.XPathSelectElement("//wa:CloudService/wa:Resources/wa:Resource/wa:ETag", nsManager).Value;
    }
} 

Я предварительно создал файл XML, содержащий полезную нагрузку следующего запроса PUT:

<Resource xmlns="http://schemas.microsoft.com/windowsazure">
  <IntrinsicSettings>
    <CacheServiceInput xmlns="">
      <SkuType>Standard</SkuType>
      <Location>North Europe</Location>
      <SkuCount>1</SkuCount>
      <ServiceVersion>1.3.0</ServiceVersion>
      <ObjectSizeInBytes>1024</ObjectSizeInBytes>
      <NamedCaches>
        <NamedCache>
          <CacheName>default</CacheName>
          <NotificationsEnabled>false</NotificationsEnabled>
          <HighAvailabilityEnabled>false</HighAvailabilityEnabled>
          <EvictionPolicy>LeastRecentlyUsed</EvictionPolicy>
        </NamedCache>
        <NamedCache>
          <CacheName>richard</CacheName>
          <NotificationsEnabled>true</NotificationsEnabled>
          <HighAvailabilityEnabled>true</HighAvailabilityEnabled>
          <EvictionPolicy>LeastRecentlyUsed</EvictionPolicy>
        </NamedCache>
      </NamedCaches>
    </CacheServiceInput>
  </IntrinsicSettings>
</Resource>

Я создаю HttpRequestMessage с указанной выше полезной нагрузкой и URL-адресом, состоящим из имен CloudService и Cache:

var resourceUrl = "https://" + endpoint + "/" + subscriptionId + "/cloudservices/" + serviceName + "/resources/cacheservice/Caching/" + cacheName;
var data = File.ReadAllText(putPayloadXml);
XDocument.Parse(data).Dump("Payload");
var message = new HttpRequestMessage(HttpMethod.Put, resourceUrl);
message.Headers.TryAddWithoutValidation("If-Match", ETag);
message.Content = new StringContent(data, Encoding.UTF8, "application/xml");
var putResult = client.SendAsync(message);
putResult.Result.Dump("PUT " + putResult.Result.RequestMessage.RequestUri);
putResult.Result.Content.ReadAsStringAsync().Result.Dump("Content " + putResult.Result.RequestMessage.RequestUri);

Этот запрос номинально принимается API управления службами Azure, поскольку он возвращает ответ StatusCode: 202, ReasonPhrase: 'Accepted'; по сути это означает, что полезная нагрузка была принята и будет обработана в автономном режиме, идентификатор операции может быть проанализирован из заголовка HTTP для получения дополнительной информации:

var requestId = putResult.Result.Headers.GetValues("x-ms-request-id").FirstOrDefault();

Этот requestId можно использовать для запроса обновления статуса операции:

var operation = client.GetAsync("https://" + endpoint + "/" + subscriptionId + "/operations/" + requestId);
operation.Result.Dump(requestId);
XDocument.Load(operation.Result.Content.ReadAsStreamAsync().Result).Dump("Operation " + requestId);

Запрос к конечной точке /operations приводит к следующей полезной нагрузке:

<Operation xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <ID>5364614d-4d82-0f14-be41-175b3b85b480</ID>
  <Status>Failed</Status>
  <HttpStatusCode>500</HttpStatusCode>
  <Error>
    <Code>InternalError</Code>
    <Message>The server encountered an internal error. Please retry the request.</Message>
  </Error>
</Operation>

И здесь я застрял, скорее всего, я слегка искажаю запрос таким образом, что базовый запрос выдает 500 Internal Server Error, однако без более подробного сообщения об ошибке или документации API я не думаю, что есть везде я могу пойти с этим.


person Richard Slater    schedule 28.08.2014    source источник


Ответы (1)


Мы работали с Ричардом в автономном режиме, и следующая полезная нагрузка XML помогла ему разблокироваться. Примечание. При добавлении/удалении именованного кэша в существующий кэш размер объекта фиксируется.

Примечание 2. API управляемого кэша Azure чувствителен к пробелам между элементом и элементом.

Также обратите внимание, что мы работаем над добавлением возможности именованного кэша в сам PowerShell, чтобы людям не приходилось использовать для этого API.

<Resource xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <IntrinsicSettings><CacheServiceInput xmlns="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <SkuType>Standard</SkuType>
      <Location>North Europe</Location>
      <SkuCount>1</SkuCount>
      <ServiceVersion>1.3.0</ServiceVersion>
      <ObjectSizeInBytes>1024</ObjectSizeInBytes>
    <NamedCaches>
      <NamedCache>
        <CacheName>default</CacheName>
        <NotificationsEnabled>false</NotificationsEnabled>
        <HighAvailabilityEnabled>false</HighAvailabilityEnabled>
        <EvictionPolicy>LeastRecentlyUsed</EvictionPolicy>
        <ExpirationSettings>
          <TimeToLiveInMinutes>10</TimeToLiveInMinutes>
          <Type>Absolute</Type>
        </ExpirationSettings>
      </NamedCache>
      <NamedCache>
        <CacheName>richard</CacheName>
        <NotificationsEnabled>false</NotificationsEnabled>
        <HighAvailabilityEnabled>false</HighAvailabilityEnabled>
        <EvictionPolicy>LeastRecentlyUsed</EvictionPolicy>
        <ExpirationSettings>
          <TimeToLiveInMinutes>10</TimeToLiveInMinutes>
          <Type>Absolute</Type>
        </ExpirationSettings>
      </NamedCache>
    </NamedCaches>    
  </CacheServiceInput>
  </IntrinsicSettings>
</Resource>
person Saurabh    schedule 02.09.2014
comment
Хороший вопрос! Я задокументировал требования, как я их вижу, в следующем выпуске на странице azure-sdk-tools GitHub: github.com/Azure/azure-sdk-tools/issues/2876 - person Richard Slater; 02.09.2014
comment
Ричард, создание кеша через Powershell и добавление именованных кешей через портал неприемлемо в вашем сценарии? - person Saurabh; 03.09.2014
comment
да — из-за сложности клиентских систем у них есть потребность в полной автоматизации, это преимущественно для удовлетворения требований других команд, которым потребуется развернуть решение во многих средах после того, как оно будет запущено. - person Richard Slater; 03.09.2014
comment
Спасибо, Ричард, имеет смысл. Я буду работать с вами в автономном режиме и отвечу в этой теме, когда мы закроем цикл. - person Saurabh; 03.09.2014
comment
Еще раз спасибо, Саураб, могу я попросить вас обновить ваш ответ, включив в него комментарии, которые я отправил вам по электронной почте, а именно, что API управляемого кэша чувствителен к пробелам между элементами «IntrinsicSettings» и «CacheServiceInput». - person Richard Slater; 05.09.2014