From 32465669cf2c0c9b46054f15c3b767b584137ba2 Mon Sep 17 00:00:00 2001 From: Eric Johnson Date: Tue, 3 May 2016 17:23:35 +0000 Subject: [PATCH] [google compute] Add support for Subnetworks Signed-off-by: Eric Johnson --- CHANGES.rst | 4 + demos/gce_demo.py | 82 ++++- libcloud/compute/drivers/gce.py | 292 +++++++++++++++++- .../fixtures/gce/aggregated_subnetworks.json | 66 ++++ .../compute/fixtures/gce/global_networks.json | 75 +++-- .../fixtures/gce/global_networks_cf.json | 14 + ..._regions_us-central1_subnetworks_post.json | 15 + .../fixtures/gce/regions_asia-east1.json | 65 ++++ .../fixtures/gce/regions_europe-west1.json | 64 ++++ .../fixtures/gce/regions_us-central1.json | 65 ++++ .../gce/regions_us-central1_subnetworks.json | 18 ++ ...tral1_subnetworks_cf_972cf02e6ad49112.json | 11 + .../regions_us-central1_subnetworks_post.json | 14 + .../fixtures/gce/regions_us-east1.json | 64 ++++ .../fixtures/gce/zones_asia-east1-b.json | 10 + .../fixtures/gce/zones_us-east1-b.json | 10 + libcloud/test/compute/test_gce.py | 132 +++++++- 17 files changed, 954 insertions(+), 47 deletions(-) create mode 100644 libcloud/test/compute/fixtures/gce/aggregated_subnetworks.json create mode 100644 libcloud/test/compute/fixtures/gce/global_networks_cf.json create mode 100644 libcloud/test/compute/fixtures/gce/operations_operation_regions_us-central1_subnetworks_post.json create mode 100644 libcloud/test/compute/fixtures/gce/regions_asia-east1.json create mode 100644 libcloud/test/compute/fixtures/gce/regions_europe-west1.json create mode 100644 libcloud/test/compute/fixtures/gce/regions_us-central1.json create mode 100644 libcloud/test/compute/fixtures/gce/regions_us-central1_subnetworks.json create mode 100644 libcloud/test/compute/fixtures/gce/regions_us-central1_subnetworks_cf_972cf02e6ad49112.json create mode 100644 libcloud/test/compute/fixtures/gce/regions_us-central1_subnetworks_post.json create mode 100644 libcloud/test/compute/fixtures/gce/regions_us-east1.json create mode 100644 libcloud/test/compute/fixtures/gce/zones_asia-east1-b.json create mode 100644 libcloud/test/compute/fixtures/gce/zones_us-east1-b.json diff --git a/CHANGES.rst b/CHANGES.rst index 55e914aaac..3d6ebc8b47 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -24,6 +24,10 @@ General Compute ~~~~~~~ +- Add Subnetworks to GCE driver + (GITHUB-780) + [Eric Johnson] + - Fix missing pricing data for GCE (LIBCLOUD-713, GITHUB-779) [Eric Johnson] diff --git a/demos/gce_demo.py b/demos/gce_demo.py index 03201d94aa..696ebaedda 100755 --- a/demos/gce_demo.py +++ b/demos/gce_demo.py @@ -270,7 +270,6 @@ def clean_up(gce, base_name, node_list=None, resource_list=None): raise -# ==== COMPUTE CODE STARTS HERE ==== def main_compute(): start_time = datetime.datetime.now() display('Compute demo/test start time: %s' % str(start_time)) @@ -300,6 +299,9 @@ def main_compute(): firewalls = gce.ex_list_firewalls() display('Firewalls:', firewalls) + subnetworks = gce.ex_list_subnetworks() + display('Subnetworks:', subnetworks) + networks = gce.ex_list_networks() display('Networks:', networks) @@ -317,8 +319,78 @@ def main_compute(): # == 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 + networks + snapshots) + 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) + + # == 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: @@ -480,6 +552,9 @@ def main_compute(): firewalls = gce.ex_list_firewalls() display('Firewalls:', firewalls) + subnetworks = gce.ex_list_subnetworks() + display('Subnetworks:', subnetworks) + networks = gce.ex_list_networks() display('Networks:', networks) @@ -488,8 +563,9 @@ def main_compute(): 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 + networks + snapshots) + addresses + firewalls + snapshots + networks) volumes = gce.list_volumes() clean_up(gce, DEMO_BASE_NAME, None, volumes) end_time = datetime.datetime.now() diff --git a/libcloud/compute/drivers/gce.py b/libcloud/compute/drivers/gce.py index 371e91d49a..45a2ce30ab 100644 --- a/libcloud/compute/drivers/gce.py +++ b/libcloud/compute/drivers/gce.py @@ -519,6 +519,33 @@ def deprecate(self, replacement, state, deprecated=None, obsolete=None, deprecated, obsolete, deleted) +class GCESubnetwork(UuidMixin): + """A GCE Subnetwork object class.""" + def __init__(self, id, name, cidr, network, region, driver, extra=None): + self.id = str(id) + self.name = name + self.cidr = cidr + self.network = network + self.region = region + self.driver = driver + self.extra = extra + UuidMixin.__init__(self) + + def destroy(self): + """ + Destroy this subnetwork + + :return: True if successful + :rtype: ``bool`` + """ + return self.driver.ex_destroy_subnetwork(self) + + def __repr__(self): + return '' % (self.id, self.name, self.region.name, + self.network.name, self.cidr) + + class GCENetwork(UuidMixin): """A GCE Network object class.""" def __init__(self, id, name, cidr, driver, extra=None): @@ -527,6 +554,11 @@ def __init__(self, id, name, cidr, driver, extra=None): self.cidr = cidr self.driver = driver self.extra = extra + self.mode = 'legacy' + self.subnetworks = [] + if 'mode' in extra and extra['mode'] != 'legacy': + self.mode = extra['mode'] + self.subnetworks = extra['subnetworks'] UuidMixin.__init__(self) def destroy(self): @@ -539,8 +571,8 @@ def destroy(self): return self.driver.ex_destroy_network(network=self) def __repr__(self): - return '' % ( - self.id, self.name, self.cidr) + return '' % ( + self.id, self.name, self.cidr, self.mode) class GCERoute(UuidMixin): @@ -1587,6 +1619,43 @@ def ex_list_routes(self): response.get('items', [])] return list_routes + def ex_list_subnetworks(self, region=None): + """ + Return the list of subnetworks. + + :keyword region: Region for the subnetwork. Specify 'all' to return + the aggregated list of subnetworks. + :type region: ``str`` or :class:`GCERegion` + + :return: A list of subnetwork objects. + :rtype: ``list`` of :class:`GCESubNetwork` + """ + region = self._set_region(region) + if region is None: + request = '/aggregated/subnetworks' + else: + request = '/regions/%s/subnetworks' % (region.name) + + list_subnetworks = [] + response = self.connection.request(request, method='GET').object + + if 'items' in response: + if region is None: + for v in response['items'].values(): + for i in v.get('subnetworks', []): + try: + list_subnetworks.append(self._to_subnetwork(i)) + except ResourceNotFoundError: + pass + else: + for i in response['items']: + try: + list_subnetworks.append(self._to_subnetwork(i)) + except ResourceNotFoundError: + pass + + return list_subnetworks + def ex_list_networks(self): """ Return the list of networks. @@ -2252,29 +2321,112 @@ def ex_create_route(self, name, dest_range, priority=500, return self.ex_get_route(name) - def ex_create_network(self, name, cidr, description=None): + def ex_create_subnetwork(self, name, cidr=None, network=None, region=None, + description=None): """ - Create a network. + Create a subnetwork. - :param name: Name of network to be created + :param name: Name of subnetwork to be created :type name: ``str`` :param cidr: Address range of network in CIDR format. :type cidr: ``str`` + :param network: The network name or object this subnet belongs to. + :type network: ``str`` or :class:`GCENetwork` + + :param region: The region the subnetwork belongs to. + :type region: ``str`` or :class:`GCERegion` + :param description: Custom description for the network. :type description: ``str`` or ``None`` + :return: Subnetwork object + :rtype: :class:`GCESubnetwork` + """ + if not cidr: + raise ValueError("Must provide an IP network in CIDR notation.") + + if not network: + raise ValueError("Must provide a network for the subnetwork.") + else: + if isinstance(network, GCENetwork): + network_url = network.extra['selfLink'] + else: + if network.startswith('https://'): + network_url = network + else: + network_obj = self.ex_get_network(network) + network_url = network_obj.extra['selfLink'] + + if not region: + raise ValueError("Must provide a region for the subnetwork.") + else: + if isinstance(region, GCERegion): + region_url = region.extra['selfLink'] + else: + if region.startswith('https://'): + region_url = region + else: + region_obj = self.ex_get_region(region) + region_url = region_obj.extra['selfLink'] + + subnet_data = {} + subnet_data['name'] = name + subnet_data['description'] = description + subnet_data['ipCidrRange'] = cidr + subnet_data['network'] = network_url + subnet_data['region'] = region_url + region_name = region_url.split('/')[-1] + + request = '/regions/%s/subnetworks' % (region_name) + self.connection.async_request(request, method='POST', + data=subnet_data) + + return self.ex_get_subnetwork(name, region_name) + + def ex_create_network(self, name, cidr, description=None, mode="legacy"): + """ + Create a network. In November 2015, Google introduced Subnetworks and + suggests using networks with 'auto' generated subnetworks. See, the + `subnet docs `_ for + more details. Note that libcloud follows the usability pattern from + the Cloud SDK (e.g. 'gcloud compute' command-line utility) and uses + 'mode' to specify 'auto', 'custom', or 'legacy'. + + :param name: Name of network to be created + :type name: ``str`` + + :param cidr: Address range of network in CIDR format. + :type cidr: ``str`` or ``None`` + + :param description: Custom description for the network. + :type description: ``str`` or ``None`` + + :param mode: Create a 'auto', 'custom', or 'legacy' network. + :type mode: ``str`` + :return: Network object :rtype: :class:`GCENetwork` """ network_data = {} network_data['name'] = name - network_data['IPv4Range'] = cidr network_data['description'] = description + if mode.lower() not in ['auto', 'custom', 'legacy']: + raise ValueError("Invalid network mode: '%s'. Must be 'auto', " + "'custom', or 'legacy'." % mode) + if cidr and mode in ['auto', 'custom']: + raise ValueError("Can only specify IPv4Range with 'legacy' mode.") request = '/global/networks' + if mode == 'legacy': + if not cidr: + raise ValueError("Must specify IPv4Range with 'legacy' mode.") + network_data['IPv4Range'] = cidr + else: + network_data['autoCreateSubnetworks'] = (mode.lower() == 'auto') + self.connection.async_request(request, method='POST', data=network_data) @@ -4254,6 +4406,91 @@ def ex_get_route(self, name): response = self.connection.request(request, method='GET').object return self._to_route(response) + def ex_destroy_subnetwork(self, name, region=None): + """ + Delete a Subnetwork object based on name and region. + + :param name: The name, URL or object of the subnetwork + :type name: ``str`` or :class:`GCESubnetwork` + + :param name: The region object, name, or URL of the subnetwork + :type name: ``str`` or :class:`GCERegion` or ``None`` + + :return: True if successful + :rtype: ``bool`` + """ + region_name = None + subnet_name = None + if region: + if isinstance(region, GCERegion): + region_name = region.name + else: + if region.startswith('https://'): + region_name = region.split('/')[-1] + else: + region_name = region + if isinstance(name, GCESubnetwork): + subnet_name = name.name + if not region_name: + region_name = name.region.name + else: + if name.startswith('https://'): + url_parts = self._get_components_from_path(name) + subnet_name = url_parts['name'] + if not region_name: + region_name = url_parts['region'] + else: + subnet_name = name + + if not region_name: + region = self._set_region(region) + if not region: + raise ("Could not determine region for subnetwork.") + else: + region_name = region.name + + request = '/regions/%s/subnetworks/%s' % (region_name, subnet_name) + self.connection.request(request, method='DELETE').object + return True + + def ex_get_subnetwork(self, name, region=None): + """ + Return a Subnetwork object based on name and region. + + :param name: The name or URL of the subnetwork + :type name: ``str`` + + :param name: The region of the subnetwork + :type name: ``str`` or :class:`GCERegion` or ``None`` + + :return: A Subnetwork object + :rtype: :class:`GCESubnetwork` + """ + region_name = None + if name.startswith('https://'): + parts = self._get_components_from_path(name) + name = parts['name'] + region_name = parts['region'] + else: + if isinstance(region, GCERegion): + region_name = region.name + elif isinstance(region, str): + if region.startswith('https://'): + region_name = region.split('/')[-1] + else: + region_name = region + + if not region_name: + region = self._set_region(region) + if not region: + raise ("Could not determine region for subnetwork.") + else: + region_name = region.name + + request = '/regions/%s/subnetworks/%s' % (region_name, name) + response = self.connection.request(request, method='GET').object + return self._to_subnetwork(response) + def ex_get_network(self, name): """ Return a Network object based on a network name. @@ -5336,6 +5573,33 @@ def _to_forwarding_rule(self, forwarding_rule): protocol=forwarding_rule.get('IPProtocol'), targetpool=target, driver=self, extra=extra) + def _to_subnetwork(self, subnetwork): + """ + Return a Subnetwork object from the JSON-response dictionary. + + :param subnetwork: The dictionary describing the subnetwork. + :type subnetwork: ``dict`` + + :return: Subnetwork object + :rtype: :class:`GCESubnetwork` + """ + extra = {} + + extra['creationTimestamp'] = subnetwork.get('creationTimestamp') + extra['description'] = subnetwork.get('description') + extra['gatewayAddress'] = subnetwork.get('gatewayAddress') + extra['ipCidrRange'] = subnetwork.get('ipCidrRange') + extra['network'] = subnetwork.get('network') + extra['region'] = subnetwork.get('region') + extra['selfLink'] = subnetwork.get('selfLink') + network = self._get_object_by_kind(subnetwork.get('network')) + region = self._get_object_by_kind(subnetwork.get('region')) + + return GCESubnetwork(id=subnetwork['id'], name=subnetwork['name'], + cidr=subnetwork.get('ipCidrRange'), + network=network, region=region, + driver=self, extra=extra) + def _to_network(self, network): """ Return a Network object from the JSON-response dictionary. @@ -5349,9 +5613,23 @@ def _to_network(self, network): extra = {} extra['selfLink'] = network.get('selfLink') - extra['gatewayIPv4'] = network.get('gatewayIPv4') extra['description'] = network.get('description') extra['creationTimestamp'] = network.get('creationTimestamp') + # 'legacy' + extra['gatewayIPv4'] = network.get('gatewayIPv4') + extra['IPv4Range'] = network.get('IPv4Range') + # 'auto' or 'custom' + extra['autoCreateSubnetworks'] = network.get('autoCreateSubnetworks') + extra['subnetworks'] = network.get('subnetworks') + + # match Cloud SDK 'gcloud' + if 'autoCreateSubnetworks' in network: + if network['autoCreateSubnetworks']: + extra['mode'] = 'auto' + else: + extra['mode'] = 'custom' + else: + extra['mode'] = 'legacy' return GCENetwork(id=network['id'], name=network['name'], cidr=network.get('IPv4Range'), diff --git a/libcloud/test/compute/fixtures/gce/aggregated_subnetworks.json b/libcloud/test/compute/fixtures/gce/aggregated_subnetworks.json new file mode 100644 index 0000000000..6b4adb60da --- /dev/null +++ b/libcloud/test/compute/fixtures/gce/aggregated_subnetworks.json @@ -0,0 +1,66 @@ +{ + "kind": "compute#subnetworkAggregatedList", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/aggregated/subnetworks", + "items": { + "regions/us-central1": { + "subnetworks": [ + { + "kind": "compute#subnetwork", + "id": "4297043163355844284", + "creationTimestamp": "2016-03-25T05:34:27.209-07:00", + "gatewayAddress": "10.128.0.1", + "name": "cf-972cf02e6ad49112", + "network": "https://www.googleapis.com/compute/v1/projects/project_name/global/networks/cf", + "ipCidrRange": "10.128.0.0/20", + "region": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1/subnetworks/cf-972cf02e6ad49112" + } + ] + }, + "regions/europe-west1": { + "subnetworks": [ + { + "kind": "compute#subnetwork", + "id": "447043451408125628", + "creationTimestamp": "2016-03-25T05:34:27.272-07:00", + "gatewayAddress": "10.132.0.1", + "name": "cf-df1837b06a6f927b", + "network": "https://www.googleapis.com/compute/v1/projects/project_name/global/networks/cf", + "ipCidrRange": "10.132.0.0/20", + "region": "https://www.googleapis.com/compute/v1/projects/project_name/regions/europe-west1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/regions/europe-west1/subnetworks/cf-df1837b06a6f927b" + } + ] + }, + "regions/asia-east1": { + "subnetworks": [ + { + "kind": "compute#subnetwork", + "id": "1240429769038270140", + "creationTimestamp": "2016-03-25T05:34:27.413-07:00", + "gatewayAddress": "10.140.0.1", + "name": "cf-4c2da366a0381eb9", + "network": "https://www.googleapis.com/compute/v1/projects/project_name/global/networks/cf", + "ipCidrRange": "10.140.0.0/20", + "region": "https://www.googleapis.com/compute/v1/projects/project_name/regions/asia-east1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/regions/asia-east1/subnetworks/cf-4c2da366a0381eb9" + } + ] + }, + "regions/us-east1": { + "subnetworks": [ + { + "kind": "compute#subnetwork", + "id": "648244394139881148", + "creationTimestamp": "2016-03-25T05:34:27.475-07:00", + "gatewayAddress": "10.142.0.1", + "name": "cf-daf1e2124a902a47", + "network": "https://www.googleapis.com/compute/v1/projects/project_name/global/networks/cf", + "ipCidrRange": "10.142.0.0/20", + "region": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-east1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-east1/subnetworks/cf-daf1e2124a902a47" + } + ] + } + } +} diff --git a/libcloud/test/compute/fixtures/gce/global_networks.json b/libcloud/test/compute/fixtures/gce/global_networks.json index dc7ca55d26..1e041f42c5 100644 --- a/libcloud/test/compute/fixtures/gce/global_networks.json +++ b/libcloud/test/compute/fixtures/gce/global_networks.json @@ -1,34 +1,43 @@ { - "id": "projects/project_name/global/networks", - "items": [ - { - "IPv4Range": "10.240.0.0/16", - "creationTimestamp": "2013-06-19T12:37:13.233-07:00", - "gatewayIPv4": "10.240.0.1", - "id": "08257021638942464470", - "kind": "compute#network", - "name": "default", - "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/networks/default" - }, - { - "IPv4Range": "10.10.0.0/16", - "creationTimestamp": "2013-06-26T09:51:34.018-07:00", - "gatewayIPv4": "10.10.0.1", - "id": "13254259054875092094", - "kind": "compute#network", - "name": "libcloud-demo-europe-network", - "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/networks/libcloud-demo-europe-network" - }, - { - "IPv4Range": "10.10.0.0/16", - "creationTimestamp": "2013-06-26T09:48:15.703-07:00", - "gatewayIPv4": "10.10.0.1", - "id": "17172579178188075621", - "kind": "compute#network", - "name": "libcloud-demo-network", - "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/networks/libcloud-demo-network" - } - ], - "kind": "compute#networkList", - "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/networks" -} \ No newline at end of file + "kind": "compute#networkList", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/networks", + "id": "projects/project_name/global/networks", + "items": [ + { + "kind": "compute#network", + "id": "5125152985904090792", + "creationTimestamp": "2016-03-25T05:34:15.077-07:00", + "name": "cf", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/networks/cf", + "autoCreateSubnetworks": true, + "subnetworks": [ + "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1/subnetworks/cf-972cf02e6ad49112", + "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-east1/subnetworks/cf-daf1e2124a902a47", + "https://www.googleapis.com/compute/v1/projects/project_name/regions/asia-east1/subnetworks/cf-4c2da366a0381eb9", + "https://www.googleapis.com/compute/v1/projects/project_name/regions/europe-west1/subnetworks/cf-df1837b06a6f927b" + ] + }, + { + "kind": "compute#network", + "id": "7887441312352916157", + "creationTimestamp": "2016-04-30T10:33:06.252-07:00", + "name": "custom", + "description": "Custom network", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/networks/custom", + "autoCreateSubnetworks": false, + "subnetworks": [ + "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1/subnetworks/subnet1" + ] + }, + { + "kind": "compute#network", + "id": "2672023774255449680", + "creationTimestamp": "2014-01-21T10:30:55.392-08:00", + "name": "default", + "description": "Default network for the project", + "IPv4Range": "10.240.0.0/16", + "gatewayIPv4": "10.240.0.1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/networks/default" + } + ] +} diff --git a/libcloud/test/compute/fixtures/gce/global_networks_cf.json b/libcloud/test/compute/fixtures/gce/global_networks_cf.json new file mode 100644 index 0000000000..410b4d3068 --- /dev/null +++ b/libcloud/test/compute/fixtures/gce/global_networks_cf.json @@ -0,0 +1,14 @@ +{ + "kind": "compute#network", + "id": "5125152985904090792", + "creationTimestamp": "2016-03-25T05:34:15.077-07:00", + "name": "cf", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/networks/cf", + "autoCreateSubnetworks": true, + "subnetworks": [ + "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1/subnetworks/cf-972cf02e6ad49112", + "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-east1/subnetworks/cf-daf1e2124a902a47", + "https://www.googleapis.com/compute/v1/projects/project_name/regions/asia-east1/subnetworks/cf-4c2da366a0381eb9", + "https://www.googleapis.com/compute/v1/projects/project_name/regions/europe-west1/subnetworks/cf-df1837b06a6f927b" + ] +} diff --git a/libcloud/test/compute/fixtures/gce/operations_operation_regions_us-central1_subnetworks_post.json b/libcloud/test/compute/fixtures/gce/operations_operation_regions_us-central1_subnetworks_post.json new file mode 100644 index 0000000000..f11725309f --- /dev/null +++ b/libcloud/test/compute/fixtures/gce/operations_operation_regions_us-central1_subnetworks_post.json @@ -0,0 +1,15 @@ +{ + "id": "16064059851942653139", + "insertTime": "2013-06-26T12:21:40.299-07:00", + "kind": "compute#operation", + "name": "operation-regions_us-central1_subnetworks_post", + "operationType": "insert", + "progress": 100, + "region": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1/operations/operation-regions_us-central1_subnetworks_post", + "startTime": "2013-06-26T12:21:40.358-07:00", + "status": "DONE", + "targetId": "01531551729918243104", + "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1/subnetworks/cf-972cf02e6ad49112", + "user": "897001307951@developer.gserviceaccount.com" +} diff --git a/libcloud/test/compute/fixtures/gce/regions_asia-east1.json b/libcloud/test/compute/fixtures/gce/regions_asia-east1.json new file mode 100644 index 0000000000..adc4569a6d --- /dev/null +++ b/libcloud/test/compute/fixtures/gce/regions_asia-east1.json @@ -0,0 +1,65 @@ +{ + "kind": "compute#region", + "id": "1220", + "creationTimestamp": "2014-05-30T18:35:16.514-07:00", + "name": "asia-east1", + "description": "asia-east1", + "status": "UP", + "zones": [ + "https://www.googleapis.com/compute/v1/projects/project_name/zones/asia-east1-a", + "https://www.googleapis.com/compute/v1/projects/project_name/zones/asia-east1-b" + ], + "quotas": [ + { + "metric": "CPUS", + "limit": 24.0, + "usage": 0.0 + }, + { + "metric": "DISKS_TOTAL_GB", + "limit": 10240.0, + "usage": 0.0 + }, + { + "metric": "STATIC_ADDRESSES", + "limit": 7.0, + "usage": 0.0 + }, + { + "metric": "IN_USE_ADDRESSES", + "limit": 23.0, + "usage": 0.0 + }, + { + "metric": "SSD_TOTAL_GB", + "limit": 2048.0, + "usage": 0.0 + }, + { + "metric": "LOCAL_SSD_TOTAL_GB", + "limit": 10240.0, + "usage": 0.0 + }, + { + "metric": "INSTANCE_GROUPS", + "limit": 100.0, + "usage": 0.0 + }, + { + "metric": "INSTANCE_GROUP_MANAGERS", + "limit": 50.0, + "usage": 0.0 + }, + { + "metric": "INSTANCES", + "limit": 240.0, + "usage": 0.0 + }, + { + "metric": "AUTOSCALERS", + "limit": 50.0, + "usage": 0.0 + } + ], + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/regions/asia-east1" +} diff --git a/libcloud/test/compute/fixtures/gce/regions_europe-west1.json b/libcloud/test/compute/fixtures/gce/regions_europe-west1.json new file mode 100644 index 0000000000..59d174dc6c --- /dev/null +++ b/libcloud/test/compute/fixtures/gce/regions_europe-west1.json @@ -0,0 +1,64 @@ +{ + "kind": "compute#region", + "id": "1100", + "creationTimestamp": "2014-05-30T18:35:16.413-07:00", + "name": "europe-west1", + "description": "europe-west1", + "status": "UP", + "zones": [ + "https://www.googleapis.com/compute/v1/projects/project_name/zones/europe-west1-b" + ], + "quotas": [ + { + "metric": "CPUS", + "limit": 24.0, + "usage": 0.0 + }, + { + "metric": "DISKS_TOTAL_GB", + "limit": 10240.0, + "usage": 0.0 + }, + { + "metric": "STATIC_ADDRESSES", + "limit": 7.0, + "usage": 0.0 + }, + { + "metric": "IN_USE_ADDRESSES", + "limit": 23.0, + "usage": 0.0 + }, + { + "metric": "SSD_TOTAL_GB", + "limit": 2048.0, + "usage": 0.0 + }, + { + "metric": "LOCAL_SSD_TOTAL_GB", + "limit": 10240.0, + "usage": 0.0 + }, + { + "metric": "INSTANCE_GROUPS", + "limit": 100.0, + "usage": 0.0 + }, + { + "metric": "INSTANCE_GROUP_MANAGERS", + "limit": 50.0, + "usage": 0.0 + }, + { + "metric": "INSTANCES", + "limit": 240.0, + "usage": 0.0 + }, + { + "metric": "AUTOSCALERS", + "limit": 50.0, + "usage": 0.0 + } + ], + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/regions/europe-west1" +} diff --git a/libcloud/test/compute/fixtures/gce/regions_us-central1.json b/libcloud/test/compute/fixtures/gce/regions_us-central1.json new file mode 100644 index 0000000000..a070fbce58 --- /dev/null +++ b/libcloud/test/compute/fixtures/gce/regions_us-central1.json @@ -0,0 +1,65 @@ +{ + "kind": "compute#region", + "id": "1000", + "creationTimestamp": "2014-05-30T18:35:16.413-07:00", + "name": "us-central1", + "description": "us-central1", + "status": "UP", + "zones": [ + "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a", + "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-b" + ], + "quotas": [ + { + "metric": "CPUS", + "limit": 1050.0, + "usage": 30.0 + }, + { + "metric": "DISKS_TOTAL_GB", + "limit": 20000.0, + "usage": 344.0 + }, + { + "metric": "STATIC_ADDRESSES", + "limit": 10.0, + "usage": 2.0 + }, + { + "metric": "IN_USE_ADDRESSES", + "limit": 1050.0, + "usage": 11.0 + }, + { + "metric": "SSD_TOTAL_GB", + "limit": 2048.0, + "usage": 500.0 + }, + { + "metric": "LOCAL_SSD_TOTAL_GB", + "limit": 10240.0, + "usage": 0.0 + }, + { + "metric": "INSTANCE_GROUPS", + "limit": 100.0, + "usage": 0.0 + }, + { + "metric": "INSTANCE_GROUP_MANAGERS", + "limit": 50.0, + "usage": 0.0 + }, + { + "metric": "INSTANCES", + "limit": 10500.0, + "usage": 11.0 + }, + { + "metric": "AUTOSCALERS", + "limit": 50.0, + "usage": 0.0 + } + ], + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1" +} diff --git a/libcloud/test/compute/fixtures/gce/regions_us-central1_subnetworks.json b/libcloud/test/compute/fixtures/gce/regions_us-central1_subnetworks.json new file mode 100644 index 0000000000..902ce2595d --- /dev/null +++ b/libcloud/test/compute/fixtures/gce/regions_us-central1_subnetworks.json @@ -0,0 +1,18 @@ +{ + "kind": "compute#subnetworkList", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1/subnetworks", + "id": "projects/project_name/regions/us-central1/subnetworks", + "items": [ + { + "kind": "compute#subnetwork", + "id": "4297043163355844284", + "creationTimestamp": "2016-03-25T05:34:27.209-07:00", + "gatewayAddress": "10.128.0.1", + "name": "cf-972cf02e6ad49112", + "network": "https://www.googleapis.com/compute/v1/projects/project_name/global/networks/cf", + "ipCidrRange": "10.128.0.0/20", + "region": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1/subnetworks/cf-972cf02e6ad49112" + } + ] +} diff --git a/libcloud/test/compute/fixtures/gce/regions_us-central1_subnetworks_cf_972cf02e6ad49112.json b/libcloud/test/compute/fixtures/gce/regions_us-central1_subnetworks_cf_972cf02e6ad49112.json new file mode 100644 index 0000000000..855eda56a6 --- /dev/null +++ b/libcloud/test/compute/fixtures/gce/regions_us-central1_subnetworks_cf_972cf02e6ad49112.json @@ -0,0 +1,11 @@ +{ + "kind": "compute#subnetwork", + "id": "4297043163355844284", + "creationTimestamp": "2016-03-25T05:34:27.209-07:00", + "gatewayAddress": "10.128.0.1", + "name": "cf-972cf02e6ad49112", + "network": "https://www.googleapis.com/compute/v1/projects/project_name/global/networks/cf", + "ipCidrRange": "10.128.0.0/20", + "region": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1/subnetworks/cf-972cf02e6ad49112" +} diff --git a/libcloud/test/compute/fixtures/gce/regions_us-central1_subnetworks_post.json b/libcloud/test/compute/fixtures/gce/regions_us-central1_subnetworks_post.json new file mode 100644 index 0000000000..57a540f128 --- /dev/null +++ b/libcloud/test/compute/fixtures/gce/regions_us-central1_subnetworks_post.json @@ -0,0 +1,14 @@ +{ + "id": "16064059851942653139", + "insertTime": "2013-06-26T12:21:40.299-07:00", + "kind": "compute#operation", + "name": "operation-regions_us-central1_subnetworks_post", + "operationType": "insert", + "progress": 0, + "region": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1/operations/operation-regions_us-central1_subnetworks_post", + "startTime": "2013-06-26T12:21:40.358-07:00", + "status": "PENDING", + "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-central1/subnetworks/cf-972cf02e6ad49112", + "user": "897001307951@developer.gserviceaccount.com" +} diff --git a/libcloud/test/compute/fixtures/gce/regions_us-east1.json b/libcloud/test/compute/fixtures/gce/regions_us-east1.json new file mode 100644 index 0000000000..071bb40cb1 --- /dev/null +++ b/libcloud/test/compute/fixtures/gce/regions_us-east1.json @@ -0,0 +1,64 @@ +{ + "kind": "compute#region", + "id": "1230", + "creationTimestamp": "2014-09-03T16:13:49.013-07:00", + "name": "us-east1", + "description": "us-east1", + "status": "UP", + "zones": [ + "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-east1-b" + ], + "quotas": [ + { + "metric": "CPUS", + "limit": 24.0, + "usage": 0.0 + }, + { + "metric": "DISKS_TOTAL_GB", + "limit": 10240.0, + "usage": 0.0 + }, + { + "metric": "STATIC_ADDRESSES", + "limit": 7.0, + "usage": 0.0 + }, + { + "metric": "IN_USE_ADDRESSES", + "limit": 23.0, + "usage": 0.0 + }, + { + "metric": "SSD_TOTAL_GB", + "limit": 2048.0, + "usage": 0.0 + }, + { + "metric": "LOCAL_SSD_TOTAL_GB", + "limit": 10240.0, + "usage": 0.0 + }, + { + "metric": "INSTANCE_GROUPS", + "limit": 100.0, + "usage": 0.0 + }, + { + "metric": "INSTANCE_GROUP_MANAGERS", + "limit": 50.0, + "usage": 0.0 + }, + { + "metric": "INSTANCES", + "limit": 240.0, + "usage": 0.0 + }, + { + "metric": "AUTOSCALERS", + "limit": 50.0, + "usage": 0.0 + } + ], + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-east1" +} diff --git a/libcloud/test/compute/fixtures/gce/zones_asia-east1-b.json b/libcloud/test/compute/fixtures/gce/zones_asia-east1-b.json new file mode 100644 index 0000000000..1c3ac1bff0 --- /dev/null +++ b/libcloud/test/compute/fixtures/gce/zones_asia-east1-b.json @@ -0,0 +1,10 @@ +{ + "kind": "compute#zone", + "id": "2220", + "creationTimestamp": "2014-05-30T18:35:16.575-07:00", + "name": "asia-east1-a", + "description": "asia-east1-a", + "status": "UP", + "region": "https://www.googleapis.com/compute/v1/projects/project_name/regions/asia-east1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/asia-east1-a" +} diff --git a/libcloud/test/compute/fixtures/gce/zones_us-east1-b.json b/libcloud/test/compute/fixtures/gce/zones_us-east1-b.json new file mode 100644 index 0000000000..1460ee2b17 --- /dev/null +++ b/libcloud/test/compute/fixtures/gce/zones_us-east1-b.json @@ -0,0 +1,10 @@ +{ + "kind": "compute#zone", + "id": "2231", + "creationTimestamp": "2015-09-08T16:57:06.746-07:00", + "name": "us-east1-b", + "description": "us-east1-b", + "status": "UP", + "region": "https://www.googleapis.com/compute/v1/projects/project_name/regions/us-east1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-east1-b" +} diff --git a/libcloud/test/compute/test_gce.py b/libcloud/test/compute/test_gce.py index e8024dc0ca..77e3775521 100644 --- a/libcloud/test/compute/test_gce.py +++ b/libcloud/test/compute/test_gce.py @@ -1,4 +1,4 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more +# License 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 @@ -25,9 +25,9 @@ GCEAddress, GCEBackendService, GCEFirewall, GCEForwardingRule, GCEHealthCheck, GCENetwork, - GCENodeImage, GCERoute, + GCENodeImage, GCERoute, GCERegion, GCETargetHttpProxy, GCEUrlMap, - GCEZone) + GCEZone, GCESubnetwork) from libcloud.common.google import (GoogleBaseAuthConnection, ResourceNotFoundError, ResourceExistsError, InvalidRequestError, GoogleBaseError) @@ -128,6 +128,7 @@ def test_ex_list(self): d.ex_list_forwarding_rules, d.ex_list_healthchecks, d.ex_list_networks, + d.ex_list_subnetworks, d.ex_list_project_images, d.ex_list_regions, d.ex_list_routes, @@ -233,10 +234,72 @@ def test_ex_list_routes(self): self.assertEqual(len(routes), 3) self.assertTrue('lcdemoroute' in [route.name for route in routes]) + def test_ex_list_subnetworks(self): + subnetworks = self.driver.ex_list_subnetworks() + self.assertEqual(len(subnetworks), 1) + self.assertEqual(subnetworks[0].name, 'cf-972cf02e6ad49112') + self.assertEqual(subnetworks[0].cidr, '10.128.0.0/20') + subnetworks = self.driver.ex_list_subnetworks('all') + self.assertEqual(len(subnetworks), 4) + + def test_ex_create_subnetwork(self): + name = 'cf-972cf02e6ad49112' + cidr = '10.128.0.0/20' + network_name = 'cf' + network = self.driver.ex_get_network(network_name) + region_name = 'us-central1' + region = self.driver.ex_get_region(region_name) + # test by network/region name + subnet = self.driver.ex_create_subnetwork(name, cidr, network_name, region_name) + self.assertTrue(isinstance(subnet, GCESubnetwork)) + self.assertTrue(isinstance(subnet.region, GCERegion)) + self.assertTrue(isinstance(subnet.network, GCENetwork)) + self.assertEqual(subnet.name, name) + self.assertEqual(subnet.cidr, cidr) + # test by network/region object + subnet = self.driver.ex_create_subnetwork(name, cidr, network, region) + self.assertTrue(isinstance(subnet, GCESubnetwork)) + self.assertTrue(isinstance(subnet.region, GCERegion)) + self.assertTrue(isinstance(subnet.network, GCENetwork)) + self.assertEqual(subnet.name, name) + self.assertEqual(subnet.cidr, cidr) + + def test_ex_destroy_subnetwork(self): + name = 'cf-972cf02e6ad49112' + region_name = 'us-central1' + region = self.driver.ex_get_region(region_name) + # delete with no region + self.assertTrue(self.driver.ex_destroy_subnetwork(name)) + # delete with region name + self.assertTrue(self.driver.ex_destroy_subnetwork(name, region_name)) + # delete with region object + self.assertTrue(self.driver.ex_destroy_subnetwork(name, region)) + + def test_ex_get_subnetwork(self): + name = 'cf-972cf02e6ad49112' + region_name = 'us-central1' + region = self.driver.ex_get_region(region_name) + # fetch by no region + subnetwork = self.driver.ex_get_subnetwork(name) + self.assertEqual(subnetwork.name, name) + # fetch by region name + subnetwork = self.driver.ex_get_subnetwork(name, region_name) + self.assertEqual(subnetwork.name, name) + # fetch by region object + subnetwork = self.driver.ex_get_subnetwork(name, region) + self.assertEqual(subnetwork.name, name) + def test_ex_list_networks(self): networks = self.driver.ex_list_networks() self.assertEqual(len(networks), 3) - self.assertEqual(networks[0].name, 'default') + self.assertEqual(networks[0].name, 'cf') + self.assertEqual(networks[0].mode, 'auto') + self.assertEqual(len(networks[0].subnetworks), 4) + self.assertEqual(networks[1].name, 'custom') + self.assertEqual(networks[1].mode, 'custom') + self.assertEqual(len(networks[1].subnetworks), 1) + self.assertEqual(networks[2].name, 'default') + self.assertEqual(networks[2].mode, 'legacy') def test_list_nodes(self): nodes = self.driver.list_nodes() @@ -479,6 +542,16 @@ def test_ex_create_network(self): self.assertEqual(network.name, network_name) self.assertEqual(network.cidr, cidr) + def test_ex_create_network_bad_options(self): + network_name = 'lcnetwork' + cidr = '10.11.0.0/16' + self.assertRaises(ValueError, self.driver.ex_create_network, + network_name, cidr, mode='auto') + self.assertRaises(ValueError, self.driver.ex_create_network, + network_name, cidr, mode='foobar') + self.assertRaises(ValueError, self.driver.ex_create_network, + network_name, None, mode='legacy') + def test_ex_set_machine_type_notstopped(self): # get running node, change machine type zone = 'us-central1-a' @@ -1573,6 +1646,10 @@ def _setCommonInstanceMetadata(self, method, url, body, headers): body = self.fixtures.load('setCommonInstanceMetadata_post.json') return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + def _aggregated_subnetworks(self, method, url, body, headers): + body = self.fixtures.load('aggregated_subnetworks.json') + return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + def _aggregated_addresses(self, method, url, body, headers): body = self.fixtures.load('aggregated_addresses.json') return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) @@ -1733,6 +1810,10 @@ def _global_networks(self, method, url, body, headers): body = self.fixtures.load('global_networks.json') return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + def _global_networks_cf(self, method, url, body, headers): + body = self.fixtures.load('global_networks_cf.json') + return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + def _global_networks_default(self, method, url, body, headers): body = self.fixtures.load('global_networks_default.json') return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) @@ -1949,6 +2030,11 @@ def _global_urlMaps_web_map(self, method, url, body, headers): body = self.fixtures.load('global_urlMaps_web_map.json') return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + def _regions_us_central1_subnetworks_cf_972cf02e6ad49112(self, method, url, body, headers): + body = self.fixtures.load( + 'regions_us-central1_subnetworks_cf_972cf02e6ad49112.json') + return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + def _regions_us_central1_operations_operation_regions_us_central1_addresses_lcaddress_delete( self, method, url, body, headers): body = self.fixtures.load( @@ -1967,6 +2053,12 @@ def _regions_us_central1_operations_operation_regions_us_central1_addresses_post 'operations_operation_regions_us-central1_addresses_post.json') return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + def _regions_us_central1_operations_operation_regions_us_central1_subnetworks_post( + self, method, url, body, headers): + body = self.fixtures.load( + 'operations_operation_regions_us-central1_subnetworks_post.json') + return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + def _regions_us_central1_operations_operation_regions_us_central1_forwardingRules_post( self, method, url, body, headers): body = self.fixtures.load( @@ -2232,6 +2324,30 @@ def _global_addresses(self, method, url, body, headers): body = self.fixtures.load('global_addresses.json') return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + def _regions_europe_west1(self, method, url, body, headers): + body = self.fixtures.load('regions_europe-west1.json') + return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + + def _regions_asia_east1(self, method, url, body, headers): + body = self.fixtures.load('regions_asia-east1.json') + return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + + def _regions_us_central1(self, method, url, body, headers): + body = self.fixtures.load('regions_us-central1.json') + return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + + def _regions_us_east1(self, method, url, body, headers): + body = self.fixtures.load('regions_us-east1.json') + return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + + def _regions_us_central1_subnetworks(self, method, url, body, headers): + if method == 'POST': + body = self.fixtures.load( + 'regions_us-central1_subnetworks_post.json') + else: + body = self.fixtures.load('regions_us-central1_subnetworks.json') + return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + def _regions_us_central1_addresses(self, method, url, body, headers): if method == 'POST': body = self.fixtures.load( @@ -2384,6 +2500,14 @@ def _zones_asia_east_1a(self, method, url, body, headers): body = self.fixtures.load('zones_asia-east1-a.json') return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + def _zones_asia_east1_b(self, method, url, body, headers): + body = self.fixtures.load('zones_asia-east1-b.json') + return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + + def _zones_us_east1_b(self, method, url, body, headers): + body = self.fixtures.load('zones_us-east1-b.json') + return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + def _zones_us_central1_a_diskTypes(self, method, url, body, headers): body = self.fixtures.load('zones_us-central1-a_diskTypes.json') return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])