diff --git a/samples/vmc/networks/expose_public_ip.py b/samples/vmc/networks/expose_public_ip.py new file mode 100644 index 00000000..1ee64bd1 --- /dev/null +++ b/samples/vmc/networks/expose_public_ip.py @@ -0,0 +1,244 @@ +#!/usr/bin/env python + +""" +* ******************************************************* +* Copyright (c) VMware, Inc. 2018. All Rights Reserved. +* SPDX-License-Identifier: MIT +* ******************************************************* +* +* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN, +* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED +* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, +* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. +""" + +__author__ = 'VMware, Inc.' +__vcenter_version__ = 'VMware Cloud on AWS' + +import argparse +import random + +from com.vmware.vmc.model_client import * +from vmware.vapi.vmc.client import create_vmc_client +from samples.vmc.helpers.vmc_task_helper import wait_for_task + + +class ExposePublicIP(object): + """ + Demo steps required to expose a VM to public internet + 1. Request a public IP address + 2. Add a firewall rule on compute gateway to access to the VM + 3. Create a NAT rule to forward traffic from public IP to private IP + + Sample Prerequisites: + - A VM deployed inside the SDDC with private IP address + """ + + def __init__(self): + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument('-r', '--refresh-token', + required=True, + help='VMware Cloud API refresh token') + + parser.add_argument('-o', '--org-id', + required=True, + help='Organization identifier.') + + parser.add_argument('-s', '--sddc-id', + required=True, + help='Sddc Identifier.') + + parser.add_argument('--notes', + default='Sample public IP ' + str(random.randint(0, 100)), + help='Notes of the new public IP') + + parser.add_argument('--fw-rule-name', + default='Sample firewall rule ' + str(random.randint(0, 100)), + help='Name of the compute gae') + + parser.add_argument('--nat-rule-description', + default='Sample NAT rule ' + str(random.randint(0, 100)), + help='Description for the NAT rule') + + parser.add_argument('--internal-ip', + required=True, + help='Private IP of the VM') + + parser.add_argument('-c', '--cleardata', + action='store_true', + help='Clean up after sample run') + args = parser.parse_args() + + self.network_id = None + self.edge_id = None + self.nat_rule_id = None + self.public_ip = None + self.nfwr = None + self.org_id = args.org_id + self.sddc_id = args.sddc_id + self.notes = args.notes + self.fw_rule_name = args.fw_rule_name + self.nat_rule_description = args.nat_rule_description + self.internal_ip = args.internal_ip + self.cleardata = args.cleardata + self.vmc_client = create_vmc_client(args.refresh_token) + + def setup(self): + # Check if the organization exists + orgs = self.vmc_client.Orgs.list() + if self.org_id not in [org.id for org in orgs]: + raise ValueError("Org with ID {} doesn't exist".format(self.org_id)) + + # Check if the SDDC exists + sddcs = self.vmc_client.orgs.Sddcs.list(self.org_id) + if self.sddc_id not in [sddc.id for sddc in sddcs]: + raise ValueError("SDDC with ID {} doesn't exist in org {}". + format(self.sddc_id, self.org_id)) + + edges = self.vmc_client.orgs.sddcs.networks.Edges.get( + org=self.org_id, + sddc=self.sddc_id, + edge_type='gatewayServices').edge_page.data + print('\n# Setup: Compute Gateway ID: {}'.format(edges[1].id)) + self.edge_id = edges[1].id + + def request_public_ip(self): + print('\n# Example: Request a new IP for SDDC') + ip_spec = SddcAllocatePublicIpSpec(names=[self.notes], count=1) + task = self.vmc_client.orgs.sddcs.Publicips.create( + org=self.org_id, + sddc=self.sddc_id, + spec=ip_spec) + + wait_for_task(task_client=self.vmc_client.orgs.Tasks, + org_id=self.org_id, + task_id=task.id, + interval_sec=2) + + ips = self.vmc_client.orgs.sddcs.Publicips.list( + org=self.org_id, + sddc=self.sddc_id) + + for ip in ips: + if ip.name == self.notes: + self.ip_id = ip.allocation_id + self.public_ip = ip.public_ip + print('# Successfully requested public IP {}'. + format(ip.public_ip)) + break + else: + raise Exception("Can't find public IP with notes {}". + format(self.notes)) + + def create_firewall_rule_on_cgw(self): + + print('\n# Example: Add a firewall rule to the compute gateway') + + # Construct a new NSX firewall rule object + # which allow any to any traffic + self.nfwr = Nsxfirewallrule(rule_type='user', + name=self.fw_rule_name, + enabled=True, + action='accept', + source=AddressFWSourceDestination( + exclude=False, + ip_address=['any'], + grouping_object_id=[], + vnic_group_id=[]), + destination=AddressFWSourceDestination( + exclude=False, + ip_address=['any'], + grouping_object_id=[], + vnic_group_id=[]), + logging_enabled=False, + application=None) + + self.vmc_client.orgs.sddcs.networks.edges.firewall.config.Rules.add( + org=self.org_id, + sddc=self.sddc_id, + edge_id=self.edge_id, + firewall_rules=FirewallRules([self.nfwr])) + + print(' # New firewall rule "{}" is added'.format(self.fw_rule_name)) + + def create_net_rule(self): + + print('\n# Example: Add a NAT rule to the compute gateway') + + # Construct a new NSX NAT rule spec + rule = Nsxnatrule(vnic='0', + rule_type='user', + action='dnat', # Supported types are DNAT|SNAT + protocol='any', + description=self.nat_rule_description, + original_address=self.public_ip, + original_port='any', + translated_address=self.internal_ip, + translated_port='any', + enabled=True) + + self.vmc_client.orgs.sddcs.networks.edges.nat.config.Rules.add( + org=self.org_id, + sddc=self.sddc_id, + edge_id=self.edge_id, + nat_rules=NatRules([rule])) + + print(' # New NAT rule "{}" is added'.format(self.nat_rule_description)) + + def cleanup(self): + if self.cleardata: + + # Delete the firewall rule + fw_rules = self.vmc_client.orgs.sddcs.networks.edges.firewall.Config.get( + org=self.org_id, + sddc=self.sddc_id, + edge_id=self.edge_id).firewall_rules.firewall_rules + + for r in fw_rules: + if r.name == self.fw_rule_name: + self.vmc_client.orgs.sddcs.networks.edges.firewall.config.Rules.delete( + org=self.org_id, + sddc=self.sddc_id, + edge_id=self.edge_id, + rule_id=r.rule_id) + break + print('\n# Cleanup: Firewall rule {} is deleted'. + format(self.fw_rule_name)) + + # Delete the NAT rule + rules = self.vmc_client.orgs.sddcs.networks.edges.nat.Config.get( + org=self.org_id, + sddc=self.sddc_id, + edge_id=self.edge_id).rules.nat_rules_dtos + for rule in rules: + if rule.description == self.nat_rule_description: + self.vmc_client.orgs.sddcs.networks.edges.nat.config.Rules.delete( + org=self.org_id, + sddc=self.sddc_id, + edge_id=self.edge_id, + rule_id=rule.rule_id) + print('\n# Cleanup: NAT rule "{}" is deleted'. + format(self.nat_rule_description)) + + # Release the public IP address + self.vmc_client.orgs.sddcs.Publicips.delete( + org=self.org_id, + sddc=self.sddc_id, + id=self.ip_id) + print('\n# Cleanup: Public IP "{}" is released'. + format(self.public_ip)) + + +def main(): + expose_public_ip = ExposePublicIP() + expose_public_ip.setup() + expose_public_ip.request_public_ip() + expose_public_ip.create_firewall_rule_on_cgw() + expose_public_ip.create_net_rule() + expose_public_ip.cleanup() + + +if __name__ == '__main__': + main()