В этой статье расскажу, как работать через API с NSX Edge. Это решение от VMware выполняет для виртуального дата-центра функции маршрутизации, Firewall, NAT, DHCP, VPN и другие. Благодаря возможностям работы через API отправка запросов к Edge становится удобнее и нагляднее, чем в командной строке. 

Описанный здесь способ также решает некоторые проблемы обращения к Edge через vCloud Director. При работе через API у нас есть возможность работать с Edge напрямую через NSX или через  vCloud Director, а также с помощью API обращаться к БД vCloud Director. Покажу оба варианта. 

Вот наиболее интересные сценарии, когда нам пригодится использование API:

  1. Миграция Edge в другой NSX-менеджер.

  2. Восстановление Edge или части его настроек. Например, если после миграции из одного дата-центра в другой мы также переносим настройки файрвола, VPN, балансировщика нагрузки и т. п. 

  3. Резервное копирование настроек. Например, если мы хотим сохранить конфигурацию Edge в формате XML и при необходимости вернуться к ней. 

В описании я использую NSX-V 6.4.6 и vCloud Director 10.2, однако статья актуальна и для других версий ПО. Для всех экспериментов пользовался документацией по API отсюда.

Готовим инструмент для работы с API

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

Сразу напомню самые распространенные типы запросов:

GET – получение информации из инфраструктуры, не выполняет изменения.

POST – чаще всего создание нового объекта или добавление конфигурации к существующему.

PUT – обновление текущего объекта, старые данные объекта затираются.

DELETE – удаление объекта.

Чтобы запросы работали корректно, настроим Postman для работы с NSX-менеджером, который управляет всеми объектами Edge.

  1. Открываем Postman и настраиваем авторизацию. Выбираем тип Basic Auth, указываем логин и пароль от админской учетной записи. 

  2. Настраиваем заголовки. Указываем Content-Type: application/xml

  3. Пробуем вывести список Edge командой GET https://nsx-fqdn/api/4.0/edges (где nsx-fqdn – это IP-адрес или FQDN NSX-менеджера).

Получили 200 ОК, значит, все в порядке: авторизация, заголовки и другие параметры указаны верно.

Вывод этого запроса покажет длинный список Edge и базовую информацию по каждому из них. Посмотрим, как это использовать в нужном нам сценарии.

Восстанавливаем Edge целиком или его отдельные настройки

Возьмем пример, где актуальны все три сценария использования API. 

Итак, у нас есть 2 NSX-менеджера, один из которых мы восстановили  в изолированную сеть из бэкапа недельной давности, как описано здесь

