В данной статье мы рассмотрим, какие действия с Advanced Edge Gateway доступны тенанту (клиенту) и как работать с ним через API используя PowerShell. Ссылки на официальную документацию приведены в конце статьи. Но, если кратко, то через API вы можете выполнить те же самые действия, что и через веб-интерфейс управления вашим облаком.
Согласно ролевой модели доступа, клиенту доступны изменения в разделе Services > Firewall / NAT / VPN / ... Например, следующие настройки доступны только на просмотр, т.к. их изменением занимаются инженеры C4Y:
- Rate Limits
- IP Allocations
- General > Name / Edge Gateway Configuration / ...
Чтобы вам было проще разобраться с официальной документацией, мы по-этапно разберём работу через API на примере добавления DNAT правила для подключения к Windows-серверу по RDP.
0 - подготовка
Для начала, необходимо указать данные для работы - облако, тенант (вОрг), учётную запись Organization Administrator
и имя Edge, с которым будем работать.
#Requires -Version 7.2 # скрипт разрабатывался и тестировался с интерпретатором "C:\Program Files\PowerShell\7\pwsh.exe"
$Auth = @{
'cloud' = 'vcd.cloud4y.ru' # облако, с которым собираемся работать по API
'tenant' = 'demo-tenant' # имя вашей вОрг, определить можно по URL https://vcd.cloud4y.ru/tenant/demo-tenant/vdcs
'user' = 'administrator' # имя учётной записи с ролью 'Organization Administrator'
'password' = '3CQvyk3aZ0ZVCav4U' # пароль учётной записи
}
$Edge = 'demo-tenant_K41_VDC_Edge' # имя Edge, с которым вы собираетесь работать через API
$DemoAddingNatRule = $true # $true - добавить новое NAT-правило для демонстрации, $false - перечислить существующие правила
1 - открываем сессию
Общий принцип работы с облаком через API следующий:
- узнать последнюю актуальную версию API
- открыть рабочую сессию, выполнив базовую авторизацию в облаке в своём тенанте по логину и паролю
- для всех остальных запросов в качестве авторизации используется токен сессии, открытой на предыдущем шаге
$rApiVer = Invoke-WebRequest -UseBasicParsing -Method 'Get' -Headers @{"Accept"="application/*+json"} -Uri ('https://{0}/api/versions' -f $Auth['cloud'])
$rApiVerJson = [System.Text.Encoding]::UTF8.GetString($rApiVer.Content) | ConvertFrom-Json
$ApiVer = ($rApiVerJson.versionInfo | Where-Object {$_.deprecated -eq $false} | Select-Object -Last 1).version
$objCredential = '{0}@{1}:{2}' -f $Auth['user'], $Auth['tenant'], $Auth['password'] # Login@vOrg:Password
$CredentialBytes = [System.Text.Encoding]::UTF8.GetBytes($objCredential)
$CredentialBase64 = [System.Convert]::ToBase64String($CredentialBytes)
$HeadersAuthBasic = @{
'Accept' = 'application/*+json;version={0};multisite=global' -f $ApiVer
'Authorization' = 'Basic {0}' -f $CredentialBase64
}
$rAuth = Invoke-WebRequest -UseBasicParsing -Method 'Post' -Headers $HeadersAuthBasic -Uri ('https://{0}/api/sessions' -f $Auth['cloud'])
$rAuthBody = [System.Text.Encoding]::UTF8.GetString($rAuth.Content) | ConvertFrom-Json
$AuthHeaders = @{
'Accept' = 'application/*+json;version={0};multisite=global' -f $ApiVer
'Authorization' = '{0} {1}' -f ($rAuth.Headers['X-VMWARE-VCLOUD-TOKEN-TYPE'] -join ''), ($rAuth.Headers['X-VMWARE-VCLOUD-ACCESS-TOKEN'] -join '')
}
$uriNsx = $rAuthBody.link | Where-Object {$_.rel -eq 'nsx'} | Select-Object -ExpandProperty 'href'
$uriQuery = $rAuthBody.link | Where-Object {$_.href -match 'query' -and $_.type -match 'json'} | Select-Object -ExpandProperty 'href'
$uriSession = $rAuthBody.href
"`n{0}`nApiVer`t`t`t{1}`nQuery Service URL`t{2}`nNSX URL`t`t`t{3}`nHeaders`n{4}" -f 'step 1 - open session', $ApiVer, $uriQuery, $uriNsx, ($AuthHeaders | ConvertTo-Json) | Out-Default
step 1 - open session
ApiVer 35.0
Query Service URL https://vcd.cloud4y.ru/api/query
NSX URL https://vcd.cloud4y.ru/network
Headers
{
"Accept": "application/*+json;version=35.0;multisite=global",
"Authorization": "Bearer eyJhb...Zpa9FQ"
}
2 - Query Service
Query Service позволяет получить основную информацию, в т.ч. ИД объектов облака: вОрг, вДЦ, ВМ, сетям, Edge Gateway и т.д. Далее, зная ИД объекта, можно через API получить детальные свойства объекта, включая ссылки для изменения.
Посмотрим допустимые запросы и выберем относящиеся к маршрутизатору.
# посмотреть все возможные типы запросов можно так:
$rPossibleQueriesList = Invoke-WebRequest -UseBasicParsing -Method 'Get' -Headers $AuthHeaders -Uri $uriQuery
$rPossibleQueriesListBody = [System.Text.Encoding]::UTF8.GetString($rPossibleQueriesList.Content) | ConvertFrom-Json
"`n{0}" -f 'step 2 - list of queries' | Out-Default
$rPossibleQueriesListBody.link | Where-Object { $_.type -match 'json' -and $_.href -match '=records' } | Select-Object -Property 'name', 'href' | Sort-Object -Property 'name' | Out-Default
# а так мы узнаем допустимые запросы по Edge Gateway, которые вернут информацию в json-формате в records-представлении
$rPossibleQueriesListBody.link | Where-Object { $_.type -match 'json' -and $_.href -match '=records' -and $_.name -match 'gate' } | Format-List | Out-Default
step 2 - list of queries
name href
---- ----
adminApiDefinition https://vcd.cloud4y.ru/api/query?type=adminApiDefinition&format=records
adminFileDescriptor https://vcd.cloud4y.ru/api/query?type=adminFileDescriptor&format=records
adminService https://vcd.cloud4y.ru/api/query?type=adminService&format=records
apiDefinition https://vcd.cloud4y.ru/api/query?type=apiDefinition&format=records
catalog https://vcd.cloud4y.ru/api/query?type=catalog&format=records
catalogItem https://vcd.cloud4y.ru/api/query?type=catalogItem&format=records
disk https://vcd.cloud4y.ru/api/query?type=disk&format=records
edgeGateway https://vcd.cloud4y.ru/api/query?type=edgeGateway&format=records
event https://vcd.cloud4y.ru/api/query?type=event&format=records
externalLocalization https://vcd.cloud4y.ru/api/query?type=externalLocalization&format=records
fileDescriptor https://vcd.cloud4y.ru/api/query?type=fileDescriptor&format=records
fromCloudTunnel https://vcd.cloud4y.ru/api/query?type=fromCloudTunnel&format=records
gatewayUplinks https://vcd.cloud4y.ru/api/query?type=gatewayUplinks&format=records
group https://vcd.cloud4y.ru/api/query?type=group&format=records
media https://vcd.cloud4y.ru/api/query?type=media&format=records
organization https://vcd.cloud4y.ru/api/query?type=organization&format=records
orgNetwork https://vcd.cloud4y.ru/api/query?type=orgNetwork&format=records
orgVdc https://vcd.cloud4y.ru/api/query?type=orgVdc&format=records
orgVdcNetwork https://vcd.cloud4y.ru/api/query?type=orgVdcNetwork&format=records
orgVdcStorageProfile https://vcd.cloud4y.ru/api/query?type=orgVdcStorageProfile&format=records
orgVdcTemplate https://vcd.cloud4y.ru/api/query?type=orgVdcTemplate&format=records
right https://vcd.cloud4y.ru/api/query?type=right&format=records
role https://vcd.cloud4y.ru/api/query?type=role&format=records
service https://vcd.cloud4y.ru/api/query?type=service&format=records
strandedUser https://vcd.cloud4y.ru/api/query?type=strandedUser&format=records
task https://vcd.cloud4y.ru/api/query?type=task&format=records
toCloudTunnel https://vcd.cloud4y.ru/api/query?type=toCloudTunnel&format=records
user https://vcd.cloud4y.ru/api/query?type=user&format=records
vApp https://vcd.cloud4y.ru/api/query?type=vApp&format=records
vAppNetwork https://vcd.cloud4y.ru/api/query?type=vAppNetwork&format=records
vAppOrgVdcNetworkRelation https://vcd.cloud4y.ru/api/query?type=vAppOrgVdcNetworkRelation&format=records
vAppTemplate https://vcd.cloud4y.ru/api/query?type=vAppTemplate&format=records
vm https://vcd.cloud4y.ru/api/query?type=vm&format=records
vmDiskRelation https://vcd.cloud4y.ru/api/query?type=vmDiskRelation&format=records
otherAttributes :
href : https://vcd.cloud4y.ru/api/query?type=edgeGateway&format=records
id :
name : edgeGateway
type : application/vnd.vmware.vcloud.query.records+json
model :
rel : down
vCloudExtension : {}
otherAttributes :
href : https://vcd.cloud4y.ru/api/query?type=gatewayUplinks&format=records
id :
name : gatewayUplinks
type : application/vnd.vmware.vcloud.query.records+json
model :
rel : down
vCloudExtension : {}
3 - запрос Edge'ей в своей вОрг (тенанте)
Подходящий тип запроса - edgeGateway
, так мы узнаем ИД, необходимый для дальнейшей работы с маршрутизатором. Продробнее про параметры, определённые ниже, вы можете узнать из официальной документации по ссылкам в конце статьи. Если в вашей вОрг несколько вДЦ (виртуальных дата-центров), то можно либо получить список всех своих маршрутизаторов, либо сразу указать нужный с помощью 'filter' = 'name==*edge_name*'
.
$params = [ordered] @{
'format' = 'records'
'type' = 'edgeGateway'
'page' = 1
'pageSize' = 128
# 'filter' = 'name==*{0}*' -f $Edge
}
$paramsStr = ($params.GetEnumerator() | ForEach-Object {$_.Key + '=' + $_.Value}) -join '&'
$rTenantEdges = Invoke-WebRequest -UseBasicParsing -Method 'Get' -Headers $AuthHeaders -Uri ('{0}?{1}' -f $uriQuery, $paramsStr)
$rTenantEdgesBody = [System.Text.Encoding]::UTF8.GetString($rTenantEdges.Content) | ConvertFrom-Json
"`n{0}" -f 'step 3 - edge list' | Out-Default
$rTenantEdgesBody.record | Select-Object -Property 'name', 'href' | Out-Default
step 3 - edge list
name href
---- ----
demo-tenant_M14_VDC_k8s_Edge https://vcd.cloud4y.ru/api/admin/edgeGateway/1e995b68-e864-45b0-bdb5-6e4fa2d4d487
demo-tenant_K41_VDC_Edge https://vcd.cloud4y.ru/api/admin/edgeGateway/b056f3c9-3712-46c6-98d1-a6e5eea2b99f
4 - проверка Edge на Advanced'ность
Прежде, чем двигаться далее, необходимо проверить, является ли ваш маршрутизатор Advanced
, от этого зависит дальнейший способ работы. Если да, то необходимо использовать NSX API. Если нет, то с ним можно работать, как описано в статье Изменение параметров EDGE c помощью vCloud API нашей БЗ.
$uriEdge = $rTenantEdgesBody.record | Where-Object {$_.name -match $Edge} | Select-Object -ExpandProperty 'href'
$rEdgeFullInfo = Invoke-WebRequest -UseBasicParsing -Method 'Get' -Headers $AuthHeaders -Uri $uriEdge
$rEdgeFullInfoBody = [System.Text.Encoding]::UTF8.GetString($rEdgeFullInfo.Content) | ConvertFrom-Json
"`n{0}" -f 'step 4 - check target edge "advanced" property' | Out-Default
"`n'{0}' is{1} Advanced because 'AdvancedNetworkingEnabled' is {2}" -f $Edge, (' not' * [int][bool] (-not $rEdgeFullInfoBody.configuration.advancedNetworkingEnabled)), $rEdgeFullInfoBody.configuration.advancedNetworkingEnabled | Out-Default
# Verify that the Edge Gateway is not an Advanced Gateway
if ($rEdgeFullInfoBody.configuration.advancedNetworkingEnabled)
{
@(
'using the VMware Cloud Director API to configure Edge Gateway services can produce unexpected results'
'Use "VMware Cloud Director API for NSX Programming Guide" instead:'
' https://developer.vmware.com/docs/12789/vmware-cloud-director-api-for-nsx-programming-guide'
' https://vdc-download.vmware.com/vmwb-repository/dcr-public/6c72dc6b-b5c5-4563-b781-189f11fd7d51/ba3dd30d-4355-4b4f-91ee-a041a51decda/vmware_cloud_director_nsx_api_guide_35_0.pdf'
) | Out-Default
}
else
{
@(
'Use "VMware Cloud Director API Programming Guide":'
' https://vdc-download.vmware.com/vmwb-repository/dcr-public/715b0387-34d7-4568-b2d8-d11454c52d51/944f905e-fa4e-4005-be7d-19c3cea70ffd/vmware_cloud_director_sp_api_guide_35_0.pdf#unique_93'
' https://developer.vmware.com/docs/12676/vmware-cloud-director-api-programming-guide/GUID-1E7274A7-57D3-488F-9EFF-1D097FFE61A8.html'
' https://client.cloud4y.ru/knowledgebase.php?action=displayarticle&catid=19&id=665'
) | Out-Default
"`n{0}`n{1}" -f 'step 4 - edge full view', $uriEdge
$rEdgeFullInfoBody.link | Where-Object { $_.type -notmatch 'xml' } | Select-Object -Property 'rel', 'type', 'href' | Format-Table -AutoSize
$rEdgeFullInfoBody | ConvertTo-Json -Depth 13 | Out-File -FilePath ('./{0}.json' -f $rEdgeFullInfoBody.name)
}
step 4 - check target edge "advanced" property
'demo-tenant_K41_VDC_Edge' is Advanced because 'AdvancedNetworkingEnabled' is True
using the VMware Cloud Director API to configure Edge Gateway services can produce unexpected results
Use "VMware Cloud Director API for NSX Programming Guide" instead:
https://developer.vmware.com/docs/12789/vmware-cloud-director-api-for-nsx-programming-guide
https://vdc-download.vmware.com/vmwb-repository/dcr-public/6c72dc6b-b5c5-4563-b781-189f11fd7d51/ba3dd30d-4355-4b4f-91ee-a041a51decda/vmware_cloud_director_nsx_api_guide_35_0.pdf
5 - конфигурация Advanced Edge Gateway
$id = $uriEdge -split '/' | Select-Object -Last 1
$rNat = Invoke-WebRequest -UseBasicParsing -Method 'Get' -Headers $AuthHeaders -Uri ('{0}/edges/{1}/nat/config' -f $uriNsx, $id)
$rNat = $rNat.Content | ConvertFrom-Json
$rNat | ConvertTo-Json -Depth 13 | Out-File -FilePath ('./{0}_nat.json' -f $rEdgeFullInfoBody.name)
if ($DemoAddingNatRule)
{
$rNat.rules.natRulesDtos += [PSCustomObject] @{
# ruleId = 0
# ruleTag = 0
loggingEnabled = $false
enabled = $false
description = 'DEMO - JUST ADDING ONE MORE DISABLING NAT RULE, ALLOWING RDP OVER UDP'
translatedAddress = '192.168.0.123'
ruleType = 'user'
action = 'dnat'
vnic = '0'
originalAddress = '176.53.183.149'
dnatMatchSourceAddress = 'any'
protocol = 'udp'
originalPort = '3389'
translatedPort = '3389'
dnatMatchSourcePort = 'any'
}
$rNat.rules.natRulesDtos | Format-Table -AutoSize
$rNatMod = Invoke-WebRequest -UseBasicParsing -Method 'Put' -Headers $AuthHeaders -Uri ('{0}/edges/{1}/nat/config' -f $uriNsx, $id) -Body ($rNat | ConvertTo-Json -Depth 13) -ContentType "application/*+json;charset=UTF-8"
$rNatMod | Out-Default
}
else
{
$rNat.rules.natRulesDtos | Format-Table -AutoSize | Out-Default
}
ruleId ruleTag loggingEnabled enabled description translatedAddress ruleT
ype
------ ------- -------------- ------- ----------- ----------------- -----
196609 196609 False True allow Internet access for demo-tenant_K41_VDC_LAN 176.53.183.149 user
196610 196610 False True allow RDP to unexisting VM 192.168.0.123 user
False False DEMO - JUST ADDING ONE MORE DISABLING NAT RULE, ALLOWING RDP OVER UDP 192.168.0.123 user
StatusCode : 204
StatusDescription : No Content
Content : {}
RawContent : HTTP/1.1 204 No Content
Connection: close
X-VMWARE-VCLOUD-REQUEST-ID: ff2d5311-a0fa-477e-83e2-30750618e20b
Strict-Transport-Security: max-age=31536000
X-XSS-Protection: 1; mode=block
X-Content-Ty...
Headers : {[Connection, close], [X-VMWARE-VCLOUD-REQUEST-ID, ff2d5311-a0fa-477e-83e2-30750618e20b], [Strict-Transport-Sec
urity, max-age=31536000], [X-XSS-Protection, 1; mode=block]...}
RawContentLength : 0
Список материалов