SOAP против REST для выполнения задач в средах VMware

Опубликовано: 17 Апреля, 2023
SOAP против REST для выполнения задач в средах VMware

В предыдущей статье мы узнали от Люка Декенса о REST API в средах VMware. Люк является vExpert и MVP и интересуется автоматизацией всех вещей, в частности, с помощью PowerShell и PowerCLI. Он является соавтором справочника по PowerCLI и регулярно выступает на конференциях. Обязательно загляните в блог Люка и на его страницу в Твиттере. В этой статье Люк опирается на предыдущую, сравнивая, как SOAP и REST работают при выполнении задачи в среде VMware.

SOAP против REST API

Теперь у нас есть общее представление о REST API в средах VMware и о том, как использовать их из PowerShell, но что это на самом деле означает на практике? Почему мы должны перейти от вызова SOAP к вызову REST? В качестве примера я собираюсь показать, как выполнить одно и то же действие дважды, один раз через SOAP API и один раз через REST API. Различия между этими двумя должны прояснить, где находится ваша выгода, как потребителя/кодировщика.

Задание

В среде VMware vSphere при добавлении жесткого диска к виртуальной машине с помощью PowerCLI система решает, какой номер устройства получит жесткий диск. Вы можете выбрать контроллер SCSI, но не номер устройства. Для некоторых приложений или даже просто в качестве требования для управления ВМ может потребоваться возможность выбора предопределенного номера устройства. Но с нашим текущим инструментом автоматизации, VMware PowerCLI, командлет New-HardDisk не позволяет этого.

МЫЛО

В эпоху до REST нам приходилось возвращаться к вызову vSphere API на основе SOAP из скрипта PowerCLI. При использовании vSphere API Справочник по vSphere API обязателен. Недостаток — этот документ может быть пугающим, когда вам нужно использовать его первые пару раз.

Помимо всех вопросов доступности, мы ищем метод ReconfigVM. С помощью конструкции вложенных объектов мы можем указать серверу vSphere, что именно мы хотим сделать:

$vmName = 'ВМ1'
$hdSizeGB = 1
$unitNumber = 6
$номер_автобуса = 0

$vm = Get-VM -имя $vmName

# Найдите ключ контроллера SCSI с шиной 0

$ctrl = $vm.ExtensionData.Config.Hardware.Device |
где {$_ — это [VMware.Vim.VirtualLsiLogicSASController] — и
$_.BusNumber -eq $busNumber} |
Выберите -ExpandProperty Key

# Построить спецификацию для добавления жесткого диска

$spec = новый объект VMware.Vim.VirtualMachineConfigSpec
$dev = новый объект VMware.Vim.VirtualDeviceConfigSpec
$disk = новый объект VMware.Vim.VirtualDisk
$back = новый объект VMware.Vim.VirtualDiskFlatVer2BackingInfo

$назад.ИмяФайла = ''
$back.ThinProvisioned = $true
$back.DiskMode = [VMware.Vim.VirtualDiskMode]::independent_persistent

$диск.Ключ = -100
$disk.ControllerKey = $ctrl
$disk.CapacityInKB = $hdSizeGB*1GB/1KB
$disk.UnitNumber = $unitNumber # <== определить номер устройства
$disk.Backing = $назад

$dev.Operation = [VMware.Vim.VirtualDeviceConfigSpecOperation]::добавить
$dev.FileOperation = [VMware.Vim.VirtualDeviceConfigSpecFileOperation]::create
$dev.Device = $диск

$spec.DeviceChange += $dev

# Добавляем жесткий диск

$vm.ExtensionData.ReconfigVM($spec)

# Проверка

Get-VM -Name $vmName | Получить-жесткий диск |
выберите Имя,ИмяФайла,@{N='Unit';E={$_.ExtensionData.UnitNumber}}

Как видно из кода, мы можем явно указать, какой номер устройства ($disk.UnitNumber) будет у нового жесткого диска.

ОТДЫХАТЬ

Когда мы делаем то же самое с REST API, код может выглядеть так:

$vmName = 'ВМ1'
$hdSizeGB = 1
$unitNumber = 6
$номер_автобуса = 0

$vCenterName = 'vcsa.local.lab'
$ авторизация = @ {
'vmware-api-session-id' = '8dd2aa8f186187949ceb7ce4318a9472'
}

# Найдите виртуальную машину

$uriFind = "https://$($vCenterName)/rest/vcenter/vm?filter.names=$($vmName)"
$vm = Invoke-RestMethod -Uri $uriFind -Headers $auth

# Создаем новый HD

$uriHD = «https://$($vCenterName)/rest/vcenter/vm/$($vm.value[0].vm)/оборудование/диск»

$sRest = @{
Ури = $uriHD
Метод = "Опубликовать"
Заголовки = $ авторизация
ContentType = 'приложение/json'
Тело = @{
спец = @{
new_vmdk = @{
емкость = $hdSizeGB * 1 ГБ
}
scsi = @{
автобус = $номер_автобуса
единица = $unitNumber
}
тип = 'SCSI'
}
} | ConvertTo-Json
}

