В данной статье мы рассмотрим, какие действия с 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
Список материалов