You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by an...@apache.org on 2016/11/14 23:51:12 UTC
[25/56] [abbrv] libcloud git commit: Removed sdist
http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/gce.py
----------------------------------------------------------------------
diff --git a/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/gce.py b/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/gce.py
deleted file mode 100644
index 4aa92ac..0000000
--- a/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/gce.py
+++ /dev/null
@@ -1,5860 +0,0 @@
-# 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.
-"""
-Module for Google Compute Engine Driver.
-"""
-from __future__ import with_statement
-
-import datetime
-import time
-import sys
-
-from libcloud.common.base import LazyObject
-from libcloud.common.google import GoogleOAuth2Credential
-from libcloud.common.google import GoogleResponse
-from libcloud.common.google import GoogleBaseConnection
-from libcloud.common.google import GoogleBaseError
-from libcloud.common.google import ResourceNotFoundError
-from libcloud.common.google import ResourceExistsError
-from libcloud.common.types import ProviderError
-
-from libcloud.compute.base import Node, NodeDriver, NodeImage, NodeLocation
-from libcloud.compute.base import NodeSize, StorageVolume, VolumeSnapshot
-from libcloud.compute.base import UuidMixin
-from libcloud.compute.providers import Provider
-from libcloud.compute.types import NodeState
-from libcloud.utils.iso8601 import parse_date
-
-API_VERSION = 'v1'
-DEFAULT_TASK_COMPLETION_TIMEOUT = 180
-
-
-def timestamp_to_datetime(timestamp):
- """
- Return a datetime object that corresponds to the time in an RFC3339
- timestamp.
-
- :param timestamp: RFC3339 timestamp string
- :type timestamp: ``str``
-
- :return: Datetime object corresponding to timestamp
- :rtype: :class:`datetime.datetime`
- """
- # We remove timezone offset and microseconds (Python 2.5 strptime doesn't
- # support %f)
- ts = datetime.datetime.strptime(timestamp[:-10], '%Y-%m-%dT%H:%M:%S')
- tz_hours = int(timestamp[-5:-3])
- tz_mins = int(timestamp[-2:]) * int(timestamp[-6:-5] + '1')
- tz_delta = datetime.timedelta(hours=tz_hours, minutes=tz_mins)
- return ts + tz_delta
-
-
-class GCEResponse(GoogleResponse):
- pass
-
-
-class GCEConnection(GoogleBaseConnection):
- """
- Connection class for the GCE driver.
-
- GCEConnection extends :class:`google.GoogleBaseConnection` for 2 reasons:
- 1. modify request_path for GCE URI.
- 2. Implement gce_params functionality described below.
-
- If the parameter gce_params is set to a dict prior to calling request(),
- the URL parameters will be updated to include those key/values FOR A
- SINGLE REQUEST. If the response contains a nextPageToken,
- gce_params['pageToken'] will be set to its value. This can be used to
- implement paging in list:
-
- >>> params, more_results = {'maxResults': 2}, True
- >>> while more_results:
- ... driver.connection.gce_params=params
- ... driver.ex_list_urlmaps()
- ... more_results = 'pageToken' in params
- ...
- [<GCEUrlMap id="..." name="cli-map">, <GCEUrlMap id="..." name="lc-map">]
- [<GCEUrlMap id="..." name="web-map">]
- """
- host = 'www.googleapis.com'
- responseCls = GCEResponse
-
- def __init__(self, user_id, key, secure, auth_type=None,
- credential_file=None, project=None, **kwargs):
- super(GCEConnection, self).__init__(user_id, key, secure=secure,
- auth_type=auth_type,
- credential_file=credential_file,
- **kwargs)
- self.request_path = '/compute/%s/projects/%s' % (API_VERSION, project)
- self.gce_params = None
-
- def pre_connect_hook(self, params, headers):
- """
- Update URL parameters with values from self.gce_params.
-
- @inherits: :class:`GoogleBaseConnection.pre_connect_hook`
- """
- params, headers = super(GCEConnection, self).pre_connect_hook(params,
- headers)
- if self.gce_params:
- params.update(self.gce_params)
- return params, headers
-
- def request(self, *args, **kwargs):
- """
- Perform request then do GCE-specific processing of URL params.
-
- @inherits: :class:`GoogleBaseConnection.request`
- """
- response = super(GCEConnection, self).request(*args, **kwargs)
-
- # If gce_params has been set, then update the pageToken with the
- # nextPageToken so it can be used in the next request.
- if self.gce_params:
- if 'nextPageToken' in response.object:
- self.gce_params['pageToken'] = response.object['nextPageToken']
- elif 'pageToken' in self.gce_params:
- del self.gce_params['pageToken']
- self.gce_params = None
-
- return response
-
-
-class GCEList(object):
- """
- An Iterator that wraps list functions to provide additional features.
-
- GCE enforces a limit on the number of objects returned by a list operation,
- so users with more than 500 objects of a particular type will need to use
- filter(), page() or both.
-
- >>> l=GCEList(driver, driver.ex_list_urlmaps)
- >>> for sublist in l.filter('name eq ...-map').page(1):
- ... sublist
- ...
- [<GCEUrlMap id="..." name="cli-map">]
- [<GCEUrlMap id="..." name="web-map">]
-
- One can create a GCEList manually, but it's slightly easier to use the
- ex_list() method of :class:`GCENodeDriver`.
- """
-
- def __init__(self, driver, list_fn, **kwargs):
- """
- :param driver: An initialized :class:``GCENodeDriver``
- :type driver: :class:``GCENodeDriver``
-
- :param list_fn: A bound list method from :class:`GCENodeDriver`.
- :type list_fn: ``instancemethod``
- """
- self.driver = driver
- self.list_fn = list_fn
- self.kwargs = kwargs
- self.params = {}
-
- def __iter__(self):
- list_fn = self.list_fn
- more_results = True
- while more_results:
- self.driver.connection.gce_params = self.params
- yield list_fn(**self.kwargs)
- more_results = 'pageToken' in self.params
-
- def __repr__(self):
- return '<GCEList list="%s" params="%s">' % (
- self.list_fn.__name__, repr(self.params))
-
- def filter(self, expression):
- """
- Filter results of a list operation.
-
- GCE supports server-side filtering of resources returned by a list
- operation. Syntax of the filter expression is fully described in the
- GCE API reference doc, but in brief it is::
-
- FIELD_NAME COMPARISON_STRING LITERAL_STRING
-
- where FIELD_NAME is the resource's property name, COMPARISON_STRING is
- 'eq' or 'ne', and LITERAL_STRING is a regular expression in RE2 syntax.
-
- >>> for sublist in l.filter('name eq ...-map'):
- ... sublist
- ...
- [<GCEUrlMap id="..." name="cli-map">, \
- <GCEUrlMap id="..." name="web-map">]
-
- API reference: https://cloud.google.com/compute/docs/reference/latest/
- RE2 syntax: https://github.com/google/re2/blob/master/doc/syntax.txt
-
- :param expression: Filter expression described above.
- :type expression: ``str``
-
- :return: This :class:`GCEList` instance
- :rtype: :class:`GCEList`
- """
- self.params['filter'] = expression
- return self
-
- def page(self, max_results=500):
- """
- Limit the number of results by each iteration.
-
- This implements the paging functionality of the GCE list methods and
- returns this GCEList instance so that results can be chained:
-
- >>> for sublist in GCEList(driver, driver.ex_list_urlmaps).page(2):
- ... sublist
- ...
- [<GCEUrlMap id="..." name="cli-map">, \
- <GCEUrlMap id="..." name="lc-map">]
- [<GCEUrlMap id="..." name="web-map">]
-
- :keyword max_results: Maximum number of results to return per
- iteration. Defaults to the GCE default of 500.
- :type max_results: ``int``
-
- :return: This :class:`GCEList` instance
- :rtype: :class:`GCEList`
- """
- self.params['maxResults'] = max_results
- return self
-
-
-class GCELicense(UuidMixin, LazyObject):
- """A GCE License used to track software usage in GCE nodes."""
- def __init__(self, name, project, driver):
- UuidMixin.__init__(self)
- self.id = name
- self.name = name
- self.project = project
- self.driver = driver
- self.charges_use_fee = None # init in _request
- self.extra = None # init in _request
-
- self._request()
-
- def _request(self):
- # TODO(crunkleton@google.com): create new connection? or make
- # connection thread-safe? Saving, modifying, and restoring
- # driver.connection.request_path is really hacky and thread-unsafe.
- saved_request_path = self.driver.connection.request_path
- new_request_path = saved_request_path.replace(self.driver.project,
- self.project)
- self.driver.connection.request_path = new_request_path
-
- request = '/global/licenses/%s' % self.name
- response = self.driver.connection.request(request, method='GET').object
- self.driver.connection.request_path = saved_request_path
-
- self.extra = {
- 'selfLink': response.get('selfLink'),
- 'kind': response.get('kind')
- }
- self.charges_use_fee = response['chargesUseFee']
-
- def destroy(self):
- raise ProviderError("Can not destroy a License resource.")
-
- def __repr__(self):
- return '<GCELicense id="%s" name="%s" charges_use_fee="%s">' % (
- self.id, self.name, self.charges_use_fee)
-
-
-class GCEDiskType(UuidMixin):
- """A GCE DiskType resource."""
- def __init__(self, id, name, zone, driver, extra=None):
- self.id = str(id)
- self.name = name
- self.zone = zone
- self.driver = driver
- self.extra = extra
- UuidMixin.__init__(self)
-
- def destroy(self):
- raise ProviderError("Can not destroy a DiskType resource.")
-
- def __repr__(self):
- return '<GCEDiskType id="%s" name="%s" zone="%s">' % (
- self.id, self.name, self.zone)
-
-
-class GCEAddress(UuidMixin):
- """A GCE Static address."""
- def __init__(self, id, name, address, region, driver, extra=None):
- self.id = str(id)
- self.name = name
- self.address = address
- self.region = region
- self.driver = driver
- self.extra = extra
- UuidMixin.__init__(self)
-
- def destroy(self):
- """
- Destroy this address.
-
- :return: True if successful
- :rtype: ``bool``
- """
- return self.driver.ex_destroy_address(address=self)
-
- def __repr__(self):
- return '<GCEAddress id="%s" name="%s" address="%s" region="%s">' % (
- self.id, self.name, self.address,
- (hasattr(self.region, "name") and self.region.name or self.region))
-
-
-class GCEBackendService(UuidMixin):
- """A GCE Backend Service."""
-
- def __init__(self, id, name, backends, healthchecks, port, port_name,
- protocol, timeout, driver, extra=None):
- self.id = str(id)
- self.name = name
- self.backends = backends or []
- self.healthchecks = healthchecks or []
- self.port = port
- self.port_name = port_name
- self.protocol = protocol
- self.timeout = timeout
- self.driver = driver
- self.extra = extra or {}
- UuidMixin.__init__(self)
-
- def __repr__(self):
- return '<GCEBackendService id="%s" name="%s">' % (
- self.id, self.name)
-
- def destroy(self):
- """
- Destroy this Backend Service.
-
- :return: True if successful
- :rtype: ``bool``
- """
- return self.driver.ex_destroy_backendservice(backendservice=self)
-
-
-class GCEFailedDisk(object):
- """Dummy Node object for disks that are not created."""
- def __init__(self, name, error, code):
- self.name = name
- self.error = error
- self.code = code
-
- def __repr__(self):
- return '<GCEFailedDisk name="%s" error_code="%s">' % (
- self.name, self.code)
-
-
-class GCEFailedNode(object):
- """Dummy Node object for nodes that are not created."""
- def __init__(self, name, error, code):
- self.name = name
- self.error = error
- self.code = code
-
- def __repr__(self):
- return '<GCEFailedNode name="%s" error_code="%s">' % (
- self.name, self.code)
-
-
-class GCEHealthCheck(UuidMixin):
- """A GCE Http Health Check class."""
- def __init__(self, id, name, path, port, interval, timeout,
- unhealthy_threshold, healthy_threshold, driver, extra=None):
- self.id = str(id)
- self.name = name
- self.path = path
- self.port = port
- self.interval = interval
- self.timeout = timeout
- self.unhealthy_threshold = unhealthy_threshold
- self.healthy_threshold = healthy_threshold
- self.driver = driver
- self.extra = extra or {}
- UuidMixin.__init__(self)
-
- def destroy(self):
- """
- Destroy this Health Check.
-
- :return: True if successful
- :rtype: ``bool``
- """
- return self.driver.ex_destroy_healthcheck(healthcheck=self)
-
- def update(self):
- """
- Commit updated healthcheck values.
-
- :return: Updated Healthcheck object
- :rtype: :class:`GCEHealthcheck`
- """
- return self.driver.ex_update_healthcheck(healthcheck=self)
-
- def __repr__(self):
- return '<GCEHealthCheck id="%s" name="%s" path="%s" port="%s">' % (
- self.id, self.name, self.path, self.port)
-
-
-class GCEFirewall(UuidMixin):
- """A GCE Firewall rule class."""
- def __init__(self, id, name, allowed, network, source_ranges, source_tags,
- target_tags, driver, extra=None):
- self.id = str(id)
- self.name = name
- self.network = network
- self.allowed = allowed
- self.source_ranges = source_ranges
- self.source_tags = source_tags
- self.target_tags = target_tags
- self.driver = driver
- self.extra = extra
- UuidMixin.__init__(self)
-
- def destroy(self):
- """
- Destroy this firewall.
-
- :return: True if successful
- :rtype: ``bool``
- """
- return self.driver.ex_destroy_firewall(firewall=self)
-
- def update(self):
- """
- Commit updated firewall values.
-
- :return: Updated Firewall object
- :rtype: :class:`GCEFirewall`
- """
- return self.driver.ex_update_firewall(firewall=self)
-
- def __repr__(self):
- return '<GCEFirewall id="%s" name="%s" network="%s">' % (
- self.id, self.name, self.network.name)
-
-
-class GCEForwardingRule(UuidMixin):
- def __init__(self, id, name, region, address, protocol, targetpool, driver,
- extra=None):
- self.id = str(id)
- self.name = name
- self.region = region
- self.address = address
- self.protocol = protocol
- # TODO: 'targetpool' should more correctly be 'target' since a
- # forwarding rule's target can be something besides a targetpool
- self.targetpool = targetpool
- self.driver = driver
- self.extra = extra
- UuidMixin.__init__(self)
-
- def destroy(self):
- """
- Destroy this Forwarding Rule
-
- :return: True if successful
- :rtype: ``bool``
- """
- return self.driver.ex_destroy_forwarding_rule(forwarding_rule=self)
-
- def __repr__(self):
- return '<GCEForwardingRule id="%s" name="%s" address="%s">' % (
- self.id, self.name, self.address)
-
-
-class GCENodeImage(NodeImage):
- """A GCE Node Image class."""
- def __init__(self, id, name, driver, extra=None):
- super(GCENodeImage, self).__init__(id, name, driver, extra=extra)
-
- def delete(self):
- """
- Delete this image
-
- :return: True if successful
- :rtype: ``bool``
- """
- return self.driver.ex_delete_image(image=self)
-
- def deprecate(self, replacement, state, deprecated=None, obsolete=None,
- deleted=None):
- """
- Deprecate this image
-
- :param replacement: Image to use as a replacement
- :type replacement: ``str`` or :class: `GCENodeImage`
-
- :param state: Deprecation state of this image. Possible values include
- \'DELETED\', \'DEPRECATED\' or \'OBSOLETE\'.
- :type state: ``str``
-
- :param deprecated: RFC3339 timestamp to mark DEPRECATED
- :type deprecated: ``str`` or ``None``
-
- :param obsolete: RFC3339 timestamp to mark OBSOLETE
- :type obsolete: ``str`` or ``None``
-
- :param deleted: RFC3339 timestamp to mark DELETED
- :type deleted: ``str`` or ``None``
-
- :return: True if successful
- :rtype: ``bool``
- """
- return self.driver.ex_deprecate_image(self, replacement, state,
- deprecated, obsolete, deleted)
-
-
-class GCENetwork(UuidMixin):
- """A GCE Network object class."""
- def __init__(self, id, name, cidr, driver, extra=None):
- self.id = str(id)
- self.name = name
- self.cidr = cidr
- self.driver = driver
- self.extra = extra
- UuidMixin.__init__(self)
-
- def destroy(self):
- """
- Destroy this network
-
- :return: True if successful
- :rtype: ``bool``
- """
- return self.driver.ex_destroy_network(network=self)
-
- def __repr__(self):
- return '<GCENetwork id="%s" name="%s" cidr="%s">' % (
- self.id, self.name, self.cidr)
-
-
-class GCERoute(UuidMixin):
- """A GCE Route object class."""
- def __init__(self, id, name, dest_range, priority, network="default",
- tags=None, driver=None, extra=None):
- self.id = str(id)
- self.name = name
- self.dest_range = dest_range
- self.priority = priority
- self.network = network
- self.tags = tags
- self.driver = driver
- self.extra = extra
- UuidMixin.__init__(self)
-
- def destroy(self):
- """
- Destroy this route
-
- :return: True if successful
- :rtype: ``bool``
- """
- return self.driver.ex_destroy_route(route=self)
-
- def __repr__(self):
- return '<GCERoute id="%s" name="%s" dest_range="%s" network="%s">' % (
- self.id, self.name, self.dest_range,
- hasattr(self.network, 'name') and self.network.name or
- self.network)
-
-
-class GCENodeSize(NodeSize):
- """A GCE Node Size (MachineType) class."""
- def __init__(self, id, name, ram, disk, bandwidth, price, driver,
- extra=None):
- self.extra = extra
- super(GCENodeSize, self).__init__(id, name, ram, disk, bandwidth,
- price, driver, extra=extra)
-
-
-class GCEProject(UuidMixin):
- """GCE Project information."""
- def __init__(self, id, name, metadata, quotas, driver, extra=None):
- self.id = str(id)
- self.name = name
- self.metadata = metadata
- self.quotas = quotas
- self.driver = driver
- 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' parameter to ``True``.
-
- :param metadata: Dictionary 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)
-
-
-class GCERegion(UuidMixin):
- def __init__(self, id, name, status, zones, quotas, deprecated, driver,
- extra=None):
- self.id = str(id)
- self.name = name
- self.status = status
- self.zones = zones
- self.quotas = quotas
- self.deprecated = deprecated
- self.driver = driver
- self.extra = extra
- UuidMixin.__init__(self)
-
- def __repr__(self):
- return '<GCERegion id="%s" name="%s", status="%s">' % (
- self.id, self.name, self.status)
-
-
-class GCESnapshot(VolumeSnapshot):
- def __init__(self, id, name, size, status, driver, extra=None,
- created=None):
- self.name = name
- self.status = status
- super(GCESnapshot, self).__init__(id, driver, size, extra, created)
-
-
-class GCETargetHttpProxy(UuidMixin):
- def __init__(self, id, name, urlmap, driver, extra=None):
- self.id = str(id)
- self.name = name
- self.urlmap = urlmap
- self.driver = driver
- self.extra = extra or {}
- UuidMixin.__init__(self)
-
- def __repr__(self):
- return '<GCETargetHttpProxy id="%s" name="%s">' % (
- self.id, self.name)
-
- def destroy(self):
- """
- Destroy this Target HTTP Proxy.
-
- :return: True if successful
- :rtype: ``bool``
- """
- return self.driver.ex_destroy_targethttpproxy(targethttpproxy=self)
-
-
-class GCETargetInstance(UuidMixin):
- def __init__(self, id, name, zone, node, driver, extra=None):
- self.id = str(id)
- self.name = name
- self.zone = zone
- self.node = node
- self.driver = driver
- self.extra = extra
- UuidMixin.__init__(self)
-
- def destroy(self):
- """
- Destroy this Target Instance
-
- :return: True if successful
- :rtype: ``bool``
- """
- return self.driver.ex_destroy_targetinstance(targetinstance=self)
-
- def __repr__(self):
- return '<GCETargetInstance id="%s" name="%s" zone="%s" node="%s">' % (
- self.id, self.name, self.zone.name,
- (hasattr(self.node, 'name') and self.node.name or self.node))
-
-
-class GCETargetPool(UuidMixin):
- def __init__(self, id, name, region, healthchecks, nodes, driver,
- extra=None):
- self.id = str(id)
- self.name = name
- self.region = region
- self.healthchecks = healthchecks
- self.nodes = nodes
- self.driver = driver
- self.extra = extra
- UuidMixin.__init__(self)
-
- def add_node(self, node):
- """
- Add a node to this target pool.
-
- :param node: Node to add
- :type node: ``str`` or :class:`Node`
-
- :return: True if successful
- :rtype: ``bool``
- """
- return self.driver.ex_targetpool_add_node(targetpool=self, node=node)
-
- def remove_node(self, node):
- """
- Remove a node from this target pool.
-
- :param node: Node to remove
- :type node: ``str`` or :class:`Node`
-
- :return: True if successful
- :rtype: ``bool``
- """
- return self.driver.ex_targetpool_remove_node(targetpool=self,
- node=node)
-
- def add_healthcheck(self, healthcheck):
- """
- Add a healthcheck to this target pool.
-
- :param healthcheck: Healthcheck to add
- :type healthcheck: ``str`` or :class:`GCEHealthCheck`
-
- :return: True if successful
- :rtype: ``bool``
- """
- return self.driver.ex_targetpool_add_healthcheck(
- targetpool=self, healthcheck=healthcheck)
-
- def remove_healthcheck(self, healthcheck):
- """
- Remove a healthcheck from this target pool.
-
- :param healthcheck: Healthcheck to remove
- :type healthcheck: ``str`` or :class:`GCEHealthCheck`
-
- :return: True if successful
- :rtype: ``bool``
- """
- return self.driver.ex_targetpool_remove_healthcheck(
- targetpool=self, healthcheck=healthcheck)
-
- def set_backup_targetpool(self, backup_targetpool, failover_ratio=0.1):
- """
- Set a backup targetpool.
-
- :param backup_targetpool: The existing targetpool to use for
- failover traffic.
- :type backup_targetpool: :class:`GCETargetPool`
-
- :param failover_ratio: The percentage of healthy VMs must fall at or
- below this value before traffic will be sent
- to the backup targetpool (default 0.10)
- :type failover_ratio: ``float``
-
- :return: True if successful
- :rtype: ``bool``
- """
- return self.driver.ex_targetpool_set_backup_targetpool(
- targetpool=self, backup_targetpool=backup_targetpool,
- failover_ratio=failover_ratio)
-
- def get_health(self, node=None):
- """
- Return a hash of target pool instances and their health.
-
- :param node: Optional node to specify if only a specific node's
- health status should be returned
- :type node: ``str``, ``Node``, or ``None``
-
- :return: List of hashes of nodes and their respective health
- :rtype: ``list`` of ``dict``
- """
- return self.driver.ex_targetpool_get_health(targetpool=self, node=node)
-
- def destroy(self):
- """
- Destroy this Target Pool
-
- :return: True if successful
- :rtype: ``bool``
- """
- return self.driver.ex_destroy_targetpool(targetpool=self)
-
- def __repr__(self):
- return '<GCETargetPool id="%s" name="%s" region="%s">' % (
- self.id, self.name, self.region.name)
-
-
-class GCEUrlMap(UuidMixin):
- """A GCE URL Map."""
-
- def __init__(self, id, name, default_service, host_rules, path_matchers,
- tests, driver, extra=None):
- self.id = str(id)
- self.name = name
- self.default_service = default_service
- self.host_rules = host_rules or []
- self.path_matchers = path_matchers or []
- self.tests = tests or []
- self.driver = driver
- self.extra = extra or {}
- UuidMixin.__init__(self)
-
- def __repr__(self):
- return '<GCEUrlMap id="%s" name="%s">' % (
- self.id, self.name)
-
- def destroy(self):
- """
- Destroy this URL Map
-
- :return: True if successful
- :rtype: ``bool``
- """
- return self.driver.ex_destroy_urlmap(urlmap=self)
-
-
-class GCEZone(NodeLocation):
- """Subclass of NodeLocation to provide additional information."""
- def __init__(self, id, name, status, maintenance_windows, deprecated,
- driver, extra=None):
- self.status = status
- self.maintenance_windows = maintenance_windows
- self.deprecated = deprecated
- self.extra = extra
- country = name.split('-')[0]
- super(GCEZone, self).__init__(id=str(id), name=name, country=country,
- driver=driver)
-
- @property
- def time_until_mw(self):
- """
- Returns the time until the next Maintenance Window as a
- datetime.timedelta object.
- """
- return self._get_time_until_mw()
-
- @property
- def next_mw_duration(self):
- """
- Returns the duration of the next Maintenance Window as a
- datetime.timedelta object.
- """
- return self._get_next_mw_duration()
-
- def _now(self):
- """
- Returns current UTC time.
-
- Can be overridden in unittests.
- """
- return datetime.datetime.utcnow()
-
- def _get_next_maint(self):
- """
- Returns the next Maintenance Window.
-
- :return: A dictionary containing maintenance window info (or None if
- no maintenance windows are scheduled)
- The dictionary contains 4 keys with values of type ``str``
- - name: The name of the maintenance window
- - description: Description of the maintenance window
- - beginTime: RFC3339 Timestamp
- - endTime: RFC3339 Timestamp
- :rtype: ``dict`` or ``None``
- """
- begin = None
- next_window = None
- if not self.maintenance_windows:
- return None
- if len(self.maintenance_windows) == 1:
- return self.maintenance_windows[0]
- for mw in self.maintenance_windows:
- begin_next = timestamp_to_datetime(mw['beginTime'])
- if (not begin) or (begin_next < begin):
- begin = begin_next
- next_window = mw
- return next_window
-
- def _get_time_until_mw(self):
- """
- Returns time until next maintenance window.
-
- :return: Time until next maintenance window (or None if no
- maintenance windows are scheduled)
- :rtype: :class:`datetime.timedelta` or ``None``
- """
- next_window = self._get_next_maint()
- if not next_window:
- return None
- now = self._now()
- next_begin = timestamp_to_datetime(next_window['beginTime'])
- return next_begin - now
-
- def _get_next_mw_duration(self):
- """
- Returns the duration of the next maintenance window.
-
- :return: Duration of next maintenance window (or None if no
- maintenance windows are scheduled)
- :rtype: :class:`datetime.timedelta` or ``None``
- """
- next_window = self._get_next_maint()
- if not next_window:
- return None
- next_begin = timestamp_to_datetime(next_window['beginTime'])
- next_end = timestamp_to_datetime(next_window['endTime'])
- return next_end - next_begin
-
- def __repr__(self):
- return '<GCEZone id="%s" name="%s" status="%s">' % (self.id, self.name,
- self.status)
-
-
-class GCENodeDriver(NodeDriver):
- """
- GCE Node Driver class.
-
- This is the primary driver for interacting with Google Compute Engine. It
- contains all of the standard libcloud methods, plus additional ex_* methods
- for more features.
-
- Note that many methods allow either objects or strings (or lists of
- objects/strings). In most cases, passing strings instead of objects will
- result in additional GCE API calls.
- """
- connectionCls = GCEConnection
- api_name = 'google'
- name = "Google Compute Engine"
- type = Provider.GCE
- website = 'https://cloud.google.com/'
-
- # Google Compute Engine node states are mapped to Libcloud node states
- # per the following dict. GCE does not have an actual 'stopped' state
- # but instead uses a 'terminated' state to indicate the node exists
- # but is not running. In order to better match libcloud, GCE maps this
- # 'terminated' state to 'STOPPED'.
- # Also, when a node is deleted from GCE, it no longer exists and instead
- # will result in a ResourceNotFound error versus returning a placeholder
- # node in a 'terminated' state.
- # For more details, please see GCE's docs,
- # https://cloud.google.com/compute/docs/instances#checkmachinestatus
- NODE_STATE_MAP = {
- "PROVISIONING": NodeState.PENDING,
- "STAGING": NodeState.PENDING,
- "RUNNING": NodeState.RUNNING,
- "STOPPING": NodeState.PENDING,
- "TERMINATED": NodeState.STOPPED,
- "UNKNOWN": NodeState.UNKNOWN
- }
-
- AUTH_URL = "https://www.googleapis.com/auth/"
- SA_SCOPES_MAP = {
- # list derived from 'gcloud compute instances create --help'
- "bigquery": "bigquery",
- "cloud-platform": "cloud-platform",
- "compute-ro": "compute.readonly",
- "compute-rw": "compute",
- "datastore": "datastore",
- "logging-write": "logging.write",
- "monitoring": "monitoring",
- "sql": "sqlservice",
- "sql-admin": "sqlservice.admin",
- "storage-full": "devstorage.full_control",
- "storage-ro": "devstorage.read_only",
- "storage-rw": "devstorage.read_write",
- "taskqueue": "taskqueue",
- "useraccounts-ro": "cloud.useraccounts.readonly",
- "useraccounts-rw": "cloud.useraccounts",
- "userinfo-email": "userinfo.email"
- }
-
- IMAGE_PROJECTS = {
- "centos-cloud": ["centos"],
- "coreos-cloud": ["coreos"],
- "debian-cloud": ["debian", "backports"],
- "gce-nvme": ["nvme-backports"],
- "google-containers": ["container-vm"],
- "opensuse-cloud": ["opensuse"],
- "rhel-cloud": ["rhel"],
- "suse-cloud": ["sles", "suse"],
- "ubuntu-os-cloud": ["ubuntu"],
- "windows-cloud": ["windows"],
- }
-
- def __init__(self, user_id, key=None, datacenter=None, project=None,
- auth_type=None, scopes=None, credential_file=None, **kwargs):
- """
- :param user_id: The email address (for service accounts) or Client ID
- (for installed apps) to be used for authentication.
- :type user_id: ``str``
-
- :param key: The RSA Key (for service accounts) or file path containing
- key or Client Secret (for installed apps) to be used for
- authentication.
- :type key: ``str``
-
- :keyword datacenter: The name of the datacenter (zone) used for
- operations.
- :type datacenter: ``str``
-
- :keyword project: Your GCE project name. (required)
- :type project: ``str``
-
- :keyword auth_type: Accepted values are "SA" or "IA" or "GCE"
- ("Service Account" or "Installed Application" or
- "GCE" if libcloud is being used on a GCE instance
- with service account enabled).
- If not supplied, auth_type will be guessed based
- on value of user_id or if the code is being
- executed in a GCE instance.
- :type auth_type: ``str``
-
- :keyword scopes: List of authorization URLs. Default is empty and
- grants read/write to Compute, Storage, DNS.
- :type scopes: ``list``
-
- :keyword credential_file: Path to file for caching authentication
- information used by GCEConnection.
- :type credential_file: ``str``
- """
- if not project:
- raise ValueError('Project name must be specified using '
- '"project" keyword.')
-
- self.auth_type = auth_type
- self.project = project
- self.scopes = scopes
- self.credential_file = credential_file or \
- GoogleOAuth2Credential.default_credential_file + '.' + self.project
-
- super(GCENodeDriver, self).__init__(user_id, key, **kwargs)
-
- # Cache Zone and Region information to reduce API calls and
- # increase speed
- self.base_path = '/compute/%s/projects/%s' % (API_VERSION,
- self.project)
- self.zone_list = self.ex_list_zones()
- self.zone_dict = {}
- for zone in self.zone_list:
- self.zone_dict[zone.name] = zone
- if datacenter:
- self.zone = self.ex_get_zone(datacenter)
- else:
- self.zone = None
-
- self.region_list = self.ex_list_regions()
- self.region_dict = {}
- for region in self.region_list:
- self.region_dict[region.name] = region
-
- if self.zone:
- self.region = self._get_region_from_zone(self.zone)
- else:
- self.region = None
-
- def ex_add_access_config(self, node, name, nic, nat_ip=None,
- config_type=None):
- """
- Add a network interface access configuration to a node.
-
- :keyword node: The existing target Node (instance) that will receive
- the new access config.
- :type node: ``Node``
-
- :keyword name: Name of the new access config.
- :type node: ``str``
-
- :keyword nat_ip: The external existing static IP Address to use for
- the access config. If not provided, an ephemeral
- IP address will be allocated.
- :type nat_ip: ``str`` or ``None``
-
- :keyword config_type: The type of access config to create. Currently
- the only supported type is 'ONE_TO_ONE_NAT'.
- :type config_type: ``str`` or ``None``
-
- :return: True if successful
- :rtype: ``bool``
- """
- if not isinstance(node, Node):
- raise ValueError("Must specify a valid libcloud node object.")
- node_name = node.name
- zone_name = node.extra['zone'].name
-
- config = {'name': name}
- if config_type is None:
- config_type = 'ONE_TO_ONE_NAT'
- config['type'] = config_type
-
- if nat_ip is not None:
- config['natIP'] = nat_ip
- params = {'networkInterface': nic}
- request = '/zones/%s/instances/%s/addAccessConfig' % (zone_name,
- node_name)
- self.connection.async_request(request, method='POST',
- data=config, params=params)
- return True
-
- def ex_delete_access_config(self, node, name, nic):
- """
- Delete a network interface access configuration from a node.
-
- :keyword node: The existing target Node (instance) for the request.
- :type node: ``Node``
-
- :keyword name: Name of the access config.
- :type node: ``str``
-
- :keyword nic: Name of the network interface.
- :type nic: ``str``
-
- :return: True if successful
- :rtype: ``bool``
- """
- if not isinstance(node, Node):
- raise ValueError("Must specify a valid libcloud node object.")
- node_name = node.name
- zone_name = node.extra['zone'].name
-
- params = {'accessConfig': name, 'networkInterface': nic}
- request = '/zones/%s/instances/%s/deleteAccessConfig' % (zone_name,
- node_name)
- self.connection.async_request(request, method='POST', params=params)
- return True
-
- def ex_set_node_metadata(self, node, metadata):
- """
- Set metadata for the specified node.
-
- :keyword node: The existing target Node (instance) for the request.
- :type node: ``Node``
-
- :keyword metadata: Set (or clear with None) metadata for this
- particular node.
- :type metadata: ``dict`` or ``None``
-
- :return: True if successful
- :rtype: ``bool``
- """
- if not isinstance(node, Node):
- raise ValueError("Must specify a valid libcloud node object.")
- node_name = node.name
- zone_name = node.extra['zone'].name
- if 'metadata' in node.extra and \
- 'fingerprint' in node.extra['metadata']:
- current_fp = node.extra['metadata']['fingerprint']
- else:
- current_fp = 'absent'
- body = self._format_metadata(current_fp, metadata)
- request = '/zones/%s/instances/%s/setMetadata' % (zone_name,
- node_name)
- self.connection.async_request(request, method='POST', data=body)
- return True
-
- def ex_get_serial_output(self, node):
- """
- Fetch the console/serial port output from the node.
-
- :keyword node: The existing target Node (instance) for the request.
- :type node: ``Node``
-
- :return: A string containing serial port output of the node.
- :rtype: ``str``
- """
- if not isinstance(node, Node):
- raise ValueError("Must specify a valid libcloud node object.")
- node_name = node.name
- zone_name = node.extra['zone'].name
- request = '/zones/%s/instances/%s/serialPort' % (zone_name,
- node_name)
- response = self.connection.request(request, method='GET').object
- return response['contents']
-
- def ex_list(self, list_fn, **kwargs):
- """
- Wrap a list method in a :class:`GCEList` iterator.
-
- >>> for sublist in driver.ex_list(driver.ex_list_urlmaps).page(1):
- ... sublist
- ...
- [<GCEUrlMap id="..." name="cli-map">]
- [<GCEUrlMap id="..." name="lc-map">]
- [<GCEUrlMap id="..." name="web-map">]
-
- :param list_fn: A bound list method from :class:`GCENodeDriver`.
- :type list_fn: ``instancemethod``
-
- :return: An iterator that returns sublists from list_fn.
- :rtype: :class:`GCEList`
- """
- return GCEList(driver=self, list_fn=list_fn, **kwargs)
-
- def ex_list_disktypes(self, zone=None):
- """
- Return a list of DiskTypes for a zone or all.
-
- :keyword zone: The zone to return DiskTypes from. For example:
- 'us-central1-a'. If None, will return DiskTypes from
- self.zone. If 'all', will return all DiskTypes.
- :type zone: ``str`` or ``None``
-
- :return: A list of static DiskType objects.
- :rtype: ``list`` of :class:`GCEDiskType`
- """
- list_disktypes = []
- zone = self._set_zone(zone)
- if zone is None:
- request = '/aggregated/diskTypes'
- else:
- request = '/zones/%s/diskTypes' % (zone.name)
- response = self.connection.request(request, method='GET').object
-
- if 'items' in response:
- # The aggregated result returns dictionaries for each region
- if zone is None:
- for v in response['items'].values():
- zone_disktypes = [self._to_disktype(a) for a in
- v.get('diskTypes', [])]
- list_disktypes.extend(zone_disktypes)
- else:
- list_disktypes = [self._to_disktype(a) for a in
- 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' parameter to ``True``.
-
- :param metadata: Dictionary 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:
- metadata = self._format_metadata('na', metadata)
-
- request = '/setCommonInstanceMetadata'
-
- project = self.ex_get_project()
- current_metadata = project.extra['commonInstanceMetadata']
- fingerprint = current_metadata['fingerprint']
- md_items = []
- if 'items' in current_metadata:
- md_items = current_metadata['items']
-
- # grab copy of current 'sshKeys' in case we want to retain them
- current_keys = ""
- for md in md_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.
-
- :keyword region: The region to return addresses from. For example:
- 'us-central1'. If None, will return addresses from
- region of self.zone. If 'all', will return all
- addresses. If 'global', it will return addresses in
- the global namespace.
- :type region: ``str`` or ``None``
-
- :return: A list of static address objects.
- :rtype: ``list`` of :class:`GCEAddress`
- """
- list_addresses = []
- if region != 'global':
- region = self._set_region(region)
- if region is None:
- request = '/aggregated/addresses'
- elif region == 'global':
- request = '/global/addresses'
- else:
- request = '/regions/%s/addresses' % (region.name)
- response = self.connection.request(request, method='GET').object
-
- if 'items' in response:
- # The aggregated result returns dictionaries for each region
- if region is None:
- for v in response['items'].values():
- region_addresses = [self._to_address(a) for a in
- v.get('addresses', [])]
- list_addresses.extend(region_addresses)
- else:
- list_addresses = [self._to_address(a) for a in
- response['items']]
- return list_addresses
-
- def ex_list_backendservices(self):
- """
- Return a list of backend services.
-
- :return: A list of backend service objects.
- :rtype: ``list`` of :class:`GCEBackendService`
- """
- list_backendservices = []
- response = self.connection.request('/global/backendServices',
- method='GET').object
-
- list_backendservices = [self._to_backendservice(d) for d in
- response.get('items', [])]
-
- return list_backendservices
-
- def ex_list_healthchecks(self):
- """
- Return the list of health checks.
-
- :return: A list of health check objects.
- :rtype: ``list`` of :class:`GCEHealthCheck`
- """
- list_healthchecks = []
- request = '/global/httpHealthChecks'
- response = self.connection.request(request, method='GET').object
- list_healthchecks = [self._to_healthcheck(h) for h in
- response.get('items', [])]
- return list_healthchecks
-
- def ex_list_firewalls(self):
- """
- Return the list of firewalls.
-
- :return: A list of firewall objects.
- :rtype: ``list`` of :class:`GCEFirewall`
- """
- list_firewalls = []
- request = '/global/firewalls'
- response = self.connection.request(request, method='GET').object
- list_firewalls = [self._to_firewall(f) for f in
- response.get('items', [])]
- return list_firewalls
-
- def ex_list_forwarding_rules(self, region=None, global_rules=False):
- """
- Return the list of forwarding rules for a region or all.
-
- :keyword region: The region to return forwarding rules from. For
- example: 'us-central1'. If None, will return
- forwarding rules from the region of self.region
- (which is based on self.zone). If 'all', will
- return forwarding rules for all regions, which does
- not include the global forwarding rules.
- :type region: ``str`` or :class:`GCERegion` or ``None``
-
- :keyword global_rules: List global forwarding rules instead of
- per-region rules. Setting True will cause
- 'region' parameter to be ignored.
- :type global_rules: ``bool``
-
- :return: A list of forwarding rule objects.
- :rtype: ``list`` of :class:`GCEForwardingRule`
- """
- list_forwarding_rules = []
- if global_rules:
- region = None
- request = '/global/forwardingRules'
- else:
- region = self._set_region(region)
- if region is None:
- request = '/aggregated/forwardingRules'
- else:
- request = '/regions/%s/forwardingRules' % (region.name)
- response = self.connection.request(request, method='GET').object
-
- if 'items' in response:
- # The aggregated result returns dictionaries for each region
- if not global_rules and region is None:
- for v in response['items'].values():
- region_forwarding_rules = [self._to_forwarding_rule(f) for
- f in v.get('forwardingRules',
- [])]
- list_forwarding_rules.extend(region_forwarding_rules)
- else:
- list_forwarding_rules = [self._to_forwarding_rule(f) for f in
- response['items']]
- return list_forwarding_rules
-
- def list_images(self, ex_project=None, ex_include_deprecated=False):
- """
- Return a list of image objects. If no project is specified, a list of
- all non-deprecated global and vendor images images is returned. By
- default, only non-deprecated images are returned.
-
- :keyword ex_project: Optional alternate project name.
- :type ex_project: ``str``, ``list`` of ``str``, or ``None``
-
- :keyword ex_include_deprecated: If True, even DEPRECATED images will
- be returned.
- :type ex_include_deprecated: ``bool``
-
- :return: List of GCENodeImage objects
- :rtype: ``list`` of :class:`GCENodeImage`
- """
- dep = ex_include_deprecated
- if ex_project is not None:
- return self.ex_list_project_images(ex_project=ex_project,
- ex_include_deprecated=dep)
- image_list = self.ex_list_project_images(ex_project=None,
- ex_include_deprecated=dep)
- for img_proj in list(self.IMAGE_PROJECTS.keys()):
- try:
- image_list.extend(
- self.ex_list_project_images(ex_project=img_proj,
- ex_include_deprecated=dep))
- except:
- # do not break if an OS type is invalid
- pass
- return image_list
-
- def ex_list_project_images(self, ex_project=None,
- ex_include_deprecated=False):
- """
- Return a list of image objects for a project. If no project is
- specified, only a list of 'global' images is returned.
-
- :keyword ex_project: Optional alternate project name.
- :type ex_project: ``str``, ``list`` of ``str``, or ``None``
-
- :keyword ex_include_deprecated: If True, even DEPRECATED images will
- be returned.
- :type ex_include_deprecated: ``bool``
-
- :return: List of GCENodeImage objects
- :rtype: ``list`` of :class:`GCENodeImage`
- """
- list_images = []
- request = '/global/images'
- if ex_project is None:
- response = self.connection.request(request, method='GET').object
- for img in response.get('items', []):
- if 'deprecated' not in img:
- list_images.append(self._to_node_image(img))
- else:
- if ex_include_deprecated:
- list_images.append(self._to_node_image(img))
- else:
- list_images = []
- # Save the connection request_path
- save_request_path = self.connection.request_path
- if isinstance(ex_project, str):
- ex_project = [ex_project]
- for proj in ex_project:
- # Override the connection request path
- new_request_path = save_request_path.replace(self.project,
- proj)
- self.connection.request_path = new_request_path
- try:
- response = self.connection.request(request,
- method='GET').object
- except:
- raise
- finally:
- # Restore the connection request_path
- self.connection.request_path = save_request_path
- for img in response.get('items', []):
- if 'deprecated' not in img:
- list_images.append(self._to_node_image(img))
- else:
- if ex_include_deprecated:
- list_images.append(self._to_node_image(img))
- return list_images
-
- def list_locations(self):
- """
- Return a list of locations (zones).
-
- The :class:`ex_list_zones` method returns more comprehensive results,
- but this is here for compatibility.
-
- :return: List of NodeLocation objects
- :rtype: ``list`` of :class:`NodeLocation`
- """
- list_locations = []
- request = '/zones'
- response = self.connection.request(request, method='GET').object
- list_locations = [self._to_node_location(l) for l in response['items']]
- return list_locations
-
- def ex_list_routes(self):
- """
- Return the list of routes.
-
- :return: A list of route objects.
- :rtype: ``list`` of :class:`GCERoute`
- """
- list_routes = []
- request = '/global/routes'
- response = self.connection.request(request, method='GET').object
- list_routes = [self._to_route(n) for n in
- response.get('items', [])]
- return list_routes
-
- def ex_list_networks(self):
- """
- Return the list of networks.
-
- :return: A list of network objects.
- :rtype: ``list`` of :class:`GCENetwork`
- """
- list_networks = []
- request = '/global/networks'
- response = self.connection.request(request, method='GET').object
- list_networks = [self._to_network(n) for n in
- response.get('items', [])]
- return list_networks
-
- def list_nodes(self, ex_zone=None):
- """
- Return a list of nodes in the current zone or all zones.
-
- :keyword ex_zone: Optional zone name or 'all'
- :type ex_zone: ``str`` or :class:`GCEZone` or
- :class:`NodeLocation` or ``None``
-
- :return: List of Node objects
- :rtype: ``list`` of :class:`Node`
- """
- list_nodes = []
- zone = self._set_zone(ex_zone)
- if zone is None:
- request = '/aggregated/instances'
- else:
- request = '/zones/%s/instances' % (zone.name)
-
- response = self.connection.request(request, method='GET').object
-
- if 'items' in response:
- # The aggregated response returns a dict for each zone
- if zone is None:
- for v in response['items'].values():
- for i in v.get('instances', []):
- try:
- list_nodes.append(self._to_node(i))
- # If a GCE node has been deleted between
- # - is was listed by `request('.../instances', 'GET')
- # - it is converted by `self._to_node(i)`
- # `_to_node()` will raise a ResourceNotFoundError.
- #
- # Just ignore that node and return the list of the
- # other nodes.
- except ResourceNotFoundError:
- pass
- else:
- for i in response['items']:
- try:
- list_nodes.append(self._to_node(i))
- # If a GCE node has been deleted between
- # - is was listed by `request('.../instances', 'GET')
- # - it is converted by `self._to_node(i)`
- # `_to_node()` will raise a ResourceNotFoundError.
- #
- # Just ignore that node and return the list of the
- # other nodes.
- except ResourceNotFoundError:
- pass
- return list_nodes
-
- def ex_list_regions(self):
- """
- Return the list of regions.
-
- :return: A list of region objects.
- :rtype: ``list`` of :class:`GCERegion`
- """
- list_regions = []
- request = '/regions'
- response = self.connection.request(request, method='GET').object
- list_regions = [self._to_region(r) for r in response['items']]
- return list_regions
-
- def list_sizes(self, location=None):
- """
- Return a list of sizes (machineTypes) in a zone.
-
- :keyword location: Location or Zone for sizes
- :type location: ``str`` or :class:`GCEZone` or
- :class:`NodeLocation` or ``None``
-
- :return: List of GCENodeSize objects
- :rtype: ``list`` of :class:`GCENodeSize`
- """
- list_sizes = []
- zone = self._set_zone(location)
- if zone is None:
- request = '/aggregated/machineTypes'
- else:
- request = '/zones/%s/machineTypes' % (zone.name)
-
- response = self.connection.request(request, method='GET').object
-
- if 'items' in response:
- # The aggregated response returns a dict for each zone
- if zone is None:
- for v in response['items'].values():
- zone_sizes = [self._to_node_size(s) for s in
- v.get('machineTypes', [])]
- list_sizes.extend(zone_sizes)
- else:
- list_sizes = [self._to_node_size(s) for s in response['items']]
- return list_sizes
-
- def ex_list_snapshots(self):
- """
- Return the list of disk snapshots in the project.
-
- :return: A list of snapshot objects
- :rtype: ``list`` of :class:`GCESnapshot`
- """
- list_snapshots = []
- request = '/global/snapshots'
- response = self.connection.request(request, method='GET').object
- list_snapshots = [self._to_snapshot(s) for s in
- response.get('items', [])]
- return list_snapshots
-
- def ex_list_targethttpproxies(self):
- """
- Return the list of target HTTP proxies.
-
- :return: A list of target http proxy objects
- :rtype: ``list`` of :class:`GCETargetHttpProxy`
- """
- request = '/global/targetHttpProxies'
- response = self.connection.request(request, method='GET').object
- return [self._to_targethttpproxy(u) for u in
- response.get('items', [])]
-
- def ex_list_targetinstances(self, zone=None):
- """
- Return the list of target instances.
-
- :return: A list of target instance objects
- :rtype: ``list`` of :class:`GCETargetInstance`
- """
- list_targetinstances = []
- zone = self._set_zone(zone)
- if zone is None:
- request = '/aggregated/targetInstances'
- else:
- request = '/zones/%s/targetInstances' % (zone.name)
- response = self.connection.request(request, method='GET').object
-
- if 'items' in response:
- # The aggregated result returns dictionaries for each region
- if zone is None:
- for v in response['items'].values():
- zone_targetinstances = [self._to_targetinstance(t) for t in
- v.get('targetInstances', [])]
- list_targetinstances.extend(zone_targetinstances)
- else:
- list_targetinstances = [self._to_targetinstance(t) for t in
- response['items']]
- return list_targetinstances
-
- def ex_list_targetpools(self, region=None):
- """
- Return the list of target pools.
-
- :return: A list of target pool objects
- :rtype: ``list`` of :class:`GCETargetPool`
- """
- list_targetpools = []
- region = self._set_region(region)
- if region is None:
- request = '/aggregated/targetPools'
- else:
- request = '/regions/%s/targetPools' % (region.name)
- response = self.connection.request(request, method='GET').object
-
- if 'items' in response:
- # The aggregated result returns dictionaries for each region
- if region is None:
- for v in response['items'].values():
- region_targetpools = [self._to_targetpool(t) for t in
- v.get('targetPools', [])]
- list_targetpools.extend(region_targetpools)
- else:
- list_targetpools = [self._to_targetpool(t) for t in
- response['items']]
- return list_targetpools
-
- def ex_list_urlmaps(self):
- """
- Return the list of URL Maps in the project.
-
- :return: A list of url map objects
- :rtype: ``list`` of :class:`GCEUrlMap`
- """
- request = '/global/urlMaps'
- response = self.connection.request(request, method='GET').object
- return [self._to_urlmap(u) for u in response.get('items', [])]
-
- def list_volumes(self, ex_zone=None):
- """
- Return a list of volumes for a zone or all.
-
- Will return list from provided zone, or from the default zone unless
- given the value of 'all'.
-
- :keyword ex_zone: The zone to return volumes from.
- :type ex_zone: ``str`` or :class:`GCEZone` or
- :class:`NodeLocation` or ``None``
-
- :return: A list of volume objects.
- :rtype: ``list`` of :class:`StorageVolume`
- """
- list_volumes = []
- zone = self._set_zone(ex_zone)
- if zone is None:
- request = '/aggregated/disks'
- else:
- request = '/zones/%s/disks' % (zone.name)
-
- response = self.connection.request(request, method='GET').object
- if 'items' in response:
- # The aggregated response returns a dict for each zone
- if zone is None:
- for v in response['items'].values():
- zone_volumes = [self._to_storage_volume(d) for d in
- v.get('disks', [])]
- list_volumes.extend(zone_volumes)
- else:
- list_volumes = [self._to_storage_volume(d) for d in
- response['items']]
- return list_volumes
-
- def ex_list_zones(self):
- """
- Return the list of zones.
-
- :return: A list of zone objects.
- :rtype: ``list`` of :class:`GCEZone`
- """
- list_zones = []
- request = '/zones'
- response = self.connection.request(request, method='GET').object
- list_zones = [self._to_zone(z) for z in response['items']]
- return list_zones
-
- def ex_create_address(self, name, region=None, address=None,
- description=None):
- """
- Create a static address in a region, or a global address.
-
- :param name: Name of static address
- :type name: ``str``
-
- :keyword region: Name of region for the address (e.g. 'us-central1')
- Use 'global' to create a global address.
- :type region: ``str`` or :class:`GCERegion`
-
- :keyword address: Ephemeral IP address to promote to a static one
- (e.g. 'xxx.xxx.xxx.xxx')
- :type address: ``str`` or ``None``
-
- :keyword description: Optional descriptive comment.
- :type description: ``str`` or ``None``
-
- :return: Static Address object
- :rtype: :class:`GCEAddress`
- """
- region = region or self.region
- if region != 'global' and not hasattr(region, 'name'):
- region = self.ex_get_region(region)
- elif region is None:
- raise ValueError('REGION_NOT_SPECIFIED',
- 'Region must be provided for an address')
- address_data = {'name': name}
- if address:
- address_data['address'] = address
- if description:
- address_data['description'] = description
- if region == 'global':
- request = '/global/addresses'
- else:
- request = '/regions/%s/addresses' % (region.name)
- self.connection.async_request(request, method='POST',
- data=address_data)
- return self.ex_get_address(name, region=region)
-
- def ex_create_backendservice(self, name, healthchecks):
- """
- Create a global backend service.
-
- :param name: Name of the backend service
- :type name: ``str``
-
- :keyword healthchecks: A list of HTTP Health Checks to use for this
- service. There must be at least one.
- :type healthchecks: ``list`` of (``str`` or
- :class:`GCEHealthCheck`)
-
- :return: A Backend Service object
- :rtype: :class:`GCEBackendService`
- """
- backendservice_data = {'name': name, 'healthChecks': []}
-
- for hc in healthchecks:
- if not hasattr(hc, 'extra'):
- hc = self.ex_get_healthcheck(name=hc)
- backendservice_data['healthChecks'].append(hc.extra['selfLink'])
-
- request = '/global/backendServices'
- self.connection.async_request(request, method='POST',
- data=backendservice_data)
- return self.ex_get_backendservice(name)
-
- def ex_create_healthcheck(self, name, host=None, path=None, port=None,
- interval=None, timeout=None,
- unhealthy_threshold=None,
- healthy_threshold=None,
- description=None):
- """
- Create an Http Health Check.
-
- :param name: Name of health check
- :type name: ``str``
-
- :keyword host: Hostname of health check request. Defaults to empty
- and public IP is used instead.
- :type host: ``str``
-
- :keyword path: The request path for the check. Defaults to /.
- :type path: ``str``
-
- :keyword port: The TCP port number for the check. Defaults to 80.
- :type port: ``int``
-
- :keyword interval: How often (in seconds) to check. Defaults to 5.
- :type interval: ``int``
-
- :keyword timeout: How long to wait before failing. Defaults to 5.
- :type timeout: ``int``
-
- :keyword unhealthy_threshold: How many failures before marking
- unhealthy. Defaults to 2.
- :type unhealthy_threshold: ``int``
-
- :keyword healthy_threshold: How many successes before marking as
- healthy. Defaults to 2.
- :type healthy_threshold: ``int``
-
- :keyword description: The description of the check. Defaults to None.
- :type description: ``str`` or ``None``
-
- :return: Health Check object
- :rtype: :class:`GCEHealthCheck`
- """
- hc_data = {}
- hc_data['name'] = name
- if host:
- hc_data['host'] = host
- if description:
- hc_data['description'] = description
- # As of right now, the 'default' values aren't getting set when called
- # through the API, so set them explicitly
- hc_data['requestPath'] = path or '/'
- hc_data['port'] = port or 80
- hc_data['checkIntervalSec'] = interval or 5
- hc_data['timeoutSec'] = timeout or 5
- hc_data['unhealthyThreshold'] = unhealthy_threshold or 2
- hc_data['healthyThreshold'] = healthy_threshold or 2
-
- request = '/global/httpHealthChecks'
-
- self.connection.async_request(request, method='POST', data=hc_data)
- return self.ex_get_healthcheck(name)
-
- def ex_create_firewall(self, name, allowed, network='default',
- source_ranges=None, source_tags=None,
- target_tags=None):
- """
- Create a firewall on a network.
-
- Firewall rules should be supplied in the "allowed" field. This is a
- list of dictionaries formated like so ("ports" is optional)::
-
- [{"IPProtocol": "<protocol string or number>",
- "ports": "<port_numbers or ranges>"}]
-
- For example, to allow tcp on port 8080 and udp on all ports, 'allowed'
- would be::
-
- [{"IPProtocol": "tcp",
- "ports": ["8080"]},
- {"IPProtocol": "udp"}]
-
- See `Firewall Reference <https://developers.google.com/compute/docs/
- reference/latest/firewalls/insert>`_ for more information.
-
- :param name: Name of the firewall to be created
- :type name: ``str``
-
- :param allowed: List of dictionaries with rules
- :type allowed: ``list`` of ``dict``
-
- :keyword network: The network that the firewall applies to.
- :type network: ``str`` or :class:`GCENetwork`
-
- :keyword source_ranges: A list of IP ranges in CIDR format that the
- firewall should apply to. Defaults to
- ['0.0.0.0/0']
- :type source_ranges: ``list`` of ``str``
-
- :keyword source_tags: A list of source instance tags the rules apply
- to.
- :type source_tags: ``list`` of ``str``
-
- :keyword target_tags: A list of target instance tags the rules apply
- to.
- :type target_tags: ``list`` of ``str``
-
- :return: Firewall object
- :rtype: :class:`GCEFirewall`
- """
- firewall_data = {}
- if not hasattr(network, 'name'):
- nw = self.ex_get_network(network)
- else:
- nw = network
-
- firewall_data['name'] = name
- firewall_data['allowed'] = allowed
- firewall_data['network'] = nw.extra['selfLink']
- if source_ranges is None and source_tags is None:
- source_ranges = ['0.0.0.0/0']
- if source_ranges is not None:
- firewall_data['sourceRanges'] = source_ranges
- if source_tags is not None:
- firewall_data['sourceTags'] = source_tags
- if target_tags is not None:
- firewall_data['targetTags'] = target_tags
-
- request = '/global/firewalls'
-
- self.connection.async_request(request, method='POST',
- data=firewall_data)
- return self.ex_get_firewall(name)
-
- def ex_create_forwarding_rule(self, name, target=None, region=None,
- protocol='tcp', port_range=None,
- address=None, description=None,
- global_rule=False, targetpool=None):
- """
- Create a forwarding rule.
-
- :param name: Name of forwarding rule to be created
- :type name: ``str``
-
- :keyword target: The target of this forwarding rule. For global
- forwarding rules this must be a global
- TargetHttpProxy. For regional rules this may be
- either a TargetPool or TargetInstance. If passed
- a string instead of the object, it will be the name
- of a TargetHttpProxy for global rules or a
- TargetPool for regional rules. A TargetInstance
- must be passed by object. (required)
- :type target: ``str`` or :class:`GCETargetHttpProxy` or
- :class:`GCETargetInstance` or :class:`GCETargetPool`
-
- :keyword region: Region to create the forwarding rule in. Defaults to
- self.region. Ignored if global_rule is True.
- :type region: ``str`` or :class:`GCERegion`
-
- :keyword protocol: Should be 'tcp' or 'udp'
- :type protocol: ``str``
-
- :keyword port_range: Single port number or range separated by a dash.
- Examples: '80', '5000-5999'. Required for global
- forwarding rules, optional for regional rules.
- :type port_range: ``str``
-
- :keyword address: Optional static address for forwarding rule. Must be
- in same region.
- :type address: ``str`` or :class:`GCEAddress`
-
- :keyword description: The description of the forwarding rule.
- Defaults to None.
- :type description: ``str`` or ``None``
-
- :keyword targetpool: Deprecated parameter for backwards compatibility.
- Use target instead.
- :type targetpool: ``str`` or :class:`GCETargetPool`
-
- :return: Forwarding Rule object
- :rtype: :class:`GCEForwardingRule`
- """
- forwarding_rule_data = {'name': name}
- if global_rule:
- if not hasattr(target, 'name'):
- target = self.ex_get_targethttpproxy(target)
- else:
- region = region or self.region
- if not hasattr(region, 'name'):
- region = self.ex_get_region(region)
- forwarding_rule_data['region'] = region.extra['selfLink']
-
- if not target:
- target = targetpool # Backwards compatibility
- if not hasattr(target, 'name'):
- target = self.ex_get_targetpool(target, region)
-
- forwarding_rule_data['target'] = target.extra['selfLink']
- forwarding_rule_data['IPProtocol'] = protocol.upper()
- if address:
- if not hasattr(address, 'name'):
- address = self.ex_get_address(
- address, 'global' if global_rule else region)
- forwarding_rule_data['IPAddress'] = address.address
- if port_range:
- forwarding_rule_data['portRange'] = port_range
- if description:
- forwarding_rule_data['description'] = description
-
- if global_rule:
- request = '/global/forwardingRules'
- else:
- request = '/regions/%s/forwardingRules' % (region.name)
-
- self.connection.async_request(request, method='POST',
- data=forwarding_rule_data)
-
- return self.ex_get_forwarding_rule(name, global_rule=global_rule)
-
- def ex_create_image(self, name, volume, description=None, family=None,
- use_existing=True, wait_for_completion=True):
- """
- Create an image from the provided volume.
-
- :param name: The name of the image to create.
- :type name: ``str``
-
- :param volume: The volume to use to create the image, or the
- Google Cloud Storage URI
- :type volume: ``str`` or :class:`StorageVolume`
-
- :keyword description: Description of the new Image
- :type description: ``str``
-
- :keyword family: The name of the image family to which this image
- belongs. If you create resources by specifying an
- image family instead of a specific image name, the
- resource uses the latest non-deprecated image that
- is set with that family name.
- :type family: ``str``
-
- :keyword use_existing: If True and an image with the given name
- already exists, return an object for that
- image instead of attempting to create
- a new image.
- :type use_existing: ``bool``
-
- :keyword wait_for_completion: If True, wait until the new image is
- created before returning a new NodeImage
- Otherwise, return a new NodeImage
- instance, and let the user track the
- creation progress
- :type wait_for_completion: ``bool``
-
- :return: A GCENodeImage object for the new image
- :rtype: :class:`GCENodeImage`
-
- """
- image_data = {}
- image_data['name'] = name
- image_data['description'] = description
- image_data['family'] = family
- if isinstance(volume, StorageVolume):
- image_data['sourceDisk'] = volume.extra['selfLink']
- image_data['zone'] = volume.extra['zone'].name
- elif (isinstance(volume, str) and
- volume.startswith('https://') and
- volume.endswith('tar.gz')):
- image_data['rawDisk'] = {'source': volume, 'containerType': 'TAR'}
- else:
- raise ValueError('Source must be instance of StorageVolume or URI')
-
- request = '/global/images'
-
- try:
- if wait_for_completion:
- self.connection.async_request(request, method='POST',
- data=image_data)
- else:
- self.connection.request(request, method='POST',
- data=image_data)
-
- except ResourceExistsError:
- e = sys.exc_info()[1]
- if not use_existing:
- raise e
-
- return self.ex_get_image(name)
-
- def ex_create_route(self, name, dest_range, priority=500,
- network="default", tags=None, next_hop=None,
- description=None):
- """
- Create a route.
-
- :param name: Name of route to be created
- :type name: ``str``
-
- :param dest_range: Address range of route in CIDR format.
- :type dest_range: ``str``
-
- :param priority: Priority value, lower values take precedence
- :type priority: ``int``
-
- :param network: The network the route belongs to. Can be either the
- full URL of the network or a libcloud object.
- :type network: ``str`` or ``GCENetwork``
-
- :param tags: List of instance-tags for routing, empty for all nodes
- :type tags: ``list`` of ``str`` or ``None``
-
- :param next_hop: Next traffic hop. Use ``None`` for the default
- Internet gateway, or specify an instance or IP
- address.
- :type next_hop: ``str``, ``Node``, or ``None``
-
- :param description: Custom description for the route.
- :type description: ``str`` or ``None``
-
- :return: Route object
- :rtype: :class:`GCERoute`
- """
- route_data = {}
- route_data['name'] = name
- route_data['destRange'] = dest_range
- route_data['priority'] = priority
- route_data['description'] = description
- if isinstance(network, str) and network.startswith('https://'):
- network_uri = network
- elif isinstance(network, str):
- network = self.ex_get_network(network)
- network_uri = network.extra['selfLink']
- else:
- network_uri = network.extra['selfLink']
- route_data['network'] = network_uri
- route_data['tags'] = tags
- if next_hop is None:
- url = 'https://www.googleapis.com/compute/%s/projects/%s/%s' % (
- API_VERSION, self.project,
- "global/gateways/default-internet-gateway")
- route_data['nextHopGateway'] = url
- elif isinstance(next_hop, str):
- route_data['nextHopIp'] = next_hop
- else:
- route_data['nextHopInstance'] = next_hop.extra['selfLink']
-
- request = '/global/routes'
- self.connection.async_request(request, method='POST',
- data=route_data)
-
- return self.ex_get_route(name)
-
- def ex_create_network(self, name, cidr, description=None):
- """
- Create a network.
-
- :param name: Name of network to be created
- :type name: ``str``
-
- :param cidr: Address range of network in CIDR format.
- :type cidr: ``str``
-
- :param description: Custom description for the network.
- :type description: ``str`` or ``None``
-
- :return: Network object
- :rtype: :class:`GCENetwork`
- """
- network_data = {}
- network_data['name'] = name
- network_data['IPv4Range'] = cidr
- network_data['description'] = description
-
- request = '/global/networks'
-
- self.connection.async_request(request, method='POST',
- data=network_data)
-
- return self.ex_get_network(name)
-
- def create_node(self, name, size, image, location=None,
- ex_network='default', ex_tags=None, ex_metadata=None,
- ex_boot_disk=None, use_existing_disk=True,
- external_ip='ephemeral', ex_disk_type='pd-standard',
- ex_disk_auto_delete=True, ex_service_accounts=None,
- description=None, ex_can_ip_forward=None,
- ex_disks_gce_struct=None, ex_nic_gce_struct=None,
- ex_on_host_maintenance=None, ex_automatic_restart=None,
- ex_preemptible=None):
- """
- Create a new node and return a node object for the node.
-
- :param name: The name of the node to create.
- :type name: ``str``
-
- :param size: The machine type to use.
- :type size: ``str`` or :class:`GCENodeSize`
-
- :param image: The image to use to create the node (or, if attaching
- a persistent disk, the image used to create the disk)
- :type image: ``str`` or :class:`GCENodeImage` or ``None``
-
- :keyword location: The location (zone) to create the node in.
- :type location: ``str`` or :class:`NodeLocation` or
- :class:`GCEZone` or ``None``
-
- :keyword ex_network: The network to associate with the node.
-
<TRUNCATED>