| #!/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() |