Обозначим оригинальный NSX-менеджер как nsx-fqdn-1, а восстановленный  NSX-manager как nsx-fqdn-2. Предположим, по какой-то причине объект edge-8 был удален, и нам необходимо его восстановить.

  1. Для начала сформируем запрос на получение конфига этого Edge из восстановленного NSX. Авторизация и заголовки у нас уже настроены, необходимо только указать в запросе нужный FQDN NSX-менеджера.

    GET https://nsx-fqdn-2/api/4.0/edges/edge-8

  2. Получаем вот такую конфигурацию. Часть конфигурации изменил, чтобы избежать утечки данных. 

    Конфиг целиком.
    <?xml version="1.0" encoding="UTF-8"?>
    <edge>
        <id>edge-8</id>
        <version>8</version>
        <description></description>
        <status>deployed</status>
        <tenant>88ed64d3-516d-4932-a262-9987e9779f1e</tenant>
        <name>vse-test-delete-edge (877a6842-8a67-4dad-87cf-81e155c45763)</name>
        <fqdn>vse-f8b2ccec-ef9b-464f-8bab-eb67e27f15c3</fqdn>
        <enableAesni>true</enableAesni>
        <enableFips>false</enableFips>
        <vseLogLevel>info</vseLogLevel>
        <vnics>
            <vnic>
                <label>vNic_0</label>
                <name>vnic0</name>
                <addressGroups>
                    <addressGroup>
                        <primaryAddress>esxternal-ip</primaryAddress>
                        <secondaryAddresses>
                            <ipAddress>esxternal-ip</ipAddress>
                        </secondaryAddresses>
                        <subnetMask>255.255.255.192</subnetMask>
                        <subnetPrefixLength>26</subnetPrefixLength>
                    </addressGroup>
                </addressGroups>
                <mtu>1500</mtu>
                <type>uplink</type>
                <isConnected>true</isConnected>
                <index>0</index>
                <portgroupId>dvportgroup-731</portgroupId>
                <portgroupName>internet</portgroupName>
                <enableProxyArp>false</enableProxyArp>
                <enableSendRedirects>true</enableSendRedirects>
            </vnic>
            <vnic>
                <label>vNic_1</label>
                <name>vnic1</name>
                <addressGroups>
                    <addressGroup>
                        <primaryAddress>10.0.0.1</primaryAddress>
                        <subnetMask>255.255.255.0</subnetMask>
                        <subnetPrefixLength>24</subnetPrefixLength>
                    </addressGroup>
                </addressGroups>
                <mtu>1500</mtu>
                <type>internal</type>
                <isConnected>true</isConnected>
                <index>1</index>
                <portgroupId>virtualwire-380</portgroupId>
                <portgroupName>dvs.VCDVStest-1-5ca1ab95-ded5-4af5-bf90-96eaa70e5512</portgroupName>
                <enableProxyArp>false</enableProxyArp>
                <enableSendRedirects>true</enableSendRedirects>
            </vnic>
            <vnic>
                <label>vNic_2</label>
                <name>vnic2</name>
                <addressGroups/>
                <mtu>1500</mtu>
                <type>internal</type>
                <isConnected>false</isConnected>
                <index>2</index>
                <enableProxyArp>false</enableProxyArp>
                <enableSendRedirects>true</enableSendRedirects>
            </vnic>
            <vnic>
                <label>vNic_3</label>
                <name>vnic3</name>
                <addressGroups/>
                <mtu>1500</mtu>
                <type>internal</type>
                <isConnected>false</isConnected>
                <index>3</index>
                <enableProxyArp>false</enableProxyArp>
                <enableSendRedirects>true</enableSendRedirects>
            </vnic>
            <vnic>
                <label>vNic_4</label>
                <name>vnic4</name>
                <addressGroups/>
                <mtu>1500</mtu>
                <type>internal</type>
                <isConnected>false</isConnected>
                <index>4</index>
                <enableProxyArp>false</enableProxyArp>
                <enableSendRedirects>true</enableSendRedirects>
            </vnic>
            <vnic>
                <label>vNic_5</label>
                <name>vnic5</name>
                <addressGroups/>
                <mtu>1500</mtu>
                <type>internal</type>
                <isConnected>false</isConnected>
                <index>5</index>
                <enableProxyArp>false</enableProxyArp>
                <enableSendRedirects>true</enableSendRedirects>
            </vnic>
            <vnic>
                <label>vNic_6</label>
                <name>vnic6</name>
                <addressGroups/>
                <mtu>1500</mtu>
                <type>internal</type>
                <isConnected>false</isConnected>
                <index>6</index>
                <enableProxyArp>false</enableProxyArp>
                <enableSendRedirects>true</enableSendRedirects>
            </vnic>
            <vnic>
                <label>vNic_7</label>
                <name>vnic7</name>
                <addressGroups/>
                <mtu>1500</mtu>
                <type>internal</type>
                <isConnected>false</isConnected>
                <index>7</index>
                <enableProxyArp>false</enableProxyArp>
                <enableSendRedirects>true</enableSendRedirects>
            </vnic>
            <vnic>
                <label>vNic_8</label>
                <name>vnic8</name>
                <addressGroups/>
                <mtu>1500</mtu>
                <type>internal</type>
                <isConnected>false</isConnected>
                <index>8</index>
                <enableProxyArp>false</enableProxyArp>
                <enableSendRedirects>true</enableSendRedirects>
            </vnic>
            <vnic>
                <label>vNic_9</label>
                <name>vnic9</name>
                <addressGroups/>
                <mtu>1500</mtu>
                <type>internal</type>
                <isConnected>false</isConnected>
                <index>9</index>
                <enableProxyArp>false</enableProxyArp>
                <enableSendRedirects>true</enableSendRedirects>
            </vnic>
        </vnics>
        <appliances>
            <applianceSize>compact</applianceSize>
            <appliance>
                <highAvailabilityIndex>0</highAvailabilityIndex>
                <vcUuid>500615b5-3f65-146a-1d5c-0dce84fc60ea</vcUuid>
                <vmId>vm-4274</vmId>
                <resourcePoolId>resgroup-53</resourcePoolId>
                <resourcePoolName>System vDC (c8a308dd-2509-48ad-ab8e-54e93938394d)</resourcePoolName>
                <datastoreId>datastore-1</datastoreId>
                <datastoreName>DATASTORE</datastoreName>
                <hostId>host-18</hostId>
                <hostName>ESXi-host</hostName>
                <vmFolderId>group-v453</vmFolderId>
                <vmFolderName>Service VMs</vmFolderName>
                <vmHostname>vse-f8b2ccec-ef9b-464f-8bab-eb67e27f15c3-0</vmHostname>
                <vmName>vse-test-delete-edge (877a6842-8a67-4dad-87cf-81e155c45763)-0</vmName>
                <deployed>true</deployed>
                <cpuReservation>
                    <limit>-1</limit>
                    <reservation>64</reservation>
                </cpuReservation>
                <memoryReservation>
                    <limit>-1</limit>
                    <reservation>256</reservation>
                </memoryReservation>
                <edgeId>edge-8</edgeId>
                <configuredResourcePool>
                    <id>resgroup-53</id>
                    <name>System vDC (c8a308dd-2509-48ad-ab8e-54e93938394d)</name>
                    <isValid>true</isValid>
                </configuredResourcePool>
                <configuredDataStore>
                    <id>datastore-1</id>
                    <name>DATASTORE</name>
                    <isValid>true</isValid>
                </configuredDataStore>
                <configuredHost>
                    <id>host-18</id>
                    <name>ESXi-host</name>
                    <isValid>true</isValid>
                </configuredHost>
                <configuredVmFolder>
                    <id>group-v453</id>
                    <name>Service VMs</name>
                    <isValid>true</isValid>
                </configuredVmFolder>
            </appliance>
            <deployAppliances>true</deployAppliances>
        </appliances>
        <cliSettings>
            <remoteAccess>false</remoteAccess>
            <userName>admin</userName>
            <sshLoginBannerText>
    ***************************************************************************
    NOTICE TO USERS
     
    This computer system is the private property of its owner, whether
    individual, corporate or government.  It is for authorized use only.
    Users (authorized or unauthorized) have no explicit or implicit
    expectation of privacy.
     
    Any or all uses of this system and all files on this system may be
    intercepted, monitored, recorded, copied, audited, inspected, and
    disclosed to your employer, to authorized site, government, and law
    enforcement personnel, as well as authorized officials of government
    agencies, both domestic and foreign.
     
    By using this system, the user consents to such interception, monitoring,
    recording, copying, auditing, inspection, and disclosure at the
    discretion of such personnel or officials.  Unauthorized or improper use
    of this system may result in civil and criminal penalties and
    administrative or disciplinary action, as appropriate. By continuing to
    use this system you indicate your awareness of and consent to these terms
    and conditions of use. LOG OFF IMMEDIATELY if you do not agree to the
    conditions stated in this warning.
     
    ****************************************************************************</sshLoginBannerText>
            <passwordExpiry>99999</passwordExpiry>
        </cliSettings>
        <features>
            <nat>
                <version>3</version>
                <enabled>true</enabled>
                <natRules>
                    <natRule>
                        <ruleId>196609</ruleId>
                        <ruleTag>196609</ruleTag>
                        <loggingEnabled>false</loggingEnabled>
                        <enabled>true</enabled>
                        <translatedAddress>esxternal-ip</translatedAddress>
                        <ruleType>user</ruleType>
                        <action>snat</action>
                        <vnic>0</vnic>
                        <originalAddress>10.0.0.0/24</originalAddress>
                        <snatMatchDestinationAddress>any</snatMatchDestinationAddress>
                        <protocol>any</protocol>
                        <originalPort>any</originalPort>
                        <translatedPort>any</translatedPort>
                        <snatMatchDestinationPort>any</snatMatchDestinationPort>
                    </natRule>
                    <natRule>
                        <ruleId>196610</ruleId>
                        <ruleTag>196610</ruleTag>
                        <loggingEnabled>false</loggingEnabled>
                        <enabled>true</enabled>
                        <translatedAddress>10.0.0.3</translatedAddress>
                        <ruleType>user</ruleType>
                        <action>dnat</action>
                        <vnic>0</vnic>
                        <originalAddress>esxternal-ip</originalAddress>
                        <dnatMatchSourceAddress>any</dnatMatchSourceAddress>
                        <protocol>tcp</protocol>
                        <originalPort>443</originalPort>
                        <translatedPort>8443</translatedPort>
                        <dnatMatchSourcePort>any</dnatMatchSourcePort>
                    </natRule>
                </natRules>
                <nat64Rules/>
            </nat>
            <l2Vpn>
                <version>2</version>
                <enabled>false</enabled>
                <logging>
                    <enable>true</enable>
                    <logLevel>notice</logLevel>
                </logging>
            </l2Vpn>
            <featureConfig/>
            <featureConfig/>
            <dns>
                <version>2</version>
                <enabled>false</enabled>
                <cacheSize>16</cacheSize>
                <listeners>
                    <vnic>any</vnic>
                </listeners>
                <dnsViews>
                    <dnsView>
                        <viewId>view-0</viewId>
                        <name>vsm-default-view</name>
                        <enabled>true</enabled>
                        <viewMatch>
                            <ipAddress>any</ipAddress>
                            <vnic>any</vnic>
                        </viewMatch>
                        <recursion>false</recursion>
                    </dnsView>
                </dnsViews>
                <logging>
                    <enable>false</enable>
                    <logLevel>info</logLevel>
                </logging>
            </dns>
            <syslog>
                <version>2</version>
                <enabled>false</enabled>
                <protocol>udp</protocol>
            </syslog>
            <sslvpnConfig>
                <version>2</version>
                <enabled>false</enabled>
                <logging>
                    <enable>true</enable>
                    <logLevel>notice</logLevel>
                </logging>
                <advancedConfig>
                    <enableCompression>false</enableCompression>
                    <forceVirtualKeyboard>false</forceVirtualKeyboard>
                    <randomizeVirtualkeys>false</randomizeVirtualkeys>
                    <preventMultipleLogon>false</preventMultipleLogon>
                    <clientNotification></clientNotification>
                    <enablePublicUrlAccess>false</enablePublicUrlAccess>
                    <timeout>
                        <forcedTimeout>0</forcedTimeout>
                        <sessionIdleTimeout>10</sessionIdleTimeout>
                    </timeout>
                </advancedConfig>
                <clientConfiguration>
                    <autoReconnect>true</autoReconnect>
                    <upgradeNotification>false</upgradeNotification>
                </clientConfiguration>
                <layoutConfiguration>
                    <portalTitle>VMware</portalTitle>
                    <companyName>VMware</companyName>
                    <logoExtention>jpg</logoExtention>
                    <logoUri>/api/4.0/edges/edge-8/sslvpn/config/layout/images/portallogo</logoUri>
                    <logoBackgroundColor>56A2D4</logoBackgroundColor>
                    <titleColor>996600</titleColor>
                    <topFrameColor>000000</topFrameColor>
                    <menuBarColor>999999</menuBarColor>
                    <rowAlternativeColor>FFFFFF</rowAlternativeColor>
                    <bodyColor>FFFFFF</bodyColor>
                    <rowColor>F5F5F5</rowColor>
                </layoutConfiguration>
                <authenticationConfiguration>
                    <passwordAuthentication>
                        <authenticationTimeout>1</authenticationTimeout>
                        <primaryAuthServers/>
                        <secondaryAuthServer/>
                    </passwordAuthentication>
                </authenticationConfiguration>
            </sslvpnConfig>
            <featureConfig/>
            <highAvailability>
                <version>3</version>
                <enabled>false</enabled>
                <declareDeadTime>15</declareDeadTime>
                <logging>
                    <enable>false</enable>
                    <logLevel>info</logLevel>
                </logging>
                <security>
                    <enabled>false</enabled>
                </security>
            </highAvailability>
            <routing>
                <version>3</version>
                <enabled>true</enabled>
                <routingGlobalConfig>
                    <ecmp>false</ecmp>
                    <logging>
                        <enable>false</enable>
                        <logLevel>info</logLevel>
                    </logging>
                </routingGlobalConfig>
                <staticRouting>
                    <defaultRoute>
                        <vnic>0</vnic>
                        <mtu>1500</mtu>
                        <gatewayAddress>external-ip</gatewayAddress>
                        <adminDistance>1</adminDistance>
                    </defaultRoute>
                    <staticRoutes/>
                </staticRouting>
                <ospf>
                    <enabled>false</enabled>
                    <ospfAreas>
                        <ospfArea>
                            <areaId>51</areaId>
                            <type>nssa</type>
                            <authentication>
                                <type>none</type>
                            </authentication>
                        </ospfArea>
                        <ospfArea>
                            <areaId>0</areaId>
                            <type>normal</type>
                            <authentication>
                                <type>none</type>
                            </authentication>
                        </ospfArea>
                    </ospfAreas>
                    <ospfInterfaces/>
                    <redistribution>
                        <enabled>false</enabled>
                        <rules/>
                    </redistribution>
                    <gracefulRestart>true</gracefulRestart>
                    <defaultOriginate>false</defaultOriginate>
                </ospf>
            </routing>
            <featureConfig/>
            <gslb>
                <version>2</version>
                <enabled>false</enabled>
                <serviceTimeout>6</serviceTimeout>
                <persistentCache>
                    <maxSize>20</maxSize>
                    <ttl>300</ttl>
                </persistentCache>
                <queryPort>5666</queryPort>
                <logging>
                    <enable>false</enable>
                    <logLevel>info</logLevel>
                </logging>
            </gslb>
            <firewall>
                <version>6</version>
                <enabled>true</enabled>
                <globalConfig>
                    <tcpPickOngoingConnections>false</tcpPickOngoingConnections>
                    <enableFtpLooseMode>false</enableFtpLooseMode>
                    <tcpAllowOutOfWindowPackets>false</tcpAllowOutOfWindowPackets>
                    <tcpSendResetForClosedVsePorts>true</tcpSendResetForClosedVsePorts>
                    <dropInvalidTraffic>true</dropInvalidTraffic>
                    <logInvalidTraffic>false</logInvalidTraffic>
                    <tcpTimeoutOpen>30</tcpTimeoutOpen>
                    <tcpTimeoutEstablished>21600</tcpTimeoutEstablished>
                    <tcpTimeoutClose>30</tcpTimeoutClose>
                    <udpTimeout>60</udpTimeout>
                    <icmpTimeout>10</icmpTimeout>
                    <icmp6Timeout>10</icmp6Timeout>
                    <ipGenericTimeout>120</ipGenericTimeout>
                    <enableSynFloodProtection>false</enableSynFloodProtection>
                    <logIcmpErrors>false</logIcmpErrors>
                    <dropIcmpReplays>false</dropIcmpReplays>
                    <enableSnmpAlg>true</enableSnmpAlg>
                    <enableFtpAlg>true</enableFtpAlg>
                    <enableTftpAlg>true</enableTftpAlg>
                </globalConfig>
                <defaultPolicy>
                    <action>deny</action>
                    <loggingEnabled>false</loggingEnabled>
                </defaultPolicy>
                <firewallRules>
                    <firewallRule>
                        <id>131076</id>
                        <ruleTag>131076</ruleTag>
                        <name>firewall</name>
                        <ruleType>internal_high</ruleType>
                        <enabled>true</enabled>
                        <loggingEnabled>false</loggingEnabled>
                        <description>firewall</description>
                        <action>accept</action>
                        <source>
                            <exclude>false</exclude>
                            <vnicGroupId>vse</vnicGroupId>
                        </source>
                    </firewallRule>
                    <firewallRule>
                        <id>131077</id>
                        <ruleTag>131077</ruleTag>
                        <name>test</name>
                        <ruleType>user</ruleType>
                        <enabled>true</enabled>
                        <loggingEnabled>false</loggingEnabled>
                        <action>accept</action>
                        <source>
                            <exclude>false</exclude>
                            <vnicGroupId>vnic-index-1</vnicGroupId>
                        </source>
                        <application>
                            <service>
                                <protocol>icmp</protocol>
                                <icmpType>any</icmpType>
                            </service>
                        </application>
                    </firewallRule>
                    <firewallRule>
                        <id>131075</id>
                        <ruleTag>131075</ruleTag>
                        <name>default rule for ingress traffic</name>
                        <ruleType>default_policy</ruleType>
                        <enabled>true</enabled>
                        <loggingEnabled>false</loggingEnabled>
                        <description>default rule for ingress traffic</description>
                        <action>deny</action>
                    </firewallRule>
                </firewallRules>
            </firewall>
            <loadBalancer>
                <version>2</version>
                <enabled>false</enabled>
                <enableServiceInsertion>false</enableServiceInsertion>
                <accelerationEnabled>false</accelerationEnabled>
                <monitor>
                    <monitorId>monitor-1</monitorId>
                    <type>tcp</type>
                    <interval>5</interval>
                    <timeout>15</timeout>
                    <maxRetries>3</maxRetries>
                    <name>default_tcp_monitor</name>
                </monitor>
                <monitor>
                    <monitorId>monitor-2</monitorId>
                    <type>http</type>
                    <interval>5</interval>
                    <timeout>15</timeout>
                    <maxRetries>3</maxRetries>
                    <method>GET</method>
                    <url>/</url>
                    <name>default_http_monitor</name>
                </monitor>
                <monitor>
                    <monitorId>monitor-3</monitorId>
                    <type>https</type>
                    <interval>5</interval>
                    <timeout>15</timeout>
                    <maxRetries>3</maxRetries>
                    <method>GET</method>
                    <url>/</url>
                    <name>default_https_monitor</name>
                </monitor>
                <logging>
                    <enable>false</enable>
                    <logLevel>info</logLevel>
                </logging>
            </loadBalancer>
            <ipsec>
                <version>2</version>
                <enabled>false</enabled>
                <logging>
                    <enable>true</enable>
                    <logLevel>warning</logLevel>
                </logging>
                <sites/>
                <global>
                    <psk>******</psk>
                    <caCertificates/>
                    <crlCertificates/>
                </global>
            </ipsec>
            <bridges>
                <version>2</version>
                <enabled>false</enabled>
            </bridges>
            <dhcp>
                <version>2</version>
                <enabled>false</enabled>
                <staticBindings/>
                <ipPools/>
                <logging>
                    <enable>false</enable>
                    <logLevel>info</logLevel>
                </logging>
            </dhcp>
        </features>
        <autoConfiguration>
            <enabled>true</enabled>
            <rulePriority>high</rulePriority>
        </autoConfiguration>
        <type>gatewayServices</type>
        <isUniversal>false</isUniversal>
        <hypervisorAssist>false</hypervisorAssist>
        <tunnels/>
    </edge>
    
  3. Теперь на основе полученной конфигурации в виде XML создадим новый Edge. Для этого:

    • Удаляем из него данную часть

      <id>edge-8</id>
      <version>8</version>
      <status>deployed</status>
    • Меняем <name> </name>, если Edge с таким именем уже есть.

    • Если мы хотим восстановиться в другое место, меняем теги расположения

      <resourcePoolId>
      <resourcePoolName>
      <vmFolderId>
      <vmFolderName>

      и другие.

    • С помощью тега <password> </password> вставляем пароль на Edge между тегами  <userName> и <sshLoginBannerText>, например:

      <userName>admin</userName>
      <password>Test123!test123!</password>
      <sshLoginBannerText>
    • Удаляем из раздела NAT теги  ruleId, ruleTag, ruleType, например:

      <ruleId>196609</ruleId>
      <ruleTag>196609</ruleTag>
      <ruleType>user</ruleType>
  4. С помощью итоговой XML выполняем команду на создание нового Edge. Для этого вставим в поле Body всю XML, укажем тип raw XML и отправим запрос. 

    POST https://nsx-fqdn-1/api/4.0/edges/

