Changing Advanced Edge settings via API using PowerShell 7

In this article, we will take a look on some Advanced Edge Gateway actions available to the tenant (client) and how to work with it via API using PowerShell. You can find links to the official documentation at the end of the article. In short, though, you can do the same things through the API as you do through the web interface for managing your cloud.

According to the role-based access model, changes are available to the client in the section Services > Firewall / NAT / VPN / ... For example, the following settings are available for view only, as they are changed by C4Y engineers:

  • Rate Limits
  • IP Allocations
  • General > Name / Edge Gateway Configuration / ...

To help you understand the official documentation, we'll show how to work through the API by adding a DNAT rule to connect to a Windows server with RDP.

0 - preparation

First, we need to specify the data to work with - cloud, tenant (vOrg), Organization Administrator account and the name of Edge we are going to work with

#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 - open a session

The general principle of working with the cloud via API is as follows:

  • find out the latest current version of the API
  • open a work session, performing basic authorization in the cloud in your tenant with username and password
  • for all other queries, use the token of the session opened at the previous step as authorization
$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 allows you to get basic information, including the ID of cloud objects: vOrg, vDC, VMs, networks, Edge Gateway, etc. Then, knowing the object ID, you can get detailed object properties, including links to change, via API.

Let's look at the valid queries and select those related to the router.

# посмотреть все возможные типы запросов можно так:
$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 - query the Edge in its vOrg (tenant)

The appropriate request type is edgeGateway, so we find out the ID required for further work with the router. For more details about the parameters defined below, see the official documentation available at the end of this article. If you have several VDCs in your Org, you can either get the list of all your routers, or specify the required one immediately using '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 - Checking the Edge

Before moving on, you need to check if your router is an Advanced router, this will determine the way to proceed. If it is Advanced, you need to use the NSX API. If not, you can work with it as described in the article Changing EDGE settings with the 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
$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

Resources

  1. Rights in Predefined Global Tenant Roles

  2. VMware Cloud Director Documentation (table of different versions)

  3. VMware Cloud Director API page, "Documentation" tab:

    • "VMware Cloud Director API Programming Guide", chapter "Configure Edge Gateway Services" pdfhtml

    • "VMware Cloud Director API for NSX Programming Guide" pdfhtml

 

 

  • Edge, NSX, API, PowerShell
  • 1 Users Found This Useful
Was this answer helpful?

Related Articles

vCloud API programming guide for service providers

This release of vCloud API Programming Guide for Service Providers contains information on...

vCloud Director API for NSX. Programmers’ Guide

About vCloud Director API для NSX vCloud Director API для NSX. vCloud Director API for NSX is a...

How to access VMware Cloud Director via the vCloud API

Overview To perform some tasks in a CLOUD4Y environment, you may need to access VMware Cloud...

Changing EDGE settings with the vCloud API

Introduction This tutorial shows how to receive, modify and send XML blocks, which represent the...