Repository: libcloud Updated Branches: refs/heads/trunk 4d11377bd -> 791ff6a46
[google compute] Projects support common instance metadata, usage buckets Closes #409 Signed-off-by: Eric Johnson <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/791ff6a4 Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/791ff6a4 Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/791ff6a4 Branch: refs/heads/trunk Commit: 791ff6a469397de2973ce16cdbbc10f20cbd1659 Parents: 4d11377 Author: Eric Johnson <[email protected]> Authored: Tue Dec 2 22:13:57 2014 +0000 Committer: Eric Johnson <[email protected]> Committed: Thu Dec 11 19:16:22 2014 +0000 ---------------------------------------------------------------------- CHANGES.rst | 4 + libcloud/compute/drivers/gce.py | 184 +++++++++++++++++++ ...ons_operation_setCommonInstanceMetadata.json | 15 ++ ...erations_operation_setUsageExportBucket.json | 14 ++ libcloud/test/compute/fixtures/gce/project.json | 155 ++++++++++------ .../gce/setCommonInstanceMetadata_post.json | 15 ++ .../fixtures/gce/setUsageExportBucket_post.json | 14 ++ libcloud/test/compute/test_gce.py | 117 +++++++++++- 8 files changed, 458 insertions(+), 60 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/791ff6a4/CHANGES.rst ---------------------------------------------------------------------- diff --git a/CHANGES.rst b/CHANGES.rst index 39d3a54..c7a0aba 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -16,6 +16,10 @@ General Compute ~~~~~~~ +- GCE Projects support common instance metadata and usage export buckets + (GITHUB-409) + [Eric Johnson] + - Improvements to TargetPool resource in GCE driver. (GITHUB-414) [Eric Johnson] http://git-wip-us.apache.org/repos/asf/libcloud/blob/791ff6a4/libcloud/compute/drivers/gce.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/drivers/gce.py b/libcloud/compute/drivers/gce.py index 6ee5c6e..f44945e 100644 --- a/libcloud/compute/drivers/gce.py +++ b/libcloud/compute/drivers/gce.py @@ -363,6 +363,54 @@ class GCEProject(UuidMixin): self.extra = extra UuidMixin.__init__(self) + def set_common_instance_metadata(self, metadata=None, force=False): + """ + Set common instance metadata for the project. Common uses + are for setting 'sshKeys', or setting a project-wide + 'startup-script' for all nodes (instances). Passing in + ``None`` for the 'metadata' parameter will clear out all common + instance metadata *except* for 'sshKeys'. If you also want to + update 'sshKeys', set the 'force' paramater to ``True``. + + :param metadata: Dictionay of metadata. Can be either a standard + python dictionary, or the format expected by + GCE (e.g. {'items': [{'key': k1, 'value': v1}, ...}] + :type metadata: ``dict`` or ``None`` + + :param force: Force update of 'sshKeys'. If force is ``False`` (the + default), existing sshKeys will be retained. Setting + force to ``True`` will either replace sshKeys if a new + a new value is supplied, or deleted if no new value + is supplied. + :type force: ``bool`` + + :return: True if successful + :rtype: ``bool`` + """ + return self.driver.ex_set_common_instance_metadata(self, metadata) + + def set_usage_export_bucket(self, bucket, prefix=None): + """ + Used to retain Compute Engine resource usage, storing the CSV data in + a Google Cloud Storage bucket. See the + `docs <https://cloud.google.com/compute/docs/usage-export>`_ for more + information. Please ensure you have followed the necessary setup steps + prior to enabling this feature (e.g. bucket exists, ACLs are in place, + etc.) + + :param bucket: Name of the Google Cloud Storage bucket. Specify the + name in either 'gs://<bucket_name>' or the full URL + 'https://storage.googleapis.com/<bucket_name>'. + :type bucket: ``str`` + + :param prefix: Optional prefix string for all reports. + :type prefix: ``str`` or ``None`` + + :return: True if successful + :rtype: ``bool`` + """ + return self.driver.ex_set_usage_export_bucket(self, bucket, prefix) + def __repr__(self): return '<GCEProject id="%s" name="%s">' % (self.id, self.name) @@ -770,6 +818,92 @@ class GCENodeDriver(NodeDriver): response['items']] return list_disktypes + def ex_set_usage_export_bucket(self, bucket, prefix=None): + """ + Used to retain Compute Engine resource usage, storing the CSV data in + a Google Cloud Storage bucket. See the + `docs <https://cloud.google.com/compute/docs/usage-export>`_ for more + information. Please ensure you have followed the necessary setup steps + prior to enabling this feature (e.g. bucket exists, ACLs are in place, + etc.) + + :param bucket: Name of the Google Cloud Storage bucket. Specify the + name in either 'gs://<bucket_name>' or the full URL + 'https://storage.googleapis.com/<bucket_name>'. + :type bucket: ``str`` + + :param prefix: Optional prefix string for all reports. + :type prefix: ``str`` or ``None`` + + :return: True if successful + :rtype: ``bool`` + """ + if bucket.startswith('https://www.googleapis.com/') or \ + bucket.startswith('gs://'): + data = {'bucketName': bucket} + else: + raise ValueError("Invalid bucket name: %s" % bucket) + if prefix: + data['reportNamePrefix'] = prefix + + request = '/setUsageExportBucket' + self.connection.async_request(request, method='POST', data=data) + return True + + def ex_set_common_instance_metadata(self, metadata=None, force=False): + """ + Set common instance metadata for the project. Common uses + are for setting 'sshKeys', or setting a project-wide + 'startup-script' for all nodes (instances). Passing in + ``None`` for the 'metadata' parameter will clear out all common + instance metadata *except* for 'sshKeys'. If you also want to + update 'sshKeys', set the 'force' paramater to ``True``. + + :param metadata: Dictionay of metadata. Can be either a standard + python dictionary, or the format expected by + GCE (e.g. {'items': [{'key': k1, 'value': v1}, ...}] + :type metadata: ``dict`` or ``None`` + + :param force: Force update of 'sshKeys'. If force is ``False`` (the + default), existing sshKeys will be retained. Setting + force to ``True`` will either replace sshKeys if a new + a new value is supplied, or deleted if no new value + is supplied. + :type force: ``bool`` + + :return: True if successful + :rtype: ``bool`` + """ + if metadata: + if not isinstance(metadata, dict): + raise ValueError("Metadata must be a python dictionary.") + + if 'items' not in metadata: + items = [] + for k, v in metadata.items(): + items.append({'key': k, 'value': v}) + metadata = {'items': items} + elif not isinstance(metadata['items'], list): + raise ValueError("Invalid GCE metadata format.") + + request = '/setCommonInstanceMetadata' + + project = self.ex_get_project() + current_metadata = project.extra['commonInstanceMetadata'] + fingerprint = current_metadata['fingerprint'] + + # grab copy of current 'sshKeys' in case we want to retain them + current_keys = "" + for md in current_metadata['items']: + if md['key'] == 'sshKeys': + current_keys = md['value'] + + new_md = self._set_project_metadata(metadata, force, current_keys) + + md = {'fingerprint': fingerprint, 'items': new_md} + self.connection.async_request(request, method='POST', data=md) + return True + def ex_list_addresses(self, region=None): """ Return a list of static addresses for a region, 'global', or all. @@ -4142,6 +4276,11 @@ class GCENodeDriver(NodeDriver): extra['creationTimestamp'] = project.get('creationTimestamp') extra['description'] = project.get('description') metadata = project['commonInstanceMetadata'].get('items') + if 'commonInstanceMetadata' in project: + # add this struct to get 'fingerprint' too + extra['commonInstanceMetadata'] = project['commonInstanceMetadata'] + if 'usageExportLocation' in project: + extra['usageExportLocation'] = project['usageExportLocation'] return GCEProject(id=project['id'], name=project['name'], metadata=metadata, quotas=project.get('quotas'), @@ -4313,3 +4452,48 @@ class GCENodeDriver(NodeDriver): return GCEZone(id=zone['id'], name=zone['name'], status=zone['status'], maintenance_windows=zone.get('maintenanceWindows'), deprecated=deprecated, driver=self, extra=extra) + + def _set_project_metadata(self, metadata=None, force=False, + current_keys=""): + """ + Return the GCE-friendly dictionary of metadata with/without an + entry for 'sshKeys' based on params for 'force' and 'current_keys'. + This method was added to simplify the set_common_instance_metadata + method and make it easier to test. + + :param metadata: The GCE-formatted dict (e.g. 'items' list of dicts) + :type metadata: ``dict`` or ``None`` + + :param force: Flag to specify user preference for keeping current_keys + :type force: ``bool`` + + :param current_keys: The value, if any, of existing 'sshKeys' + :type current_keys: ``str`` + + :return: GCE-friendly metadata dict + :rtype: ``dict`` + """ + if metadata is None: + # User wants to delete metdata, but if 'force' is False + # and we already have sshKeys, we should retain them. + # Otherwise, delete ALL THE THINGS! + if not force and current_keys: + new_md = [{'key': 'sshKeys', 'value': current_keys}] + else: + new_md = [] + else: + # User is providing new metadata. If 'force' is False, they + # want to preserve existing sshKeys, otherwise 'force' is True + # and the user wants to add/replace sshKeys. + new_md = metadata['items'] + if not force and current_keys: + # not sure how duplicate keys would be resolved, so ensure + # existing 'sshKeys' entry is removed. + updated_md = [] + for d in new_md: + if d['key'] != 'sshKeys': + updated_md.append({'key': d['key'], + 'value': d['value']}) + new_md = updated_md + new_md.append({'key': 'sshKeys', 'value': current_keys}) + return new_md http://git-wip-us.apache.org/repos/asf/libcloud/blob/791ff6a4/libcloud/test/compute/fixtures/gce/operations_operation_setCommonInstanceMetadata.json ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/gce/operations_operation_setCommonInstanceMetadata.json b/libcloud/test/compute/fixtures/gce/operations_operation_setCommonInstanceMetadata.json new file mode 100644 index 0000000..63f95ff --- /dev/null +++ b/libcloud/test/compute/fixtures/gce/operations_operation_setCommonInstanceMetadata.json @@ -0,0 +1,15 @@ +{ + "endTime": "2013-06-26T10:05:07.630-07:00", + "id": "3681664092089171723", + "insertTime": "2013-06-26T10:05:03.271-07:00", + "kind": "compute#operation", + "name": "operation-setCommonInstanceMetadat", + "operationType": "insert", + "progress": 100, + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/operations/operation-setCommonInstanceMetadata", + "startTime": "2013-06-26T10:05:03.315-07:00", + "status": "DONE", + "targetId": "16211908079305042870", + "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/setCommonInstanceMetadata", + "user": "[email protected]" +} http://git-wip-us.apache.org/repos/asf/libcloud/blob/791ff6a4/libcloud/test/compute/fixtures/gce/operations_operation_setUsageExportBucket.json ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/gce/operations_operation_setUsageExportBucket.json b/libcloud/test/compute/fixtures/gce/operations_operation_setUsageExportBucket.json new file mode 100644 index 0000000..5fa9902 --- /dev/null +++ b/libcloud/test/compute/fixtures/gce/operations_operation_setUsageExportBucket.json @@ -0,0 +1,14 @@ +{ + "kind": "compute#operation", + "id": "17203609782824174066", + "name": "operation-setUsageExportBucket", + "operationType": "setUsageExportBucket", + "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name", + "targetId": "8116069320260064853", + "status": "DONE", + "user": "[email protected]", + "progress": 100, + "insertTime": "2014-11-21T06:58:03.602-08:00", + "startTime": "2014-11-21T06:58:04.018-08:00", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/operations/operation-setUsageExportBucket" +} http://git-wip-us.apache.org/repos/asf/libcloud/blob/791ff6a4/libcloud/test/compute/fixtures/gce/project.json ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/gce/project.json b/libcloud/test/compute/fixtures/gce/project.json index 6b65499..b50e40f 100644 --- a/libcloud/test/compute/fixtures/gce/project.json +++ b/libcloud/test/compute/fixtures/gce/project.json @@ -1,59 +1,98 @@ { - "commonInstanceMetadata": { - "items": [ - { - "key": "sshKeys", - "value": "ASDFASDF" - } - ], - "kind": "compute#metadata" - }, - "creationTimestamp": "2013-02-05T16:19:20.516-08:00", - "description": "", - "id": "2193465259114366848", - "kind": "compute#project", - "name": "project_name", - "quotas": [ - { - "limit": 1000.0, - "metric": "SNAPSHOTS", - "usage": 0.0 - }, - { - "limit": 5.0, - "metric": "NETWORKS", - "usage": 3.0 - }, - { - "limit": 100.0, - "metric": "FIREWALLS", - "usage": 5.0 - }, - { - "limit": 100.0, - "metric": "IMAGES", - "usage": 0.0 - }, - { - "limit": 100.0, - "metric": "ROUTES", - "usage": 6.0 - }, - { - "limit": 50.0, - "metric": "FORWARDING_RULES", - "usage": 0.0 - }, - { - "limit": 50.0, - "metric": "TARGET_POOLS", - "usage": 1.0 - }, - { - "limit": 50.0, - "metric": "HEALTH_CHECKS", - "usage": 1.0 - } - ], - "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name" -} \ No newline at end of file + "kind": "compute#project", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name", + "id": "8116069320260064853", + "creationTimestamp": "2014-01-21T10:30:53.390-08:00", + "name": "project_name", + "description": "", + "commonInstanceMetadata": { + "kind": "compute#metadata", + "fingerprint": "3zEcGBxH6Vs=", + "items": [ + { + "key": "sshKeys", + "value": "ABCDEF" + }, + { + "key": "startup-script", + "value": "#!/bin/bash\n\nAUTO_SCRIPT=$(curl -s http://metadata/computeMetadata/v1/instance/attributes/my-auto-script -H \"Metadata-Flavor: Google\")\nCHECK=${AUTO_SCRIPT:-disabled}\n\nif [ \"${CHECK}\" = \"enabled\" -a -f /etc/debian_version ]; then\n export DEBIAN_FRONTEND=noninteractive\n apt-get -q -y update\n apt-get -q -y install git vim tmux\n fi\nexit 0\n" + } + ] + }, + "quotas": [ + { + "metric": "SNAPSHOTS", + "limit": 1000, + "usage": 1 + }, + { + "metric": "NETWORKS", + "limit": 5, + "usage": 3 + }, + { + "metric": "FIREWALLS", + "limit": 100, + "usage": 6 + }, + { + "metric": "IMAGES", + "limit": 100, + "usage": 1 + }, + { + "metric": "STATIC_ADDRESSES", + "limit": 7, + "usage": 1 + }, + { + "metric": "ROUTES", + "limit": 100, + "usage": 2 + }, + { + "metric": "FORWARDING_RULES", + "limit": 50, + "usage": 0 + }, + { + "metric": "TARGET_POOLS", + "limit": 50, + "usage": 0 + }, + { + "metric": "HEALTH_CHECKS", + "limit": 50, + "usage": 1 + }, + { + "metric": "IN_USE_ADDRESSES", + "limit": 23, + "usage": 0 + }, + { + "metric": "TARGET_INSTANCES", + "limit": 50, + "usage": 3 + }, + { + "metric": "TARGET_HTTP_PROXIES", + "limit": 50, + "usage": 0 + }, + { + "metric": "URL_MAPS", + "limit": 50, + "usage": 1 + }, + { + "metric": "BACKEND_SERVICES", + "limit": 50, + "usage": 1 + } + ], + "usageExportLocation": { + "bucketName": "gs://graphite-usage-reports", + "reportNamePrefix": "graphite-report" + } +} http://git-wip-us.apache.org/repos/asf/libcloud/blob/791ff6a4/libcloud/test/compute/fixtures/gce/setCommonInstanceMetadata_post.json ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/gce/setCommonInstanceMetadata_post.json b/libcloud/test/compute/fixtures/gce/setCommonInstanceMetadata_post.json new file mode 100644 index 0000000..1bbe33b --- /dev/null +++ b/libcloud/test/compute/fixtures/gce/setCommonInstanceMetadata_post.json @@ -0,0 +1,15 @@ +{ + "endTime": "2013-06-26T10:05:07.630-07:00", + "id": "3681664092089171723", + "insertTime": "2013-06-26T10:05:03.271-07:00", + "kind": "compute#operation", + "name": "operation-setCommonInstanceMetadata", + "operationType": "insert", + "progress": 0, + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/operations/operation-setCommonInstanceMetadata", + "startTime": "2013-06-26T10:05:03.315-07:00", + "status": "PENDING", + "targetId": "16211908079305042870", + "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/setCommonInstanceMetadata", + "user": "[email protected]" +} http://git-wip-us.apache.org/repos/asf/libcloud/blob/791ff6a4/libcloud/test/compute/fixtures/gce/setUsageExportBucket_post.json ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/gce/setUsageExportBucket_post.json b/libcloud/test/compute/fixtures/gce/setUsageExportBucket_post.json new file mode 100644 index 0000000..24df85c --- /dev/null +++ b/libcloud/test/compute/fixtures/gce/setUsageExportBucket_post.json @@ -0,0 +1,14 @@ +{ + "kind": "compute#operation", + "id": "17203609782824174066", + "name": "operation-setUsageExportBucket", + "operationType": "setUsageExportBucket", + "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name", + "targetId": "8116069320260064853", + "status": "PENDING", + "user": "[email protected]", + "progress": 0, + "insertTime": "2014-11-21T06:58:03.602-08:00", + "startTime": "2014-11-21T06:58:04.018-08:00", + "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/operations/operation-setUsageExportBucket" +} http://git-wip-us.apache.org/repos/asf/libcloud/blob/791ff6a4/libcloud/test/compute/test_gce.py ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/test_gce.py b/libcloud/test/compute/test_gce.py index dccff82..8efeaa1 100644 --- a/libcloud/test/compute/test_gce.py +++ b/libcloud/test/compute/test_gce.py @@ -789,9 +789,100 @@ class GCENodeDriverTest(LibcloudTestCase, TestCaseMixin): project = self.driver.ex_get_project() self.assertEqual(project.name, 'project_name') networks_quota = project.quotas[1] - self.assertEqual(networks_quota['usage'], 3.0) - self.assertEqual(networks_quota['limit'], 5.0) + self.assertEqual(networks_quota['usage'], 3) + self.assertEqual(networks_quota['limit'], 5) self.assertEqual(networks_quota['metric'], 'NETWORKS') + self.assertTrue('fingerprint' in project.extra['commonInstanceMetadata']) + self.assertTrue('items' in project.extra['commonInstanceMetadata']) + self.assertTrue('usageExportLocation' in project.extra) + self.assertTrue('bucketName' in project.extra['usageExportLocation']) + self.assertTrue(project.extra['usageExportLocation']['bucketName'], 'gs://graphite-usage-reports') + + def test_ex_set_usage_export_bucket(self): + self.assertRaises(ValueError, + self.driver.ex_set_usage_export_bucket, 'foo') + bucket_name = 'gs://foo' + self.driver.ex_set_usage_export_bucket(bucket_name) + + bucket_name = 'https://www.googleapis.com/foo' + self.driver.ex_set_usage_export_bucket(bucket_name) + + def test__set_project_metadata(self): + self.assertEqual(len(self.driver._set_project_metadata(None, False, "")), 0) + + # 'delete' metadata, but retain current sshKeys + md = self.driver._set_project_metadata(None, False, "this is a test") + self.assertEqual(len(md), 1) + self.assertEqual(md[0]['key'], 'sshKeys') + self.assertEqual(md[0]['value'], 'this is a test') + + # 'delete' metadata *and* any existing sshKeys + md = self.driver._set_project_metadata(None, True, "this is a test") + self.assertEqual(len(md), 0) + + # add new metadata, keep existing sshKeys, since the new value also + # has 'sshKeys', we want the final struct to only have one ke/value + # of sshKeys and it should be the "current_keys" + gce_md = {'items': [{'key': 'foo', 'value': 'one'}, + {'key': 'sshKeys', 'value': 'another test'}]} + md = self.driver._set_project_metadata(gce_md, False, "this is a test") + self.assertEqual(len(md), 2, str(md)) + sshKeys = "" + count = 0 + for d in md: + if d['key'] == 'sshKeys': + count += 1 + sshKeys = d['value'] + self.assertEqual(sshKeys, 'this is a test') + self.assertEqual(count, 1) + + # add new metadata, overwrite existing sshKeys, in this case, the + # existing 'sshKeys' value should be replaced + gce_md = {'items': [{'key': 'foo', 'value': 'one'}, + {'key': 'sshKeys', 'value': 'another test'}]} + md = self.driver._set_project_metadata(gce_md, True, "this is a test") + self.assertEqual(len(md), 2, str(md)) + sshKeys = "" + count = 0 + for d in md: + if d['key'] == 'sshKeys': + count += 1 + sshKeys = d['value'] + self.assertEqual(sshKeys, 'another test') + self.assertEqual(count, 1) + + # add new metadata, remove existing sshKeys. in this case, we had an + # 'sshKeys' entry, but it will be removed entirely + gce_md = {'items': [{'key': 'foo', 'value': 'one'}, + {'key': 'nokeys', 'value': 'two'}]} + md = self.driver._set_project_metadata(gce_md, True, "this is a test") + self.assertEqual(len(md), 2, str(md)) + sshKeys = "" + count = 0 + for d in md: + if d['key'] == 'sshKeys': + count += 1 + sshKeys = d['value'] + self.assertEqual(sshKeys, '') + self.assertEqual(count, 0) + + def test_ex_set_common_instance_metadata(self): + # test non-dict + self.assertRaises(ValueError, + self.driver.ex_set_common_instance_metadata, + ['bad', 'type']) + # test standard python dict + pydict = {'foo': 'pydict', 'one': 1} + self.driver.ex_set_common_instance_metadata(pydict) + # test GCE badly formatted dict + bad_gcedict = {'items': 'foo'} + self.assertRaises(ValueError, + self.driver.ex_set_common_instance_metadata, + bad_gcedict) + # test gce formatted dict + gcedict = {'items': [{'key': 'gcedict', 'value': 'v1'}, + {'key': 'gcedict', 'value': 'v2'}]} + self.driver.ex_set_common_instance_metadata(gcedict) def test_ex_get_region(self): region_name = 'us-central1' @@ -878,6 +969,16 @@ class GCEMockHttp(MockHttpTestCase): qs, path) return method_name + def _setUsageExportBucket(self, method, url, body, headers): + if method == 'POST': + body = self.fixtures.load('setUsageExportBucket_post.json') + return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + + def _setCommonInstanceMetadata(self, method, url, body, headers): + if method == 'POST': + body = self.fixtures.load('setCommonInstanceMetadata_post.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]) @@ -1033,6 +1134,18 @@ class GCEMockHttp(MockHttpTestCase): body = self.fixtures.load('global_snapshots_lcsnapshot.json') return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + def _global_operations_operation_setUsageExportBucket( + self, method, url, body, headers): + body = self.fixtures.load( + 'operations_operation_setUsageExportBucket.json') + return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + + def _global_operations_operation_setCommonInstanceMetadata( + self, method, url, body, headers): + body = self.fixtures.load( + 'operations_operation_setCommonInstanceMetadata.json') + return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK]) + def _global_operations_operation_global_httpHealthChecks_lchealthcheck_delete( self, method, url, body, headers): body = self.fixtures.load(