Edge восстановлен под именем edge-9

Теперь отдельно восстановим настройки.

  1. Разберемся с ситуацией, когда нам нужно отдельно добавить правила NAT. Для начала нужно понять, в каком формате Edge формирует эти правила. Можно посмотреть в общем конфиге по тегу <nat>. Но чтобы долго не искать, получим NAT-правила отдельным запросом:

    GET https://nsx-fqdn-1/api/4.0/edges/edge-9/nat/config

  2. Добавим правила NAT с помощью POST-запроса. Для этого сначала удалим теги  ruleId, ruleTag, ruleType, в нашем случае:

    <ruleId>196609</ruleId>
    <ruleTag>196609</ruleTag>
    <ruleType>user</ruleType>

    И отправляем POST https://nsx-fqdn-1/api/4.0/edges/edge-9/nat/config/rules

    Пример NAT-правила:

    <natRules>
    <natRule>
    <action>dnat</action>
    <vnic>0</vnic>
    <originalAddress>esxternal_ip</originalAddress>
    <translatedAddress>192.168.1.9</translatedAddress>
    <loggingEnabled>false</loggingEnabled>
    <enabled>true</enabled>
    <description></description>
    <protocol>udp</protocol>
    <originalPort>80</originalPort>
    <translatedPort>80</translatedPort>
    </natRule>
    </natRules>
  3. Важно учесть, что правила NAT через POST-запрос не перезаписываются, а добавляются заново.

    Вот что будет, если выполнить запрос дважды:

