http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/cloudwatt.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/cloudwatt.py b/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/cloudwatt.py deleted file mode 100644 index fe256f7..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/cloudwatt.py +++ /dev/null @@ -1,154 +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. - -""" -Cloudwatt driver. -""" -import sys -try: - import simplejson as json -except ImportError: - import json -from libcloud.utils.py3 import httplib -from libcloud.compute.types import Provider -from libcloud.compute.drivers.openstack import OpenStack_1_1_Connection -from libcloud.compute.drivers.openstack import OpenStack_1_1_NodeDriver -from libcloud.common.openstack_identity import OpenStackIdentityConnection -from libcloud.utils.iso8601 import parse_date - -from libcloud.compute.types import InvalidCredsError, MalformedResponseError - - -__all__ = [ - 'CloudwattNodeDriver' -] - -BASE_URL = 'https://identity.fr1.cloudwatt.com/v2.0' -AUTH_URL = BASE_URL + '/tokens' - - -class CloudwattAuthConnection(OpenStackIdentityConnection): - """ - AuthConnection class for the Cloudwatt driver. - """ - name = 'Cloudwatt Auth' - - def __init__(self, *args, **kwargs): - self._ex_tenant_id = kwargs.pop('ex_tenant_id') - super(CloudwattAuthConnection, self).__init__(*args, **kwargs) - - def authenticate(self, force=False): - reqbody = json.dumps({'auth': { - 'passwordCredentials': { - 'username': self.user_id, - 'password': self.key - }, - 'tenantId': self._ex_tenant_id - }}) - resp = self.request('/tokens', data=reqbody, headers={}, - method='POST') - - if resp.status == httplib.UNAUTHORIZED: - # HTTP UNAUTHORIZED (401): auth failed - raise InvalidCredsError() - elif resp.status != httplib.OK: - body = 'code: %s body:%s' % (resp.status, resp.body) - raise MalformedResponseError('Malformed response', body=body, - driver=self.driver) - else: - try: - body = json.loads(resp.body) - except Exception: - e = sys.exc_info()[1] - raise MalformedResponseError('Failed to parse JSON', e) - - try: - expires = body['access']['token']['expires'] - - self.auth_token = body['access']['token']['id'] - self.auth_token_expires = parse_date(expires) - self.urls = body['access']['serviceCatalog'] - self.auth_user_info = None - except KeyError: - e = sys.exc_info()[1] - raise MalformedResponseError('Auth JSON response is \ - missing required elements', e) - - return self - - -class CloudwattConnection(OpenStack_1_1_Connection): - """ - Connection class for the Cloudwatt driver. - """ - auth_url = BASE_URL - service_region = 'fr1' - service_type = 'compute' - - def __init__(self, *args, **kwargs): - self.ex_tenant_id = kwargs.pop('ex_tenant_id') - super(CloudwattConnection, self).__init__(*args, **kwargs) - osa = CloudwattAuthConnection( - auth_url=AUTH_URL, - user_id=self.user_id, - key=self.key, - tenant_name=self._ex_tenant_name, - timeout=self.timeout, - ex_tenant_id=self.ex_tenant_id, - parent_conn=self - ) - self._osa = osa - self._auth_version = '2.0' - - -class CloudwattNodeDriver(OpenStack_1_1_NodeDriver): - """ - Implements the :class:`NodeDriver`'s for Cloudwatt. - """ - name = 'Cloudwatt' - website = 'https://www.cloudwatt.com/' - connectionCls = CloudwattConnection - type = Provider.CLOUDWATT - - def __init__(self, key, secret, tenant_id, secure=True, tenant_name=None, - host=None, port=None, **kwargs): - """ - @inherits: :class:`NodeDriver.__init__` - - :param tenant_id: ID of tenant required for Cloudwatt auth - :type tenant_id: ``str`` - """ - self.ex_tenant_id = tenant_id - self.extra = {} - super(CloudwattNodeDriver, self).__init__( - key=key, - secret=secret, - secure=secure, - host=host, - port=port, - **kwargs - ) - - def attach_volume(self, node, volume, device=None): - return super(CloudwattNodeDriver, self)\ - .attach_volume(node, volume, device) - - def _ex_connection_class_kwargs(self): - """ - Includes ``tenant_id`` in Connection. - """ - return { - 'ex_tenant_id': self.ex_tenant_id - }
http://git-wip-us.apache.org/repos/asf/libcloud/blob/8afcda91/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/digitalocean.py ---------------------------------------------------------------------- diff --git a/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/digitalocean.py b/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/digitalocean.py deleted file mode 100644 index 0428cbb..0000000 --- a/apache-libcloud-1.0.0rc2/libcloud/compute/drivers/digitalocean.py +++ /dev/null @@ -1,592 +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. -""" -DigitalOcean Driver -""" -import json -import warnings - -from libcloud.utils.iso8601 import parse_date -from libcloud.utils.py3 import httplib - -from libcloud.common.digitalocean import DigitalOcean_v1_BaseDriver -from libcloud.common.digitalocean import DigitalOcean_v2_BaseDriver -from libcloud.common.types import InvalidCredsError -from libcloud.compute.types import Provider, NodeState -from libcloud.compute.base import NodeImage, NodeSize, NodeLocation, KeyPair -from libcloud.compute.base import Node, NodeDriver - -__all__ = [ - 'DigitalOceanNodeDriver', - 'DigitalOcean_v1_NodeDriver', - 'DigitalOcean_v2_NodeDriver' -] - - -class DigitalOceanNodeDriver(NodeDriver): - """ - DigitalOcean NodeDriver defaulting to using APIv2. - - :keyword key: Required for authentication. Used in both ``v1`` and - ``v2`` implementations. - :type key: ``str`` - - :keyword secret: Used in driver authentication with key. Defaults to - None and when set, will cause driver to use ``v1`` for - connection and response. (optional) - :type secret: ``str`` - - :keyword api_version: Specifies the API version to use. ``v1`` and - ``v2`` are the only valid options. Defaults to - using ``v2`` (optional) - :type api_version: ``str`` - """ - type = Provider.DIGITAL_OCEAN - name = 'DigitalOcean' - website = 'https://www.digitalocean.com' - - def __new__(cls, key, secret=None, api_version='v2', **kwargs): - if cls is DigitalOceanNodeDriver: - if api_version == 'v1' or secret is not None: - if secret is None: - raise InvalidCredsError( - 'secret missing for v1 authentication') - if secret is not None and api_version == 'v2': - raise InvalidCredsError( - 'secret not accepted for v2 authentication') - cls = DigitalOcean_v1_NodeDriver - elif api_version == 'v2': - cls = DigitalOcean_v2_NodeDriver - else: - raise NotImplementedError('Unsupported API version: %s' % - (api_version)) - return super(DigitalOceanNodeDriver, cls).__new__(cls, **kwargs) - - -# TODO Implement v1 driver using KeyPair -class SSHKey(object): - def __init__(self, id, name, pub_key): - self.id = id - self.name = name - self.pub_key = pub_key - - def __repr__(self): - return (('<SSHKey: id=%s, name=%s, pub_key=%s>') % - (self.id, self.name, self.pub_key)) - - -class DigitalOcean_v1_NodeDriver(DigitalOcean_v1_BaseDriver, - DigitalOceanNodeDriver): - """ - DigitalOcean NodeDriver using v1 of the API. - """ - - NODE_STATE_MAP = {'new': NodeState.PENDING, - 'off': NodeState.REBOOTING, - 'active': NodeState.RUNNING} - - def list_nodes(self): - data = self.connection.request('/v1/droplets').object['droplets'] - return list(map(self._to_node, data)) - - def list_locations(self): - data = self.connection.request('/v1/regions').object['regions'] - return list(map(self._to_location, data)) - - def list_images(self): - data = self.connection.request('/v1/images').object['images'] - return list(map(self._to_image, data)) - - def list_sizes(self): - data = self.connection.request('/v1/sizes').object['sizes'] - return list(map(self._to_size, data)) - - def create_node(self, name, size, image, location, ex_ssh_key_ids=None): - """ - Create a node. - - :keyword ex_ssh_key_ids: A list of ssh key ids which will be added - to the server. (optional) - :type ex_ssh_key_ids: ``list`` of ``str`` - - :return: The newly created node. - :rtype: :class:`Node` - """ - params = {'name': name, 'size_id': size.id, 'image_id': image.id, - 'region_id': location.id} - - if ex_ssh_key_ids: - params['ssh_key_ids'] = ','.join(ex_ssh_key_ids) - - data = self.connection.request('/v1/droplets/new', params=params) - - # TODO: Handle this in the response class - status = data.object.get('status', 'OK') - if status == 'ERROR': - message = data.object.get('message', None) - error_message = data.object.get('error_message', message) - raise ValueError('Failed to create node: %s' % (error_message)) - - return self._to_node(data=data.object['droplet']) - - def reboot_node(self, node): - res = self.connection.request('/v1/droplets/%s/reboot/' % (node.id)) - return res.status == httplib.OK - - def destroy_node(self, node): - params = {'scrub_data': '1'} - res = self.connection.request('/v1/droplets/%s/destroy/' % (node.id), - params=params) - return res.status == httplib.OK - - def ex_rename_node(self, node, name): - params = {'name': name} - res = self.connection.request('/v1/droplets/%s/rename/' % (node.id), - params=params) - return res.status == httplib.OK - - def list_key_pairs(self): - """ - List all the available SSH keys. - - :return: Available SSH keys. - :rtype: ``list`` of :class:`KeyPair` - """ - data = self.connection.request('/v1/ssh_keys').object['ssh_keys'] - return list(map(self._to_key_pair, data)) - - def ex_list_ssh_keys(self): - """ - List all the available SSH keys. - :return: Available SSH keys. - :rtype: ``list`` of :class:`SSHKey` - """ - warnings.warn("This method has been deprecated in " - "favor of the list_key_pairs method") - - data = self.connection.request('/v1/ssh_keys').object['ssh_keys'] - return list(map(self._to_ssh_key, data)) - - def get_key_pair(self, name): - """ - Retrieve a single key pair. - - :param name: Name of the key pair to retrieve. - :type name: ``str`` - - :rtype: :class:`.KeyPair` - """ - qkey = [k for k in self.list_key_pairs() if k.name == name][0] - data = self.connection.request('/v1/ssh_keys/%s' % - qkey.extra['id']).object['ssh_key'] - return self._to_key_pair(data=data) - - # TODO: This adds the ssh_key_pub parameter. This puts the burden of making - # it within the function or on the API. The KeyPair API needs work. - def create_key_pair(self, name, ssh_key_pub): - """ - Create a new SSH key. - - :param name: Key name (required) - :type name: ``str`` - - :param name: Valid public key string (required) - :type name: ``str`` - """ - params = {'name': name, 'ssh_pub_key': ssh_key_pub} - data = self.connection.request('/v1/ssh_keys/new/', method='GET', - params=params).object - assert 'ssh_key' in data - # TODO: libcloud.compute.base.KeyPair.create_key_pair doesn't specify - # a return value. This looks like it should return a KeyPair - return self._to_key_pair(data=data['ssh_key']) - - def ex_create_ssh_key(self, name, ssh_key_pub): - """ - Create a new SSH key. - :param name: Key name (required) - :type name: ``str`` - :param name: Valid public key string (required) - :type name: ``str`` - """ - warnings.warn("This method has been deprecated in " - "favor of the create_key_pair method") - - params = {'name': name, 'ssh_pub_key': ssh_key_pub} - data = self.connection.request('/v1/ssh_keys/new/', method='GET', - params=params).object - assert 'ssh_key' in data - return self._to_ssh_key(data=data['ssh_key']) - - def delete_key_pair(self, key_pair): - """ - Delete an existing key pair. - - :param key_pair: Key pair object. - :type key_pair: :class:`.KeyPair` - """ - res = self.connection.request('/v1/ssh_keys/%s/destroy/' % - key_pair.extra['id']) - # TODO: This looks like it should return bool like the other delete_* - return res.status == httplib.OK - - def ex_destroy_ssh_key(self, key_id): - """ - Delete an existing SSH key. - :param key_id: SSH key id (required) - :type key_id: ``str`` - """ - warnings.warn( - "This method has been deprecated in " - "favor of the delete_key_pair method") - - res = self.connection.request('/v1/ssh_keys/%s/destroy/' % (key_id)) - return res.status == httplib.OK - - def _to_node(self, data): - extra_keys = ['backups_active', 'region_id', 'image_id', 'size_id'] - if 'status' in data: - state = self.NODE_STATE_MAP.get(data['status'], NodeState.UNKNOWN) - else: - state = NodeState.UNKNOWN - - if 'ip_address' in data and data['ip_address'] is not None: - public_ips = [data['ip_address']] - else: - public_ips = [] - - extra = {} - for key in extra_keys: - if key in data: - extra[key] = data[key] - - node = Node(id=data['id'], name=data['name'], state=state, - public_ips=public_ips, private_ips=None, extra=extra, - driver=self) - return node - - def _to_image(self, data): - extra = {'distribution': data['distribution']} - return NodeImage(id=data['id'], name=data['name'], extra=extra, - driver=self) - - def _to_location(self, data): - return NodeLocation(id=data['id'], name=data['name'], country=None, - driver=self) - - def _to_size(self, data): - ram = data['name'].lower() - - if 'mb' in ram: - ram = int(ram.replace('mb', '')) - elif 'gb' in ram: - ram = int(ram.replace('gb', '')) * 1024 - - return NodeSize(id=data['id'], name=data['name'], ram=ram, disk=0, - bandwidth=0, price=0, driver=self) - - def _to_key_pair(self, data): - try: - pubkey = data['ssh_pub_key'] - except KeyError: - pubkey = None - return KeyPair(data['name'], public_key=pubkey, fingerprint=None, - driver=self, private_key=None, extra={'id': data['id']}) - - def _to_ssh_key(self, data): - return SSHKey(id=data['id'], name=data['name'], - pub_key=data.get('ssh_pub_key', None)) - - -class DigitalOcean_v2_NodeDriver(DigitalOcean_v2_BaseDriver, - DigitalOceanNodeDriver): - """ - DigitalOcean NodeDriver using v2 of the API. - """ - - NODE_STATE_MAP = {'new': NodeState.PENDING, - 'off': NodeState.STOPPED, - 'active': NodeState.RUNNING, - 'archive': NodeState.TERMINATED} - - EX_CREATE_ATTRIBUTES = ['backups', - 'ipv6', - 'private_networking', - 'ssh_keys'] - - def list_images(self): - data = self._paginated_request('/v2/images', 'images') - return list(map(self._to_image, data)) - - def list_key_pairs(self): - """ - List all the available SSH keys. - - :return: Available SSH keys. - :rtype: ``list`` of :class:`KeyPair` - """ - data = self._paginated_request('/v2/account/keys', 'ssh_keys') - return list(map(self._to_key_pair, data)) - - def list_locations(self): - data = self._paginated_request('/v2/regions', 'regions') - return list(map(self._to_location, data)) - - def list_nodes(self): - data = self._paginated_request('/v2/droplets', 'droplets') - return list(map(self._to_node, data)) - - def list_sizes(self): - data = self._paginated_request('/v2/sizes', 'sizes') - return list(map(self._to_size, data)) - - def create_node(self, name, size, image, location, ex_create_attr=None, - ex_ssh_key_ids=None, ex_user_data=None): - """ - Create a node. - - The `ex_create_attr` parameter can include the following dictionary - key and value pairs: - - * `backups`: ``bool`` defaults to False - * `ipv6`: ``bool`` defaults to False - * `private_networking`: ``bool`` defaults to False - * `user_data`: ``str`` for cloud-config data - * `ssh_keys`: ``list`` of ``int`` key ids or ``str`` fingerprints - - `ex_create_attr['ssh_keys']` will override `ex_ssh_key_ids` assignment. - - :keyword ex_create_attr: A dictionary of optional attributes for - droplet creation - :type ex_create_attr: ``dict`` - - :keyword ex_ssh_key_ids: A list of ssh key ids which will be added - to the server. (optional) - :type ex_ssh_key_ids: ``list`` of ``int`` key ids or ``str`` - key fingerprints - - :keyword ex_user_data: User data to be added to the node on create. - (optional) - :type ex_user_data: ``str`` - - :return: The newly created node. - :rtype: :class:`Node` - """ - attr = {'name': name, 'size': size.name, 'image': image.id, - 'region': location.id, 'user_data': ex_user_data} - - if ex_ssh_key_ids: - warnings.warn("The ex_ssh_key_ids parameter has been deprecated in" - " favor of the ex_create_attr parameter.") - attr['ssh_keys'] = ex_ssh_key_ids - - ex_create_attr = ex_create_attr or {} - for key in ex_create_attr.keys(): - if key in self.EX_CREATE_ATTRIBUTES: - attr[key] = ex_create_attr[key] - - res = self.connection.request('/v2/droplets', - data=json.dumps(attr), method='POST') - - data = res.object['droplet'] - # TODO: Handle this in the response class - status = res.object.get('status', 'OK') - if status == 'ERROR': - message = res.object.get('message', None) - error_message = res.object.get('error_message', message) - raise ValueError('Failed to create node: %s' % (error_message)) - - return self._to_node(data=data) - - def destroy_node(self, node): - res = self.connection.request('/v2/droplets/%s' % (node.id), - method='DELETE') - return res.status == httplib.NO_CONTENT - - def reboot_node(self, node): - attr = {'type': 'reboot'} - res = self.connection.request('/v2/droplets/%s/actions' % (node.id), - data=json.dumps(attr), method='POST') - return res.status == httplib.CREATED - - def create_image(self, node, name): - """ - Create an image from a Node. - - @inherits: :class:`NodeDriver.create_image` - - :param node: Node to use as base for image - :type node: :class:`Node` - - :param node: Name for image - :type node: ``str`` - - :rtype: ``bool`` - """ - attr = {'type': 'snapshot', 'name': name} - res = self.connection.request('/v2/droplets/%s/actions' % (node.id), - data=json.dumps(attr), method='POST') - return res.status == httplib.CREATED - - def delete_image(self, image): - """Delete an image for node. - - @inherits: :class:`NodeDriver.delete_image` - - :param image: the image to be deleted - :type image: :class:`NodeImage` - - :rtype: ``bool`` - """ - res = self.connection.request('/v2/images/%s' % (image.id), - method='DELETE') - return res.status == httplib.NO_CONTENT - - def get_image(self, image_id): - """ - Get an image based on an image_id - - @inherits: :class:`NodeDriver.get_image` - - :param image_id: Image identifier - :type image_id: ``int`` - - :return: A NodeImage object - :rtype: :class:`NodeImage` - """ - data = self._paginated_request('/v2/images/%s' % (image_id), 'image') - return self._to_image(data) - - def ex_rename_node(self, node, name): - attr = {'type': 'rename', 'name': name} - res = self.connection.request('/v2/droplets/%s/actions' % (node.id), - data=json.dumps(attr), method='POST') - return res.status == httplib.CREATED - - def ex_shutdown_node(self, node): - attr = {'type': 'shutdown'} - res = self.connection.request('/v2/droplets/%s/actions' % (node.id), - data=json.dumps(attr), method='POST') - return res.status == httplib.CREATED - - def ex_power_on_node(self, node): - attr = {'type': 'power_on'} - res = self.connection.request('/v2/droplets/%s/actions' % (node.id), - data=json.dumps(attr), method='POST') - return res.status == httplib.CREATED - - def create_key_pair(self, name, public_key=''): - """ - Create a new SSH key. - - :param name: Key name (required) - :type name: ``str`` - - :param public_key: Valid public key string (required) - :type public_key: ``str`` - """ - attr = {'name': name, 'public_key': public_key} - res = self.connection.request('/v2/account/keys', method='POST', - data=json.dumps(attr)) - - data = res.object['ssh_key'] - - return self._to_key_pair(data=data) - - def delete_key_pair(self, key): - """ - Delete an existing SSH key. - - :param key: SSH key (required) - :type key: :class:`KeyPair` - """ - key_id = key.extra['id'] - res = self.connection.request('/v2/account/keys/%s' % (key_id), - method='DELETE') - return res.status == httplib.NO_CONTENT - - def get_key_pair(self, name): - """ - Retrieve a single key pair. - - :param name: Name of the key pair to retrieve. - :type name: ``str`` - - :rtype: :class:`.KeyPair` - """ - qkey = [k for k in self.list_key_pairs() if k.name == name][0] - data = self.connection.request('/v2/account/keys/%s' % - qkey.extra['id']).object['ssh_key'] - return self._to_key_pair(data=data) - - def _to_node(self, data): - extra_keys = ['memory', 'vcpus', 'disk', 'region', 'image', - 'size_slug', 'locked', 'created_at', 'networks', - 'kernel', 'backup_ids', 'snapshot_ids', 'features'] - if 'status' in data: - state = self.NODE_STATE_MAP.get(data['status'], NodeState.UNKNOWN) - else: - state = NodeState.UNKNOWN - - created = parse_date(data['created_at']) - networks = data['networks'] - private_ips = [] - public_ips = [] - if networks: - for net in networks['v4']: - if net['type'] == 'private': - private_ips = [net['ip_address']] - if net['type'] == 'public': - public_ips = [net['ip_address']] - - extra = {} - for key in extra_keys: - if key in data: - extra[key] = data[key] - - node = Node(id=data['id'], name=data['name'], state=state, - public_ips=public_ips, private_ips=private_ips, - created_at=created, driver=self, extra=extra) - return node - - def _to_image(self, data): - extra = {'distribution': data['distribution'], - 'public': data['public'], - 'slug': data['slug'], - 'regions': data['regions'], - 'min_disk_size': data['min_disk_size'], - 'created_at': data['created_at']} - return NodeImage(id=data['id'], name=data['name'], driver=self, - extra=extra) - - def _to_location(self, data): - return NodeLocation(id=data['slug'], name=data['name'], country=None, - driver=self) - - def _to_size(self, data): - extra = {'vcpus': data['vcpus'], - 'regions': data['regions']} - return NodeSize(id=data['slug'], name=data['slug'], ram=data['memory'], - disk=data['disk'], bandwidth=data['transfer'], - price=data['price_hourly'], driver=self, extra=extra) - - def _to_key_pair(self, data): - extra = {'id': data['id']} - return KeyPair(name=data['name'], - fingerprint=data['fingerprint'], - public_key=data['public_key'], - private_key=None, - driver=self, - extra=extra)