$hd = Invoke-RestMethod @sRest

# Проверка

Get-VM -Name $vmName | Получить-жесткий диск |
выберите Имя,ИмяФайла,@{N='Unit';E={$_.ExtensionData.UnitNumber}}

Большая разница здесь, по крайней мере для меня, заключается в том, как мы сообщаем системе, что делать. Второй Invoke-RestMethod, который создает новый жесткий диск, сообщает, что мы хотим сделать, посредством комбинации URI (на какую виртуальную машину мы ориентируемся) и структуры Body, простой хэш-таблицы, которую мы конвертируем в JSON.

Мой вывод

Работа с REST API определенно упрощает структуру/объекты, которые нам нужно настроить для вызова среды vSphere. Все определяется в «текстовом формате», URI и возможные параметры, которые мы передаем через текст JSON. В моей книге это на один шаг ближе к SDDC, программно-определяемому центру обработки данных.

Означает ли это, что мы можем отказаться от наших скриптов, основанных на SOAP, в пользу REST API? Нет, не совсем. По крайней мере, пока!
Помните, что работа над vSphere REST API еще не завершена на 100 процентов. Чтобы продемонстрировать это, обратите внимание, как сценарий SOAP запросил жесткий диск Thin Provision, и, насколько мне известно, эта функция еще не доступна в REST API в том виде, в каком они существуют сегодня. Так что, пока у нас не будет 100-процентно функционально совместимой реализации REST API, пока не выбрасывайте свой код SOAP.

Модуль rCisTag

Когда у вас есть новый набор API, который предлагает функции, которые раньше были доступны только для одного инструмента, который я использую, тогда было очевидно, что я хотел изучить возможности. Функция Tag в vSphere обладает большим потенциалом, но ей не хватает гибкости. В PowerCLI действительно есть командлеты для работы с тегами, категориями тегов и назначениями тегов, но при определенных условиях они работают относительно медленно. А REST API предлагал обширный набор функций для работы с тегами.

Как насчет Connect-CisServer и Get-CisService? Один из первых вопросов, который я получил в ответ на мой модуль rCisTag: «Почему вы не использовали командлеты Connect-CisServer и Get-CisService, доступные в PowerCLI?» Что ж, есть ряд причин, по которым я выбрал чистый REST.

  • Избегайте сокрытия REST: в настоящее время все больше и больше продуктов предлагают REST API. Основная концепция вызова REST API и обработки возвращаемых данных является универсальной и может использоваться всеми интерфейсами REST API. Служба Cis, доступная в PowerCLI, в большей степени скрывает базовый интерфейс REST API, что может быть приемлемо для пользователей, которые не хотят слишком углубляться в REST API, но вы не сможете использовать свой более общий REST. Код API.
  • Избегайте зависимости от PowerCLI: поскольку REST API использует http(s), эти API можно вызывать с платформ, где нет PowerCLI. Устраняя эту зависимость, код становится более переносимым. И нет, я не говорю, что вы можете запускать PowerShell с любой платформы, но это позволяет вам создавать прототипы вашего кода в PowerShell, устраняя зависимость от PowerCLI.
  • Скорость. Командлеты, связанные с тегами, при определенных обстоятельствах работали несколько медленнее. Модуль rCisTag был частично написан, потому что ранние испытания показали, что доступ к функциям тегов, как правило, быстрее с REST API.
  • Почему люди лезут в горы? Потому что горы есть, и люди могут.

Но будьте уверены, у меня нет проблем с Cis Services, реализованными в PowerCLI. Это простой и быстрый способ поэкспериментировать с REST API.

CRUD-функции

Когда я пишу модуль, предназначенный для работы с определенными объектами или в определенной среде, я всегда стараюсь предоставить все функции CRUD. CRUD, что означает Create-Read-Update-Delete, — это просто красивое слово, указывающее на то, что что-то имеет все функции для управления полным жизненным циклом целей. В этом случае у нас есть три вида целевых объектов: теги, категории тегов и назначения тегов. Быстрая проверка в API Explorer показала, что все эти функции доступны через REST API, кроме обновления назначений тегов. Но опять же, само по себе это действие не имеет особого смысла.

Как написать модуль

Когда вы начинаете писать модуль с нуля, всегда желательно иметь боевой план. В этом случае вызов REST API и получение результатов, конечно, является центральным элементом. Для этого я попытался создать функцию, которая могла бы обрабатывать все возможные вызовы REST API. Таким образом, я мог бы содержать все фактические вызовы REST API в одной функции. Когда вы посмотрите на типичный вызов REST API, вы сразу заметите, что на самом деле он состоит из трех отличительных частей:

  • URI, а точнее часть запроса URI.
  • Метод.
  • Тело (в некоторых случаях).