Аналогично можно выполнить операции и с настройками по другим сервисам (firewall, vpn, load balancer и другие). На будущее мы можем сохранить настройки в виде XML и хранить этот файл в качестве резервной копии. 

Используем API вместе с vCloud Director. В нашем сценарии мы случайно удалили нужный нам Edge и затем восстановили его из резервной копии через API. Если Edge использовался vCloud Director’ом, но был удален через NSX-менеджер, то сам объект edge-8 удалится из vCenter, а ссылка на него останется. После восстановления наш Edge получил новый id, о котором vCloud Director еще не знает. При попытке обратиться к  сервисам через vCloud Director всплывет белый экран. Чтобы исправить это, внесем исправления в БД vCloud Director для изменения id c edge-8 на edge-9.

  1. Отправим запрос для таблицы gateway, чтобы узнать id:

    select * from gateway where name like 'test-delete-edge%'

    Получим:

    -- id=' 877a6842-8a67-4dad-87cf-81e155c45763 ' --name=' test-delete-edge' --backing-ref='edge-8'

  2. Проверяем, в каких таблицах есть упоминание об этом Edge:

    select * from global_search('edge-8')

  3. Проверяем, что выбрали нужный Edge: 

    select * from gateway where id = '877a6842-8a67-4dad-87cf-81e155c45763'

  4. Обновляем id Edge и убеждаемся, что он изменен.

    update gateway set backing_ref = 'edge-9' where id = '877a6842-8a67-4dad-87cf-81e155c45763'

  5. Проверим Edge со стороны vCloud Director.

