| #!/usr/bin/env python | |
| # Licensed to the Apache Software Foundation (ASF) under one or more | |
| # contributor license agreements. See the NOTICE file distributed with | |
| # this work for additional information regarding copyright ownership. | |
| # The ASF licenses this file to You under the Apache License, Version 2.0 | |
| # (the "License"); you may not use this file except in compliance with | |
| # the License. You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| # This example performs several tasks on Google Compute Platform. It can be | |
| # run directly or can be imported into an interactive python session. This | |
| # can also serve as live integration tests. | |
| # | |
| # To run directly, use python 2.7 or greater: | |
| # - $ python gce_demo.py --help # to see the help screen | |
| # - $ python gce_demo.py # to run all demos / tests | |
| # | |
| # To run interactively: | |
| # - Make sure you have valid values in secrets.py | |
| # (For more information about setting up your credentials, see the | |
| # libcloud/common/google.py docstring) | |
| # - Run 'python' in this directory, then: | |
| # import gce_demo | |
| # gce = gce_demo.get_gce_driver() | |
| # gce.list_nodes() | |
| # etc. | |
| # - Or, to run the full demo from the interactive python shell: | |
| # import gce_demo | |
| # gce_demo.CLEANUP = False # optional | |
| # gce_demo.MAX_NODES = 4 # optional | |
| # gce_demo.DATACENTER = 'us-central1-a' # optional | |
| # gce_demo.main_compute() # 'compute' only demo | |
| # gce_demo.main_load_balancer() # 'load_balancer' only demo | |
| # gce_demo.main_dns() # 'dns only demo | |
| # gce_demo.main() # all demos / tests | |
| import sys | |
| import time | |
| import os.path | |
| import argparse | |
| import datetime | |
| # Add parent dir of this file's dir to sys.path (OS-agnostically) | |
| sys.path.append(os.path.normpath(os.path.join(os.path.dirname(__file__), os.path.pardir))) | |
| # isort:skip pragma is needed to make sure those imports are not moved above | |
| # sys.path manipulation code (https://github.com/PyCQA/isort/issues/468) | |
| from libcloud.dns.base import Zone, Record # isort:skip | |
| from libcloud.dns.types import Provider as Provider_dns # isort:skip | |
| from libcloud.common.google import ResourceNotFoundError # isort:skip | |
| from libcloud.compute.types import Provider # isort:skip | |
| from libcloud.dns.providers import get_driver as get_driver_dns # isort:skip | |
| from libcloud.compute.providers import get_driver # isort:skip | |
| from libcloud.loadbalancer.types import Provider as Provider_lb # isort:skip | |
| from libcloud.loadbalancer.providers import get_driver as get_driver_lb # isort:skip | |
| try: | |
| import secrets | |
| except ImportError: | |
| print( | |
| '"demos/secrets.py" not found.\n\n' | |
| "Please copy secrets.py-dist to secrets.py and update the GCE* " | |
| "values with appropriate authentication information.\n" | |
| "Additional information about setting these values can be found " | |
| "in the docstring for:\n" | |
| "libcloud/common/google.py\n" | |
| ) | |
| sys.exit(1) | |
| # pylint: disable=no-name-in-module,import-error | |
| import urllib.request as url_req | |
| # Maximum number of 1-CPU nodes to allow to run simultaneously | |
| MAX_NODES = 5 | |
| # String that all resource names created by the demo will start with | |
| # WARNING: Any resource that has a matching name will be destroyed. | |
| DEMO_BASE_NAME = "lct" | |
| # Datacenter to create resources in | |
| DATACENTER = "us-central1-f" | |
| BACKUP_DATACENTER = "us-east1-c" | |
| # Clean up resources at the end (can be set to false in order to | |
| # inspect resources at the end of the run). Resources will be cleaned | |
| # at the beginning regardless. | |
| CLEANUP = True | |
| args = getattr(secrets, "GCE_PARAMS", ()) | |
| kwargs = getattr(secrets, "GCE_KEYWORD_PARAMS", {}) | |
| # Add datacenter to kwargs for Python 2.5 compatibility | |
| kwargs = kwargs.copy() | |
| kwargs["datacenter"] = DATACENTER | |
| # ==== HELPER FUNCTIONS ==== | |
| def get_gce_driver(): | |
| driver = get_driver(Provider.GCE)(*args, **kwargs) | |
| return driver | |
| def get_gcelb_driver(gce_driver=None): | |
| # The GCE Load Balancer driver uses the GCE Compute driver for all of its | |
| # API calls. You can either provide the driver directly, or provide the | |
| # same authentication information so the LB driver can get its own | |
| # Compute driver. | |
| if gce_driver: | |
| driver = get_driver_lb(Provider_lb.GCE)(gce_driver=gce_driver) | |
| else: | |
| driver = get_driver_lb(Provider_lb.GCE)(*args, **kwargs) | |
| return driver | |
| def get_dns_driver(gce_driver=None): | |
| # The Google DNS driver uses the GCE Compute driver for all of its | |
| # API calls. You can either provide the driver directly, or provide the | |
| # same authentication information so the LB driver can get its own | |
| # Compute driver. | |
| if gce_driver: | |
| driver = get_driver_dns(Provider_dns.GOOGLE)(gce_driver=gce_driver) | |
| else: | |
| driver = get_driver_dns(Provider_dns.GOOGLE)(*args, **kwargs) | |
| return driver | |
| def create_mig(gce, mig_base_name, zone, template, postfix, num_instances=2): | |
| """ | |
| Creates MIG, sets named ports, modifies various text with 'postfix'. | |
| :param gce: An initalized GCE driver. | |
| :type gce: :class`GCENodeDriver` | |
| :param zone: Zone to create Managed Instance Group in. | |
| :type zone: :class:`GCEZone` or ``str`` | |
| :param template: Instance Template to use in creating MIG. | |
| :type template: :class:`GCEInstanceTemplate` | |
| :param postfix: string to append to mig name, etc. Example: 'east', | |
| 'central' | |
| :type postfix: ``str`` | |
| :param num_instances: number of instances to create in MIG. Default is 2. | |
| :type num_instances: ``int`` | |
| :returns: initialized Managed Instance Group. | |
| :rtype: :class:`GCEInstanceGroupManager` | |
| """ | |
| mig_name = "{}-{}".format(mig_base_name, postfix) | |
| mig = gce.ex_create_instancegroupmanager( | |
| mig_name, | |
| zone, | |
| template, | |
| num_instances, | |
| base_instance_name=mig_name, | |
| description="Demo for %s" % postfix, | |
| ) | |
| display(' Managed Instance Group [{}] "{}" created'.format(postfix.upper(), mig.name)) | |
| display( | |
| " ... MIG instances created: %s" | |
| % ",".join([x["name"] for x in mig.list_managed_instances()]) | |
| ) | |
| # set the named_ports on the Instance Group. | |
| named_ports = [{"name": "%s-http" % DEMO_BASE_NAME, "port": 80}] | |
| mig.set_named_ports(named_ports=named_ports) | |
| display(" ... MIG ports set: %s" % named_ports) | |
| return mig | |
| def display(title, resource_list=[]): | |
| """ | |
| Display a list of resources. | |
| :param title: String to be printed at the heading of the list. | |
| :type title: ``str`` | |
| :param resource_list: List of resources to display | |
| :type resource_list: Any ``object`` with a C{name} attribute | |
| """ | |
| print("=> %s" % title) | |
| for item in resource_list: | |
| if isinstance(item, Record): | |
| if item.name.startswith(DEMO_BASE_NAME): | |
| print("=> name={}, type={}".format(item.name, item.type)) | |
| else: | |
| print(" name={}, type={}".format(item.name, item.type)) | |
| elif isinstance(item, Zone): | |
| if item.domain.startswith(DEMO_BASE_NAME): | |
| print("=> name={}, dnsname={}".format(item.id, item.domain)) | |
| else: | |
| print(" name={}, dnsname={}".format(item.id, item.domain)) | |
| elif hasattr(item, "name"): | |
| if item.name.startswith(DEMO_BASE_NAME): | |
| print("=> %s" % item.name) | |
| else: | |
| print(" %s" % item.name) | |
| else: | |
| if item.startswith(DEMO_BASE_NAME): | |
| print("=> %s" % item) | |
| else: | |
| print(" %s" % item) | |
| def cleanup_only(): | |
| start_time = datetime.datetime.now() | |
| display("Clean-up start time: %s" % str(start_time)) | |
| gce = get_gce_driver() | |
| # Get project info and print name | |
| project = gce.ex_get_project() | |
| display("Project: %s" % project.name) | |
| # == Get Lists of Everything and Display the lists (up to 10) == | |
| # These can either just return values for the current datacenter (zone) | |
| # or for everything. | |
| all_nodes = gce.list_nodes(ex_zone="all") | |
| display("Nodes:", all_nodes) | |
| all_addresses = gce.ex_list_addresses(region="all") | |
| display("Addresses:", all_addresses) | |
| all_volumes = gce.list_volumes(ex_zone="all") | |
| display("Volumes:", all_volumes) | |
| # This can return everything, but there is a large amount of overlap, | |
| # so we'll just get the sizes from the current zone. | |
| sizes = gce.list_sizes() | |
| display("Sizes:", sizes) | |
| # These are global | |
| firewalls = gce.ex_list_firewalls() | |
| display("Firewalls:", firewalls) | |
| networks = gce.ex_list_networks() | |
| display("Networks:", networks) | |
| images = gce.list_images() | |
| display("Images:", images) | |
| locations = gce.list_locations() | |
| display("Locations:", locations) | |
| zones = gce.ex_list_zones() | |
| display("Zones:", zones) | |
| snapshots = gce.ex_list_snapshots() | |
| display("Snapshots:", snapshots) | |
| gfrs = gce.ex_list_forwarding_rules(global_rules=True) | |
| display("Global Forwarding Rules", gfrs) | |
| targetproxies = gce.ex_list_targethttpproxies() | |
| display("Target HTTP Proxies", targetproxies) | |
| urlmaps = gce.ex_list_urlmaps() | |
| display("URLMaps", urlmaps) | |
| bes = gce.ex_list_backendservices() | |
| display("Backend Services", bes) | |
| migs = gce.ex_list_instancegroupmanagers(zone="all") | |
| display("Instance Group Managers", migs) | |
| its = gce.ex_list_instancetemplates() | |
| display("Instance Templates", its) | |
| hcs = gce.ex_list_healthchecks() | |
| display("Health Checks", hcs) | |
| # == Clean up any old demo resources == | |
| display('Cleaning up any "%s" resources' % DEMO_BASE_NAME) | |
| clean_up( | |
| gce, | |
| DEMO_BASE_NAME, | |
| None, | |
| gfrs + targetproxies + urlmaps + bes + hcs + migs + its, | |
| ) | |
| # == Pause to let cleanup occur and repopulate volume and node lists == | |
| if len(migs): | |
| time.sleep(10) | |
| all_volumes = gce.list_volumes(ex_zone="all") | |
| all_nodes = gce.list_nodes(ex_zone="all") | |
| clean_up( | |
| gce, | |
| DEMO_BASE_NAME, | |
| all_nodes, | |
| all_addresses + all_volumes + firewalls + networks + snapshots, | |
| ) | |
| volumes = gce.list_volumes() | |
| clean_up(gce, DEMO_BASE_NAME, None, volumes) | |
| end_time = datetime.datetime.now() | |
| display("Total runtime: %s" % str(end_time - start_time)) | |
| def clean_up(gce, base_name, node_list=None, resource_list=None): | |
| """ | |
| Destroy all resources that have a name beginning with 'base_name'. | |
| :param base_name: String with the first part of the name of resources | |
| to destroy | |
| :type base_name: ``str`` | |
| :keyword node_list: List of nodes to consider for deletion | |
| :type node_list: ``list`` of :class:`Node` | |
| :keyword resource_list: List of resources to consider for deletion | |
| :type resource_list: ``list`` of I{Resource Objects} | |
| """ | |
| if node_list is None: | |
| node_list = [] | |
| if resource_list is None: | |
| resource_list = [] | |
| # Use ex_destroy_multiple_nodes to destroy nodes | |
| del_nodes = [] | |
| for node in node_list: | |
| if node.name.startswith(base_name): | |
| del_nodes.append(node) | |
| result = gce.ex_destroy_multiple_nodes(del_nodes) | |
| for i, success in enumerate(result): | |
| if success: | |
| display(" Deleted %s" % del_nodes[i].name) | |
| else: | |
| display(" Failed to delete %s" % del_nodes[i].name) | |
| # Destroy everything else with just the destroy method | |
| for resrc in resource_list: | |
| if resrc.name.startswith(base_name): | |
| try: | |
| resrc.destroy() | |
| class_name = resrc.__class__.__name__ | |
| display(" Deleted {} ({})".format(resrc.name, class_name)) | |
| except ResourceNotFoundError: | |
| display(" Not found: {} ({})".format(resrc.name, resrc.__class__.__name__)) | |
| except Exception: | |
| class_name = resrc.__class__.__name__ | |
| display(" Failed to Delete {} ({})".format(resrc.name, class_name)) | |
| raise | |
| def main_compute(): | |
| start_time = datetime.datetime.now() | |
| display("Compute demo/test start time: %s" % str(start_time)) | |
| gce = get_gce_driver() | |
| # Get project info and print name | |
| project = gce.ex_get_project() | |
| display("Project: %s" % project.name) | |
| # == Get Lists of Everything and Display the lists (up to 10) == | |
| # These can either just return values for the current datacenter (zone) | |
| # or for everything. | |
| all_nodes = gce.list_nodes(ex_zone="all") | |
| display("Nodes:", all_nodes) | |
| all_addresses = gce.ex_list_addresses(region="all") | |
| display("Addresses:", all_addresses) | |
| all_volumes = gce.list_volumes(ex_zone="all") | |
| display("Volumes:", all_volumes) | |
| # This can return everything, but there is a large amount of overlap, | |
| # so we'll just get the sizes from the current zone. | |
| sizes = gce.list_sizes() | |
| display("Sizes:", sizes) | |
| # These are global | |
| firewalls = gce.ex_list_firewalls() | |
| display("Firewalls:", firewalls) | |
| subnetworks = gce.ex_list_subnetworks() | |
| display("Subnetworks:", subnetworks) | |
| networks = gce.ex_list_networks() | |
| display("Networks:", networks) | |
| images = gce.list_images() | |
| display("Images:", images) | |
| locations = gce.list_locations() | |
| display("Locations:", locations) | |
| zones = gce.ex_list_zones() | |
| display("Zones:", zones) | |
| snapshots = gce.ex_list_snapshots() | |
| display("Snapshots:", snapshots) | |
| # == Clean up any old demo resources == | |
| display('Cleaning up any "%s" resources' % DEMO_BASE_NAME) | |
| # Delete subnetworks first, networks last | |
| clean_up(gce, DEMO_BASE_NAME, None, subnetworks) | |
| clean_up( | |
| gce, | |
| DEMO_BASE_NAME, | |
| all_nodes, | |
| all_addresses + all_volumes + firewalls + snapshots + networks, | |
| ) | |
| # == Create a Legacy Network == | |
| display("Creating Legacy Network:") | |
| name = "%s-legacy-network" % DEMO_BASE_NAME | |
| cidr = "10.10.0.0/16" | |
| network_legacy = gce.ex_create_network(name, cidr) | |
| display(" Network %s created" % name) | |
| # == Delete the Legacy Network == | |
| display("Delete Legacy Network:") | |
| network_legacy.destroy() | |
| display(" Network %s delete" % name) | |
| # == Create an auto network == | |
| display("Creating Auto Network:") | |
| name = "%s-auto-network" % DEMO_BASE_NAME | |
| network_auto = gce.ex_create_network(name, cidr=None, mode="auto") | |
| display(" AutoNetwork %s created" % network_auto.name) | |
| # == Display subnetworks from the auto network == | |
| subnets = [] | |
| for sn in network_auto.subnetworks: | |
| subnets.append(gce.ex_get_subnetwork(sn)) | |
| display("Display subnetworks:", subnets) | |
| # == Delete the auto network == | |
| display("Delete Auto Network:") | |
| network_auto.destroy() | |
| display(" AutoNetwork %s deleted" % name) | |
| # == Create an custom network == | |
| display("Creating Custom Network:") | |
| name = "%s-custom-network" % DEMO_BASE_NAME | |
| network_custom = gce.ex_create_network(name, cidr=None, mode="custom") | |
| display(" Custom Network %s created" % network_custom.name) | |
| # == Create a subnetwork == | |
| display("Creating Subnetwork:") | |
| sname = "%s-subnetwork" % DEMO_BASE_NAME | |
| region = "us-central1" | |
| cidr = "192.168.17.0/24" | |
| subnet = gce.ex_create_subnetwork(sname, cidr, network_custom, region) | |
| display(" Subnetwork %s created" % subnet.name) | |
| # Refresh object, now that it has a subnet | |
| network_custom = gce.ex_get_network(name) | |
| # == Display subnetworks from the auto network == | |
| subnets = [] | |
| for sn in network_custom.subnetworks: | |
| subnets.append(gce.ex_get_subnetwork(sn)) | |
| display("Display custom subnetworks:", subnets) | |
| # == Launch instance in custom subnetwork == | |
| display("Creating Node in custom subnetwork:") | |
| name = "%s-subnet-node" % DEMO_BASE_NAME | |
| node_1 = gce.create_node( | |
| name, | |
| "g1-small", | |
| "debian-8", | |
| ex_disk_auto_delete=True, | |
| ex_network=network_custom, | |
| ex_subnetwork=subnet, | |
| ) | |
| display(" Node %s created" % name) | |
| # == Destroy instance in custom subnetwork == | |
| display("Destroying Node in custom subnetwork:") | |
| node_1.destroy() | |
| display(" Node %s destroyed" % name) | |
| # == Delete an subnetwork == | |
| display("Delete Custom Subnetwork:") | |
| subnet.destroy() | |
| display(" Custom Subnetwork %s deleted" % sname) | |
| is_deleted = False | |
| while not is_deleted: | |
| time.sleep(3) | |
| try: | |
| subnet = gce.ex_get_subnetwork(sname, region) | |
| except ResourceNotFoundError: | |
| is_deleted = True | |
| # == Delete the auto network == | |
| display("Delete Custom Network:") | |
| network_custom.destroy() | |
| display(" Custom Network %s deleted" % name) | |
| # == Create Node with disk auto-created == | |
| if MAX_NODES > 1: | |
| display("Creating a node with boot/local-ssd using GCE structure:") | |
| name = "%s-gstruct" % DEMO_BASE_NAME | |
| img_url = "projects/debian-cloud/global/images/" | |
| img_url += "backports-debian-7-wheezy-v20141205" | |
| disk_type_url = "projects/%s/zones/us-central1-f/" % project.name | |
| disk_type_url += "diskTypes/local-ssd" | |
| gce_disk_struct = [ | |
| { | |
| "type": "PERSISTENT", | |
| "deviceName": "%s-gstruct" % DEMO_BASE_NAME, | |
| "initializeParams": { | |
| "diskName": "%s-gstruct" % DEMO_BASE_NAME, | |
| "sourceImage": img_url, | |
| }, | |
| "boot": True, | |
| "autoDelete": True, | |
| }, | |
| { | |
| "type": "SCRATCH", | |
| "deviceName": "%s-gstruct-lssd" % DEMO_BASE_NAME, | |
| "initializeParams": {"diskType": disk_type_url}, | |
| "autoDelete": True, | |
| }, | |
| ] | |
| node_gstruct = gce.create_node( | |
| name, | |
| "n1-standard-1", | |
| None, | |
| "us-central1-f", | |
| ex_disks_gce_struct=gce_disk_struct, | |
| ) | |
| num_disks = len(node_gstruct.extra["disks"]) | |
| display(" Node %s created with %d disks" % (node_gstruct.name, num_disks)) | |
| display("Creating Node with auto-created SSD:") | |
| name = "%s-np-node" % DEMO_BASE_NAME | |
| node_1 = gce.create_node( | |
| name, | |
| "n1-standard-1", | |
| "debian-7", | |
| ex_tags=["libcloud"], | |
| ex_disk_type="pd-ssd", | |
| ex_disk_auto_delete=False, | |
| ) | |
| display(" Node %s created" % name) | |
| # Stop the node and change to a custom machine type (e.g. size) | |
| display("Stopping node, setting custom size, starting node:") | |
| name = "%s-np-node" % DEMO_BASE_NAME | |
| gce.ex_stop_node(node_1) | |
| gce.ex_set_machine_type(node_1, "custom-2-4096") # 2 vCPU, 4GB RAM | |
| gce.ex_start_node(node_1) | |
| node_1 = gce.ex_get_node(name) | |
| display(" {}: state={}, size={}".format(name, node_1.extra["status"], node_1.size)) | |
| # == Create, and attach a disk == | |
| display("Creating a new disk:") | |
| disk_name = "%s-attach-disk" % DEMO_BASE_NAME | |
| volume = gce.create_volume(10, disk_name) | |
| if gce.attach_volume(node_1, volume, ex_auto_delete=True): | |
| display(" Attached {} to {}".format(volume.name, node_1.name)) | |
| display(" Disabled auto-delete for {} on {}".format(volume.name, node_1.name)) | |
| gce.ex_set_volume_auto_delete(volume, node_1, auto_delete=False) | |
| if CLEANUP: | |
| # == Detach the disk == | |
| if gce.detach_volume(volume, ex_node=node_1): | |
| display(" Detached {} from {}".format(volume.name, node_1.name)) | |
| # == Create Snapshot == | |
| display("Creating a snapshot from existing disk:") | |
| # Create a disk to snapshot | |
| vol_name = "%s-snap-template" % DEMO_BASE_NAME | |
| image = gce.ex_get_image("debian-7") | |
| vol = gce.create_volume(None, vol_name, image=image) | |
| display("Created disk %s to shapshot:" % DEMO_BASE_NAME) | |
| # Snapshot volume | |
| snapshot = vol.snapshot("%s-snapshot" % DEMO_BASE_NAME) | |
| display(" Snapshot %s created" % snapshot.name) | |
| # == Create Node with existing disk == | |
| display("Creating Node with existing disk:") | |
| name = "%s-persist-node" % DEMO_BASE_NAME | |
| # Use objects this time instead of names | |
| # Get latest Debian 7 image | |
| image = gce.ex_get_image("debian-7") | |
| # Get Machine Size | |
| size = gce.ex_get_size("n1-standard-1") | |
| # Create Disk from Snapshot created above | |
| volume_name = "%s-boot-disk" % DEMO_BASE_NAME | |
| volume = gce.create_volume(None, volume_name, snapshot=snapshot) | |
| display(" Created %s from snapshot" % volume.name) | |
| # Create Node with Disk | |
| node_2 = gce.create_node( | |
| name, | |
| size, | |
| image, | |
| ex_tags=["libcloud"], | |
| ex_boot_disk=volume, | |
| ex_disk_auto_delete=False, | |
| ) | |
| display(" Node {} created with attached disk {}".format(node_2.name, volume.name)) | |
| # == Update Tags for Node == | |
| display("Updating Tags for %s:" % node_2.name) | |
| tags = node_2.extra["tags"] | |
| tags.append("newtag") | |
| if gce.ex_set_node_tags(node_2, tags): | |
| display(" Tags updated for %s" % node_2.name) | |
| check_node = gce.ex_get_node(node_2.name) | |
| display(" New tags: %s" % check_node.extra["tags"]) | |
| # == Setting Metadata for Node == | |
| display("Setting Metadata for %s:" % node_2.name) | |
| if gce.ex_set_node_metadata(node_2, {"foo": "bar", "baz": "foobarbaz"}): | |
| display(" Metadata updated for %s" % node_2.name) | |
| check_node = gce.ex_get_node(node_2.name) | |
| display(" New Metadata: %s" % check_node.extra["metadata"]) | |
| # == Create Multiple nodes at once == | |
| base_name = "%s-multiple-nodes" % DEMO_BASE_NAME | |
| number = MAX_NODES - 2 | |
| if number > 0: | |
| display("Creating Multiple Nodes (%s):" % number) | |
| multi_nodes = gce.ex_create_multiple_nodes( | |
| base_name, | |
| size, | |
| image, | |
| number, | |
| ex_tags=["libcloud"], | |
| ex_disk_auto_delete=True, | |
| ) | |
| for node in multi_nodes: | |
| display(" Node %s created" % node.name) | |
| # == Create a Network == | |
| display("Creating Network:") | |
| name = "%s-network" % DEMO_BASE_NAME | |
| cidr = "10.10.0.0/16" | |
| network_1 = gce.ex_create_network(name, cidr) | |
| display(" Network %s created" % network_1.name) | |
| # == Create a Firewall == | |
| display("Creating a Firewall:") | |
| name = "%s-firewall" % DEMO_BASE_NAME | |
| allowed = [{"IPProtocol": "tcp", "ports": ["3141"]}] | |
| firewall_1 = gce.ex_create_firewall(name, allowed, network=network_1, source_tags=["libcloud"]) | |
| display(" Firewall %s created" % firewall_1.name) | |
| # == Create a Static Address == | |
| display("Creating an Address:") | |
| name = "%s-address" % DEMO_BASE_NAME | |
| address_1 = gce.ex_create_address(name) | |
| display(" Address {} created with IP {}".format(address_1.name, address_1.address)) | |
| # == List Updated Resources in current zone/region == | |
| display("Updated Resources in current zone/region") | |
| nodes = gce.list_nodes() | |
| display("Nodes:", nodes) | |
| addresses = gce.ex_list_addresses() | |
| display("Addresses:", addresses) | |
| firewalls = gce.ex_list_firewalls() | |
| display("Firewalls:", firewalls) | |
| subnetworks = gce.ex_list_subnetworks() | |
| display("Subnetworks:", subnetworks) | |
| networks = gce.ex_list_networks() | |
| display("Networks:", networks) | |
| snapshots = gce.ex_list_snapshots() | |
| display("Snapshots:", snapshots) | |
| if CLEANUP: | |
| display("Cleaning up %s resources created" % DEMO_BASE_NAME) | |
| clean_up(gce, DEMO_BASE_NAME, None, subnetworks) | |
| clean_up(gce, DEMO_BASE_NAME, nodes, addresses + firewalls + snapshots + networks) | |
| volumes = gce.list_volumes() | |
| clean_up(gce, DEMO_BASE_NAME, None, volumes) | |
| end_time = datetime.datetime.now() | |
| display("Total runtime: %s" % str(end_time - start_time)) | |
| # ==== LOAD BALANCER CODE STARTS HERE ==== | |
| def main_load_balancer(): | |
| start_time = datetime.datetime.now() | |
| display("Load-balancer demo/test start time: %s" % str(start_time)) | |
| gce = get_gce_driver() | |
| gcelb = get_gcelb_driver(gce) | |
| # Get project info and print name | |
| project = gce.ex_get_project() | |
| display("Project: %s" % project.name) | |
| # Existing Balancers | |
| balancers = gcelb.list_balancers() | |
| display("Load Balancers", balancers) | |
| # Protocols | |
| protocols = gcelb.list_protocols() | |
| display("Protocols", protocols) | |
| # Healthchecks | |
| healthchecks = gcelb.ex_list_healthchecks() | |
| display("Health Checks", healthchecks) | |
| # This demo is based on the GCE Load Balancing Quickstart described here: | |
| # https://developers.google.com/compute/docs/load-balancing/lb-quickstart | |
| # == Clean-up and existing demo resources == | |
| all_nodes = gce.list_nodes(ex_zone="all") | |
| firewalls = gce.ex_list_firewalls() | |
| display('Cleaning up any "%s" resources' % DEMO_BASE_NAME) | |
| clean_up(gce, DEMO_BASE_NAME, all_nodes, balancers + healthchecks + firewalls) | |
| # == Create 3 nodes to balance between == | |
| startup_script = ( | |
| "apt-get -y update && " "apt-get -y install apache2 && " "hostname > /var/www/index.html" | |
| ) | |
| tag = "%s-www" % DEMO_BASE_NAME | |
| base_name = "%s-www" % DEMO_BASE_NAME | |
| image = gce.ex_get_image("debian-7") | |
| size = gce.ex_get_size("n1-standard-1") | |
| number = 3 | |
| display("Creating %d nodes" % number) | |
| metadata = {"items": [{"key": "startup-script", "value": startup_script}]} | |
| lb_nodes = gce.ex_create_multiple_nodes( | |
| base_name, | |
| size, | |
| image, | |
| number, | |
| ex_tags=[tag], | |
| ex_metadata=metadata, | |
| ex_disk_auto_delete=True, | |
| ignore_errors=False, | |
| ) | |
| display("Created Nodes", lb_nodes) | |
| # == Create a Firewall for instances == | |
| display("Creating a Firewall") | |
| name = "%s-firewall" % DEMO_BASE_NAME | |
| allowed = [{"IPProtocol": "tcp", "ports": ["80"]}] | |
| firewall = gce.ex_create_firewall(name, allowed, target_tags=[tag]) | |
| display(" Firewall %s created" % firewall.name) | |
| # == Create a Health Check == | |
| display("Creating a HealthCheck") | |
| name = "%s-healthcheck" % DEMO_BASE_NAME | |
| # These are all the default values, but listed here as an example. To | |
| # create a healthcheck with the defaults, only name is required. | |
| hc = gcelb.ex_create_healthcheck( | |
| name, | |
| host=None, | |
| path="/", | |
| port="80", | |
| interval=5, | |
| timeout=5, | |
| unhealthy_threshold=2, | |
| healthy_threshold=2, | |
| ) | |
| display("Healthcheck %s created" % hc.name) | |
| # == Create Load Balancer == | |
| display("Creating Load Balancer") | |
| name = "%s-lb" % DEMO_BASE_NAME | |
| port = 80 | |
| protocol = "tcp" | |
| algorithm = None | |
| members = lb_nodes[:2] # Only attach the first two initially | |
| healthchecks = [hc] | |
| balancer = gcelb.create_balancer( | |
| name, port, protocol, algorithm, members, ex_healthchecks=healthchecks | |
| ) | |
| display(" Load Balancer %s created" % balancer.name) | |
| # == Attach third Node == | |
| display("Attaching additional node to Load Balancer") | |
| member = balancer.attach_compute_node(lb_nodes[2]) | |
| display(" Attached {} to {}".format(member.id, balancer.name)) | |
| # == Show Balancer Members == | |
| members = balancer.list_members() | |
| display("Load Balancer Members") | |
| for member in members: | |
| display(" ID: {} IP: {}".format(member.id, member.ip)) | |
| # == Remove a Member == | |
| display("Removing a Member") | |
| detached = members[0] | |
| detach = balancer.detach_member(detached) | |
| if detach: | |
| display(" Member {} detached from {}".format(detached.id, balancer.name)) | |
| # == Show Updated Balancer Members == | |
| members = balancer.list_members() | |
| display("Updated Load Balancer Members") | |
| for member in members: | |
| display(" ID: {} IP: {}".format(member.id, member.ip)) | |
| # == Reattach Member == | |
| display("Reattaching Member") | |
| member = balancer.attach_member(detached) | |
| display(" Member {} attached to {}".format(member.id, balancer.name)) | |
| # == Test Load Balancer by connecting to it multiple times == | |
| PAUSE = 60 | |
| display("Sleeping for %d seconds for LB members to serve..." % PAUSE) | |
| time.sleep(PAUSE) | |
| rounds = 200 | |
| url = "http://%s/" % balancer.ip | |
| line_length = 75 | |
| display("Connecting to {} {} times".format(url, rounds)) | |
| for x in range(rounds): | |
| response = url_req.urlopen(url) | |
| output = str(response.read(), encoding="utf-8").strip() | |
| if "www-001" in output: | |
| padded_output = output.center(line_length) | |
| elif "www-002" in output: | |
| padded_output = output.rjust(line_length) | |
| else: | |
| padded_output = output.ljust(line_length) | |
| sys.stdout.write("\r%s" % padded_output) | |
| sys.stdout.flush() | |
| time.sleep(0.25) | |
| print("") | |
| if CLEANUP: | |
| balancers = gcelb.list_balancers() | |
| healthchecks = gcelb.ex_list_healthchecks() | |
| nodes = gce.list_nodes(ex_zone="all") | |
| firewalls = gce.ex_list_firewalls() | |
| display("Cleaning up %s resources created" % DEMO_BASE_NAME) | |
| clean_up(gce, DEMO_BASE_NAME, nodes, balancers + healthchecks + firewalls) | |
| end_time = datetime.datetime.now() | |
| display("Total runtime: %s" % str(end_time - start_time)) | |
| # ==== BACKEND SERVICE LOAD BALANCER CODE STARTS HERE ==== | |
| def main_backend_service(): | |
| start_time = datetime.datetime.now() | |
| display("Backend Service w/Global Forwarding Rule demo/test start time: %s" % str(start_time)) | |
| gce = get_gce_driver() | |
| # Get project info and print name | |
| project = gce.ex_get_project() | |
| display("Project: %s" % project.name) | |
| # Based on the instructions at: | |
| # https://cloud.google.com/compute/docs/load-balancing/http/#overview | |
| zone_central = DATACENTER | |
| zone_east = BACKUP_DATACENTER | |
| it_name = "%s-instancetemplate" % DEMO_BASE_NAME | |
| mig_name = "%s-mig" % DEMO_BASE_NAME | |
| hc_name = "%s-healthcheck" % DEMO_BASE_NAME | |
| bes_name = "%s-bes" % DEMO_BASE_NAME | |
| urlmap_name = "%s-urlmap" % DEMO_BASE_NAME | |
| targethttpproxy_name = "%s-httptargetproxy" % DEMO_BASE_NAME | |
| address_name = "%s-address" % DEMO_BASE_NAME | |
| gfr_name = "%s-gfr" % DEMO_BASE_NAME | |
| firewall_name = "%s-firewall" % DEMO_BASE_NAME | |
| startup_script = ( | |
| "apt-get -y update && " | |
| "apt-get -y install apache2 && " | |
| 'echo "$(hostname)" > /var/www/html/index.html' | |
| ) | |
| tag = "%s-mig-www" % DEMO_BASE_NAME | |
| metadata = {"items": [{"key": "startup-script", "value": startup_script}]} | |
| mig_central = None | |
| mig_east = None | |
| bes = None | |
| urlmap = None | |
| tp = None | |
| address = None | |
| gfr = None | |
| firewall = None | |
| display("Create a BackendService") | |
| # == Create an Instance Template == | |
| it = gce.ex_create_instancetemplate( | |
| it_name, | |
| size="n1-standard-1", | |
| image="debian-8", | |
| network="default", | |
| metadata=metadata, | |
| tags=[tag], | |
| ) | |
| display(' InstanceTemplate "%s" created' % it.name) | |
| # == Create a MIG == | |
| mig_central = create_mig(gce, mig_name, zone_central, it, "central") | |
| mig_east = create_mig(gce, mig_name, zone_east, it, "east") | |
| # == Create a Health Check == | |
| hc = gce.ex_create_healthcheck( | |
| hc_name, | |
| host=None, | |
| path="/", | |
| port="80", | |
| interval=30, | |
| timeout=10, | |
| unhealthy_threshold=10, | |
| healthy_threshold=1, | |
| ) | |
| display(" Healthcheck %s created" % hc.name) | |
| # == Create a Backend Service == | |
| be_central = gce.ex_create_backend(instance_group=mig_central.instance_group) | |
| be_east = gce.ex_create_backend(instance_group=mig_east.instance_group) | |
| bes = gce.ex_create_backendservice( | |
| bes_name, | |
| [hc], | |
| backends=[be_central, be_east], | |
| port_name="%s-http" % DEMO_BASE_NAME, | |
| protocol="HTTP", | |
| description="%s bes desc" % DEMO_BASE_NAME, | |
| timeout_sec=60, | |
| enable_cdn=False, | |
| ) | |
| display(' Backend Service "%s" created' % bes.name) | |
| # == Create a URLMap == | |
| urlmap = gce.ex_create_urlmap(urlmap_name, default_service=bes) | |
| display(' URLMap "%s" created' % urlmap.name) | |
| # == Create a Target (HTTP) Proxy == | |
| tp = gce.ex_create_targethttpproxy(targethttpproxy_name, urlmap) | |
| display(' TargetProxy "%s" created' % tp.name) | |
| # == Create a Static Address == | |
| address = gce.ex_create_address(address_name, region="global") | |
| display(' Address "{}" created with IP "{}"'.format(address.name, address.address)) | |
| # == Create a Global Forwarding Rule == | |
| gfr = gce.ex_create_forwarding_rule( | |
| gfr_name, | |
| target=tp, | |
| address=address, | |
| port_range="80", | |
| description="%s libcloud forwarding rule http test" % DEMO_BASE_NAME, | |
| global_rule=True, | |
| ) | |
| display(' Global Forwarding Rule "%s" created' % (gfr.name)) | |
| # == Create a Firewall for instances == | |
| allowed = [{"IPProtocol": "tcp", "ports": ["80"]}] | |
| firewall = gce.ex_create_firewall(firewall_name, allowed, target_tags=[tag]) | |
| display(" Firewall %s created" % firewall.name) | |
| # TODO(supertom): launch instances to demostrate that it works | |
| # take backends out of service. Adding in this functionality | |
| # will also add 10-15 minutes to the demo. | |
| # display("Sleeping for 10 minutes, starting at %s" % | |
| # str(datetime.datetime.now())) | |
| # time.sleep(600) | |
| if CLEANUP: | |
| display("Cleaning up %s resources created" % DEMO_BASE_NAME) | |
| clean_up( | |
| gce, | |
| DEMO_BASE_NAME, | |
| None, | |
| resource_list=[ | |
| firewall, | |
| gfr, | |
| address, | |
| tp, | |
| urlmap, | |
| bes, | |
| hc, | |
| mig_central, | |
| mig_east, | |
| it, | |
| ], | |
| ) | |
| end_time = datetime.datetime.now() | |
| display("Total runtime: %s" % str(end_time - start_time)) | |
| # ==== GOOGLE DNS CODE STARTS HERE ==== | |
| def main_dns(): | |
| start_time = datetime.datetime.now() | |
| display("DNS demo/test start time: %s" % str(start_time)) | |
| gce = get_gce_driver() | |
| gdns = get_dns_driver() | |
| # Get project info and print name | |
| project = gce.ex_get_project() | |
| display("Project: %s" % project.name) | |
| # Get list of managed zones | |
| zones = gdns.iterate_zones() | |
| display("Zones", zones) | |
| # Get list of records | |
| zones = gdns.iterate_zones() | |
| for z in zones: | |
| records = gdns.iterate_records(z) | |
| display('Records for managed zone "%s"' % z.id, records) | |
| # TODO(erjohnso): Finish this DNS section. Challenging in that you need to | |
| # own a domain, so testing will require user customization. Perhaps a new | |
| # command-line required flag unless --skip-dns is supplied. Also, real | |
| # e2e testing should try to do DNS lookups on new records, but DNS TTL | |
| # and propagation delays will introduce limits on what can be tested. | |
| end_time = datetime.datetime.now() | |
| display("Total runtime: %s" % str(end_time - start_time)) | |
| if __name__ == "__main__": | |
| parser = argparse.ArgumentParser(description="Google Cloud Platform Demo / Live Test Script") | |
| parser.add_argument( | |
| "--compute", | |
| help="perform compute demo / live tests", | |
| dest="compute", | |
| action="store_true", | |
| ) | |
| parser.add_argument( | |
| "--load-balancer", | |
| help="perform load-balancer demo / live tests", | |
| dest="lb", | |
| action="store_true", | |
| ) | |
| parser.add_argument( | |
| "--backend-service", | |
| help="perform backend-service demo / live tests", | |
| dest="bes", | |
| action="store_true", | |
| ) | |
| parser.add_argument( | |
| "--dns", help="perform DNS demo / live tests", dest="dns", action="store_true" | |
| ) | |
| parser.add_argument( | |
| "--cleanup-only", | |
| help="perform clean-up (skips all tests)", | |
| dest="cleanup", | |
| action="store_true", | |
| ) | |
| cl_args = parser.parse_args() | |
| if cl_args.cleanup: | |
| cleanup_only() | |
| else: | |
| if cl_args.compute: | |
| main_compute() | |
| if cl_args.lb: | |
| main_load_balancer() | |
| if cl_args.dns: | |
| main_dns() | |
| if cl_args.bes: | |
| main_backend_service() |