Когда я пишу функции, я обычно начинаю с самого минимума и добавляю приятные функции, когда основные функции работают. Моя первоначальная вызывающая функция REST API выглядела так:

функция Invoke-vCisRest{
параметр (
[Строка]$Метод,
[Строка]$Запрос,
[PSObject]$тело
)

Процесс
{
$sRest = @{
Uri = "https:/",$Script:CisServer.Server,'rest',$Request -join '/'
Метод = $Метод
Тело = &{if($Body){$Body | ConvertTo-Json - Глубина 32}}
ContentType = 'приложение/json'
Заголовки = @{
'vmware-api-session-id' = "$($vmware_api_session_id')"
}
}
Invoke-RestMethod @sRest
}
}

Как видите, ничего особенного, только основы. Идентификатор сеанса сохранялся в переменной при подключении. Обратите внимание, что, поскольку мы используем объект PowerShell для определения содержимого Body и поскольку мы определяем Content s JSON, мы должны преобразовать объект в JSON. Ничего сложного со встроенным командлетом ConvertTo-Json. Просто помните, что глубины командлета по умолчанию может быть недостаточно для обработки сложных объектов, поэтому был добавлен параметр -Depth 32. Как только эта функция заработала, как задумано, я мог приступить к разработке реальных функций CRUD.

Получение тега

Когда вы разрабатываете функции, важно думать о параметрах, которые вы принимаете. В случае с функцией Get-rCisTag я хотел разрешить получение тега по его имени, а также через его внутренний идентификатор. В PowerShell для этого есть наборы параметров, поэтому используйте их.

Еще одна отличная функция PowerShell — конвейер. Поэтому, когда это возможно, попробуйте встроить это в свои функции. В этой функции я обеспечил конвейерную поддержку параметра Category. Это позволило мне иметь такую строку:

В итоге функция выглядела примерно так:

функция Get-rCisTag{`
[CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Низкий',
DefaultParameterSetName='Имя')]
параметр (
[Параметр (Позиция = 1, ParameterSetName = 'Имя')]
[Строка[]]$Имя,
[Параметр (Позиция = 2, ParameterSetName = 'Имя', ValueFromPipeline = $true)]
[PSObject[]]$Категория,
[Параметр (обязательный = $ True, Position = 1, ParameterSetName = 'Id')]
[Строка[]]$Идентификатор
)

Процесс
{
if($PSCmdlet.ParameterSetName -eq 'Имя'){
если ($ Категория) {
$tagIds = $Категория | %{
$categoryIds = &{if($_ -is [строка]){
(Get-rCisTagCategory -Name $_).Id
}
еще{
$_.Ид
}}
$categoryIds | %{
# Получить все теги в категориях
$sRest = @{
Метод = "Опубликовать"
Запрос = «com/vmware/cis/tagged/tag/» +
«id:$([uri]::EscapeDataString($_))» +
«?~action=список-тегов-для-категории»
}
(Invoke-vCisRest @sRest).значение
}
}
}
еще{
$sRest = @{
Метод = "Получить"
Запрос = 'com/vmware/cis/tagged/tag'
}
$tagIds = (Invoke-vCisRest @sRest).значение
}
}
еще{
$tagIds = $Ид
}

# Получить информацию о категории
$выход = @()
$теги | где {($PSCmdlet.ParameterSetName -eq 'Id' -и $Id -содержит $_) -или
$PSCmdlet.ParameterSetName -eq 'Имя'} | %{
$sRest = @{
Метод = "Получить"
Запрос = «com/vmware/cis/tagged/tag/id:$([uri]::EscapeDataString($_))»
}
$result = Invoke-vCisRest @sRest

if($PSCmdlet.ParameterSetName -eq 'Id' -or ($PSCmdlet.ParameterSetName -eq 'Имя' -and
($Name -eq $null -или $Name -contains $result.value.name))){
$out += New-Object PSObject -Property @{
Описание = $result.value.description
Идентификатор = $result.value.id
Имя = $результат.значение.имя
Категория = (Get-rCisTagCategory -Id $result.value.category_id).Name
Uid = "$($global:defaultviserver.Id)Tag=$($result.value.id)/"
Клиент = $global:defaultviserver.Client
}
}
}
$из | Select-Object Category,Description,Id,Name,Uid,Client
}
}

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

К счастью, PowerShell дает вам доступ ко всем функциям.Net, поэтому я мог использовать метод EscapeDataString для преобразования такого идентификатора во что-то вроде этого:

Что не создает проблем в URI.

Результат

Я приглашаю вас взглянуть на полученный код в модуле rCisTag, который я сделал доступным в репозитории сообщества VMware PowerCLI.

PS C:> Get-Command -Module rCisTag

Обратите внимание, что модуль в настоящее время все еще находится в своем первом общедоступном черновике, и любые отзывы более чем приветствуются.

Наслаждаться!