Теперь сервисы отображаются корректно.

Перенесем сервисы из одного Edge в другой

Иногда с Edge требуется работать напрямую через vCloud Director, но и здесь Postman может пригодиться. Рассмотрим сценарий переноса сервисов через API vCloud Director с сохранением адресации:

  1. Открываем Postman.

  2. Настраиваем авторизацию:

    Autorization: Basic Auth - administrator@system

  3. Затем выполняем GET https://vCD-fqdn/api/versions

    Проверяем, отработал ли запрос и смотрим на версии api.

  4. Добавляем заголовок с этой версией:

    Accept application/*+xml;version=35.0

  5. Теперь перейдем на авторизацию по токену. Сначала получим токен с помощью запроса POST https://vCD-fqdn/api/sessions

    Берем отсюда: X-VMWARE-VCLOUD-ACCESS-TOKEN.

  6. Поменяем тип авторизации на Bearer Token и вставим значение X-VMWARE-VCLOUD-ACCESS-TOKEN.

  7. Выполняем запрос GET https://vCD-fqdn/api/admin, чтобы убедиться, что авторизация по токену работает.

  8. Открываем Powershell и выполняем connect-ciserver vCD-fqdn

    Далее: Get-OrgVdc OrgVDCName| Get-EdgeGateway EdgeName

    Копируем ссылку после Href.

    Href: https://vCD-fqdn/api/admin/edgeGateway/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

  9. Возвращаемся в Postman и получаем исходный конфиг с помощью этой ссылки:

    GET https://vCD-fqdn/api/admin/edgeGateway/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

  10. Создаем тело запроса на основе полученной конфигурации. Для этого берем такую “шапку”:

    <?xml version="1.0" encoding="UTF-8"?>
    <EdgeGatewayServiceConfiguration
       xmlns="http://www.vmware.com/vcloud/v1.5">
    …и дальше копируем то, что было между тегами 
      <EdgeGatewayServiceConfiguration>
      </EdgeGatewayServiceConfiguration>   

    Например:

    <?xml version="1.0" encoding="UTF-8"?>
    <EdgeGatewayServiceConfiguration
       xmlns="http://www.vmware.com/vcloud/v1.5">
                <GatewayDhcpService>
                    <IsEnabled>false</IsEnabled>
                </GatewayDhcpService>
                <FirewallService>
                    <IsEnabled>true</IsEnabled>
                    <DefaultAction>allow</DefaultAction>
                    <LogDefaultAction>false</LogDefaultAction>
                </FirewallService>
                <NatService>
                    <IsEnabled>true</IsEnabled>
                    <NatRule>
                        <RuleType>SNAT</RuleType>
                        <IsEnabled>true</IsEnabled>
                        <Id>196609</Id>
                        <GatewayNatRule>
                            <Interface href="https://fqdn-vcd/api/admin/network/xxxxxx" name="network" type="application/vnd.vmware.admin.network+xml"/>
                            <OriginalIp>10.0.0.0/24</OriginalIp>
                            <TranslatedIp>external-ip</TranslatedIp>
                        </GatewayNatRule>
                    </NatRule>
                </NatService>
                <GatewayIpsecVpnService>
                    <IsEnabled>false</IsEnabled>
                </GatewayIpsecVpnService>
                <StaticRoutingService>
                    <IsEnabled>true</IsEnabled>
                </StaticRoutingService>
                <LoadBalancerService>
                    <IsEnabled>false</IsEnabled>
                </LoadBalancerService>
    </EdgeGatewayServiceConfiguration>

    Если на Edge меняются портгруппы, необходимо в теге <Interface/> заменить сети из старого Edge на сети из нового Edge, куда переносим сервисы:

    <Interface href="https://fqdn-vcd/api/admin/network/xxxxxx" name="network" type="application/vnd.vmware.admin.network+xml"/>
  11. Добавим новую конфигурацию POST-запросом.  Для этого вставим полученную XML в Body в формате raw для пустого Edge.  Добавляем заголовок content-type application/vnd.vmware.admin.edgeGatewayServiceConfiguration+xml

    В сам запрос вставляем ссылку на нужный Edge, добавив к url /action/configureServices, например:

    POST https://vCD-fqdn/api/admin/edgeGateway/XXXX/action/configureServices

Конфигурация перенесена.

Этим же способом можно автоматизировать процесс сбора конфигурации. Так можно собирать XML для каждого Edge с помощью скриптов, опрашивающих api. Еще одна отдельная тема – открытие доступа к БД vCloud Director, а также некоторые операции с БД. Если интересно узнать об этом подробнее, пишите, расскажу отдельно.