Repository: libcloud Updated Branches: refs/heads/trunk c3fd03c65 -> 14102cc29
Packet bare metal cloud provider integration Closes #527 Signed-off-by: Tomaz Muraus <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/4d51ede1 Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/4d51ede1 Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/4d51ede1 Branch: refs/heads/trunk Commit: 4d51ede113df6a16f55e1027726fe858aff1e8d5 Parents: c3fd03c Author: Aaron Welch <[email protected]> Authored: Mon Apr 27 17:32:22 2015 -0400 Committer: Tomaz Muraus <[email protected]> Committed: Sun May 24 17:08:14 2015 +0200 ---------------------------------------------------------------------- CHANGES.rst | 4 + docs/_static/images/provider_logos/packet.png | Bin 0 -> 41262 bytes .../_supported_methods_block_storage.rst | 2 + .../_supported_methods_image_management.rst | 2 + .../_supported_methods_key_pair_management.rst | 2 + docs/compute/_supported_methods_main.rst | 2 + docs/compute/_supported_providers.rst | 2 + docs/compute/drivers/packet.rst | 25 ++ .../compute/packet/instantiate_api_v1.0.py | 10 + libcloud/compute/drivers/packet.py | 258 +++++++++++++++++++ libcloud/compute/providers.py | 2 + libcloud/compute/types.py | 1 + .../compute/fixtures/packet/device_create.json | 74 ++++++ .../test/compute/fixtures/packet/devices.json | 57 ++++ .../compute/fixtures/packet/facilities.json | 12 + .../fixtures/packet/operatingsystems.json | 28 ++ .../test/compute/fixtures/packet/plans.json | 21 ++ .../compute/fixtures/packet/sshkey_create.json | 10 + .../test/compute/fixtures/packet/sshkeys.json | 34 +++ libcloud/test/compute/test_packet.py | 184 +++++++++++++ libcloud/test/secrets.py-dist | 1 + 21 files changed, 731 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/CHANGES.rst ---------------------------------------------------------------------- diff --git a/CHANGES.rst b/CHANGES.rst index 8f964a5..570e00a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -190,6 +190,10 @@ Compute (GITHUB-338) [ZuluPro] +- Add new driver for Packet (https://www.packet.net/) provider. + (LIBCLOUD-703, GITHUB-527) + [Aaron Welch] + Storage ~~~~~~~ http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/docs/_static/images/provider_logos/packet.png ---------------------------------------------------------------------- diff --git a/docs/_static/images/provider_logos/packet.png b/docs/_static/images/provider_logos/packet.png new file mode 100644 index 0000000..249f7d4 Binary files /dev/null and b/docs/_static/images/provider_logos/packet.png differ http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/docs/compute/_supported_methods_block_storage.rst ---------------------------------------------------------------------- diff --git a/docs/compute/_supported_methods_block_storage.rst b/docs/compute/_supported_methods_block_storage.rst index 0f949a7..cacb260 100644 --- a/docs/compute/_supported_methods_block_storage.rst +++ b/docs/compute/_supported_methods_block_storage.rst @@ -55,6 +55,7 @@ Provider list volumes create volume destroy volume `Opsource`_ no no no no no no no `Outscale INC`_ yes yes yes yes yes yes yes `Outscale SAS`_ yes yes yes yes yes yes yes +`Packet`_ no no no no no no no `ProfitBricks`_ yes yes yes yes yes no no `Rackspace Cloud (Next Gen)`_ yes yes yes yes yes yes yes `Rackspace Cloud (First Gen)`_ yes yes yes yes yes no no @@ -125,6 +126,7 @@ Provider list volumes create volume destroy volume .. _`Opsource`: http://www.opsource.net/ .. _`Outscale INC`: http://www.outscale.com .. _`Outscale SAS`: http://www.outscale.com +.. _`Packet`: http://www.packet.net/ .. _`ProfitBricks`: http://www.profitbricks.com .. _`Rackspace Cloud (Next Gen)`: http://www.rackspace.com .. _`Rackspace Cloud (First Gen)`: http://www.rackspace.com http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/docs/compute/_supported_methods_image_management.rst ---------------------------------------------------------------------- diff --git a/docs/compute/_supported_methods_image_management.rst b/docs/compute/_supported_methods_image_management.rst index 2971b75..2944835 100644 --- a/docs/compute/_supported_methods_image_management.rst +++ b/docs/compute/_supported_methods_image_management.rst @@ -55,6 +55,7 @@ Provider list images get image create image delete `Opsource`_ yes no no no no `Outscale INC`_ yes yes yes yes yes `Outscale SAS`_ yes yes yes yes yes +`Packet`_ yes no no no no `ProfitBricks`_ yes no no no no `Rackspace Cloud (Next Gen)`_ yes yes yes yes no `Rackspace Cloud (First Gen)`_ yes yes yes yes no @@ -125,6 +126,7 @@ Provider list images get image create image delete .. _`Opsource`: http://www.opsource.net/ .. _`Outscale INC`: http://www.outscale.com .. _`Outscale SAS`: http://www.outscale.com +.. _`Packet`: http://www.packet.net/ .. _`ProfitBricks`: http://www.profitbricks.com .. _`Rackspace Cloud (Next Gen)`: http://www.rackspace.com .. _`Rackspace Cloud (First Gen)`: http://www.rackspace.com http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/docs/compute/_supported_methods_key_pair_management.rst ---------------------------------------------------------------------- diff --git a/docs/compute/_supported_methods_key_pair_management.rst b/docs/compute/_supported_methods_key_pair_management.rst index 9b4750b..5530506 100644 --- a/docs/compute/_supported_methods_key_pair_management.rst +++ b/docs/compute/_supported_methods_key_pair_management.rst @@ -55,6 +55,7 @@ Provider list key pairs get key pair create key pai `Opsource`_ no no no no no no `Outscale INC`_ yes yes yes yes no yes `Outscale SAS`_ yes yes yes yes no yes +`Packet`_ yes no yes no no yes `ProfitBricks`_ no no no no no no `Rackspace Cloud (Next Gen)`_ yes yes yes yes no yes `Rackspace Cloud (First Gen)`_ no no no no no no @@ -125,6 +126,7 @@ Provider list key pairs get key pair create key pai .. _`Opsource`: http://www.opsource.net/ .. _`Outscale INC`: http://www.outscale.com .. _`Outscale SAS`: http://www.outscale.com +.. _`Packet`: http://www.packet.net/ .. _`ProfitBricks`: http://www.profitbricks.com .. _`Rackspace Cloud (Next Gen)`: http://www.rackspace.com .. _`Rackspace Cloud (First Gen)`: http://www.rackspace.com http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/docs/compute/_supported_methods_main.rst ---------------------------------------------------------------------- diff --git a/docs/compute/_supported_methods_main.rst b/docs/compute/_supported_methods_main.rst index c944632..2e5ee19 100644 --- a/docs/compute/_supported_methods_main.rst +++ b/docs/compute/_supported_methods_main.rst @@ -55,6 +55,7 @@ Provider list nodes create node reboot node destroy `Opsource`_ yes yes yes yes yes yes yes `Outscale INC`_ yes yes yes yes yes yes yes `Outscale SAS`_ yes yes yes yes yes yes yes +`Packet`_ yes yes yes yes yes yes no `ProfitBricks`_ yes yes yes yes yes yes no `Rackspace Cloud (Next Gen)`_ yes yes yes yes yes yes yes `Rackspace Cloud (First Gen)`_ yes yes yes yes yes yes yes @@ -125,6 +126,7 @@ Provider list nodes create node reboot node destroy .. _`Opsource`: http://www.opsource.net/ .. _`Outscale INC`: http://www.outscale.com .. _`Outscale SAS`: http://www.outscale.com +.. _`Packet`: http://www.packet.net/ .. _`ProfitBricks`: http://www.profitbricks.com .. _`Rackspace Cloud (Next Gen)`: http://www.rackspace.com .. _`Rackspace Cloud (First Gen)`: http://www.rackspace.com http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/docs/compute/_supported_providers.rst ---------------------------------------------------------------------- diff --git a/docs/compute/_supported_providers.rst b/docs/compute/_supported_providers.rst index 9a27683..91f9398 100644 --- a/docs/compute/_supported_providers.rst +++ b/docs/compute/_supported_providers.rst @@ -55,6 +55,7 @@ Provider Documentation `Opsource`_ OPSOURCE :mod:`libcloud.compute.drivers.opsource` :class:`OpsourceNodeDriver` `Outscale INC`_ :doc:`Click </compute/drivers/outscale_inc>` OUTSCALE_INC :mod:`libcloud.compute.drivers.ec2` :class:`OutscaleINCNodeDriver` `Outscale SAS`_ :doc:`Click </compute/drivers/outscale_sas>` OUTSCALE_SAS :mod:`libcloud.compute.drivers.ec2` :class:`OutscaleSASNodeDriver` +`Packet`_ :doc:`Click </compute/drivers/packet>` PACKET :mod:`libcloud.compute.drivers.packet` :class:`PacketNodeDriver` `ProfitBricks`_ PROFIT_BRICKS :mod:`libcloud.compute.drivers.profitbricks` :class:`ProfitBricksNodeDriver` `Rackspace Cloud (Next Gen)`_ :doc:`Click </compute/drivers/rackspace>` RACKSPACE :mod:`libcloud.compute.drivers.rackspace` :class:`RackspaceNodeDriver` `Rackspace Cloud (First Gen)`_ RACKSPACE_FIRST_GEN :mod:`libcloud.compute.drivers.rackspace` :class:`RackspaceFirstGenNodeDriver` @@ -125,6 +126,7 @@ Provider Documentation .. _`Opsource`: http://www.opsource.net/ .. _`Outscale INC`: http://www.outscale.com .. _`Outscale SAS`: http://www.outscale.com +.. _`Packet`: http://www.packet.net/ .. _`ProfitBricks`: http://www.profitbricks.com .. _`Rackspace Cloud (Next Gen)`: http://www.rackspace.com .. _`Rackspace Cloud (First Gen)`: http://www.rackspace.com http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/docs/compute/drivers/packet.rst ---------------------------------------------------------------------- diff --git a/docs/compute/drivers/packet.rst b/docs/compute/drivers/packet.rst new file mode 100644 index 0000000..dd05387 --- /dev/null +++ b/docs/compute/drivers/packet.rst @@ -0,0 +1,25 @@ +Packet Compute Driver Documentation +========================================= + +`Packet`_ is a dedicated bare metal cloud hosting provider based in New York +City + +.. figure:: /_static/images/provider_logos/packet.png + :align: center + :width: 300 + :target: https://www.packet.net/ + +Instantiating a driver and listing devices in a project +------------------------------------------------------- + +.. literalinclude:: /examples/compute/packet/instantiate_api_v1.0.py + :language: python + +API Docs +-------- + +.. autoclass:: libcloud.compute.drivers.packet.Packet_v1_NodeDriver + :members: + :inherited-members: + +.. _`Packet`: https://www.packet.net/ http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/docs/examples/compute/packet/instantiate_api_v1.0.py ---------------------------------------------------------------------- diff --git a/docs/examples/compute/packet/instantiate_api_v1.0.py b/docs/examples/compute/packet/instantiate_api_v1.0.py new file mode 100644 index 0000000..7f9d4b0 --- /dev/null +++ b/docs/examples/compute/packet/instantiate_api_v1.0.py @@ -0,0 +1,10 @@ +from libcloud.compute.types import Provider +from libcloud.compute.providers import get_driver + +cls = get_driver(Provider.PACKET) + +driver = cls('your API auth token') + +nodes = driver.list_nodes('project-id') +for node in nodes: + print(node) http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/libcloud/compute/drivers/packet.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/drivers/packet.py b/libcloud/compute/drivers/packet.py new file mode 100644 index 0000000..2560145 --- /dev/null +++ b/libcloud/compute/drivers/packet.py @@ -0,0 +1,258 @@ +# 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. +""" +Packet Driver +""" + +from libcloud.utils.py3 import httplib + +from libcloud.common.base import ConnectionKey, JsonResponse +from libcloud.compute.types import Provider, NodeState, InvalidCredsError +from libcloud.compute.base import NodeDriver, Node +from libcloud.compute.base import NodeImage, NodeSize, NodeLocation +from libcloud.compute.base import KeyPair + +PACKET_ENDPOINT = "api.packet.net" + + +class PacketResponse(JsonResponse): + valid_response_codes = [httplib.OK, httplib.ACCEPTED, httplib.CREATED, + httplib.NO_CONTENT] + + def parse_error(self): + if self.status == httplib.UNAUTHORIZED: + body = self.parse_body() + raise InvalidCredsError(body['message']) + else: + body = self.parse_body() + if 'message' in body: + error = '%s (code: %s)' % (body['message'], self.status) + else: + error = body + return error + + def success(self): + return self.status in self.valid_response_codes + + +class PacketConnection(ConnectionKey): + """ + Connection class for the Packet driver. + """ + + host = PACKET_ENDPOINT + responseCls = PacketResponse + + def add_default_headers(self, headers): + """ + Add headers that are necessary for every request + """ + headers['Content-Type'] = 'application/json' + headers['X-Auth-Token'] = self.key + headers['X-Consumer-Token'] = \ + 'kcrhMn7hwG8Ceo2hAhGFa2qpxLBvVHxEjS9ue8iqmsNkeeB2iQgMq4dNc1893pYu' + return headers + + +class PacketNodeDriver(NodeDriver): + """ + Packet NodeDriver + """ + + connectionCls = PacketConnection + type = Provider.PACKET + name = 'Packet' + website = 'http://www.packet.net/' + + NODE_STATE_MAP = {'queued': NodeState.PENDING, + 'provisioning': NodeState.PENDING, + 'rebuilding': NodeState.PENDING, + 'powering_on': NodeState.REBOOTING, + 'powering_off': NodeState.REBOOTING, + 'rebooting': NodeState.REBOOTING, + 'inactive': NodeState.STOPPED, + 'deleted': NodeState.TERMINATED, + 'deprovisioning': NodeState.TERMINATED, + 'failed': NodeState.ERROR, + 'active': NodeState.RUNNING} + + def list_nodes(self, ex_project_id): + data = self.connection.request('/projects/%s/devices' % + (ex_project_id), + params={'include': 'plan'} + ).object['devices'] + return list(map(self._to_node, data)) + + def list_locations(self): + data = self.connection.request('/facilities')\ + .object['facilities'] + return list(map(self._to_location, data)) + + def list_images(self): + data = self.connection.request('/operating-systems')\ + .object['operating_systems'] + return list(map(self._to_image, data)) + + def list_sizes(self): + data = self.connection.request('/plans').object['plans'] + return list(map(self._to_size, data)) + + def create_node(self, name, size, image, location, ex_project_id): + """ + Create a node. + + :return: The newly created node. + :rtype: :class:`Node` + """ + + params = {'hostname': name, 'plan': size.id, + 'operating_system': image.id, 'facility': location.id, + 'include': 'plan', 'billing_cycle': 'hourly'} + + data = self.connection.request('/projects/%s/devices' % + (ex_project_id), + params=params, method='POST') + + 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) + + def reboot_node(self, node): + params = {'type': 'reboot'} + res = self.connection.request('/devices/%s/actions' % (node.id), + params=params, method='POST') + return res.status == httplib.OK + + def destroy_node(self, node): + res = self.connection.request('/devices/%s' % (node.id), + method='DELETE') + 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` objects + """ + data = self.connection.request('/ssh-keys').object['ssh_keys'] + return list(map(self._to_key_pairs, data)) + + 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`` + """ + params = {'label': name, 'key': public_key} + data = self.connection.request('/ssh-keys', method='POST', + params=params).object + return self._to_key_pairs(data) + + def delete_key_pair(self, key): + """ + Delete an existing SSH key. + + :param key: SSH key (required) + :type key: :class:`KeyPair` + """ + key_id = key.name + res = self.connection.request('/ssh-keys/%s' % (key_id), + method='DELETE') + return res.status == httplib.NO_CONTENT + + def _to_node(self, data): + extra_keys = ['created_at', 'updated_at', + 'userdata', 'billing_cycle', 'locked'] + if 'state' in data: + state = self.NODE_STATE_MAP.get(data['state'], NodeState.UNKNOWN) + else: + state = NodeState.UNKNOWN + + if 'ip_addresses' in data and data['ip_addresses'] is not None: + ips = self._parse_ips(data['ip_addresses']) + + if 'operating_system' in data and data['operating_system'] is not None: + image = self._to_image(data['operating_system']) + + if 'plan' in data and data['plan'] is not None: + size = self._to_size(data['plan']) + + extra = {} + for key in extra_keys: + if key in data: + extra[key] = data[key] + + node = Node(id=data['id'], name=data['hostname'], state=state, + image=image, size=size, + public_ips=ips['public'], private_ips=ips['private'], + extra=extra, driver=self) + return node + + def _to_image(self, data): + extra = {'distro': data['distro'], 'version': data['version']} + return NodeImage(id=data['slug'], name=data['name'], extra=extra, + driver=self) + + def _to_location(self, data): + return NodeLocation(id=data['code'], name=data['name'], country=None, + driver=self) + + def _to_size(self, data): + extra = {'description': data['description'], 'line': data['line']} + + ram = data['specs']['memory']['total'].lower() + if 'mb' in ram: + ram = int(ram.replace('mb', '')) + elif 'gb' in ram: + ram = int(ram.replace('gb', '')) * 1024 + + disk = 0 + for disks in data['specs']['drives']: + disk += disks['count'] * int(disks['size'].replace('GB', '')) + + price = data['pricing']['hourly'] + + return NodeSize(id=data['slug'], name=data['name'], ram=ram, disk=disk, + bandwidth=0, price=price, extra=extra, driver=self) + + def _to_key_pairs(self, data): + extra = {'label': data['label'], + 'created_at': data['created_at'], + 'updated_at': data['updated_at']} + return KeyPair(name=data['id'], + fingerprint=data['fingerprint'], + public_key=data['key'], + private_key=None, + driver=self, + extra=extra) + + def _parse_ips(self, data): + public_ips = [] + private_ips = [] + for address in data: + if 'address' in address and address['address'] is not None: + if 'public' in address and address['public'] is True: + public_ips.append(address['address']) + else: + private_ips.append(address['address']) + return {'public': public_ips, 'private': private_ips} http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/libcloud/compute/providers.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/providers.py b/libcloud/compute/providers.py index f2928d5..25687c3 100644 --- a/libcloud/compute/providers.py +++ b/libcloud/compute/providers.py @@ -161,6 +161,8 @@ DRIVERS = { ('libcloud.compute.drivers.auroracompute', 'AuroraComputeNodeDriver'), Provider.CLOUDWATT: ('libcloud.compute.drivers.cloudwatt', 'CloudwattNodeDriver'), + Provider.PACKET: + ('libcloud.compute.drivers.packet', 'PacketNodeDriver'), # Deprecated Provider.CLOUDSIGMA_US: http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/libcloud/compute/types.py ---------------------------------------------------------------------- diff --git a/libcloud/compute/types.py b/libcloud/compute/types.py index 0d1ce4f..f045546 100644 --- a/libcloud/compute/types.py +++ b/libcloud/compute/types.py @@ -133,6 +133,7 @@ class Provider(object): VULTR = 'vultr' AURORACOMPUTE = 'aurora_compute' CLOUDWATT = 'cloudwatt' + PACKET = 'packet' # OpenStack based providers HPCLOUD = 'hpcloud' http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/libcloud/test/compute/fixtures/packet/device_create.json ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/packet/device_create.json b/libcloud/test/compute/fixtures/packet/device_create.json new file mode 100644 index 0000000..2f5b12c --- /dev/null +++ b/libcloud/test/compute/fixtures/packet/device_create.json @@ -0,0 +1,74 @@ +{ + "userdata": null, + "operating_system": + { + "distro": "coreos", + "slug": "coreos_stable", + "version": "stable", + "name": "CoreOS (stable)" + }, + "locked": false, + "tags": [], + "href": "/devices/9f7eafab-CCCC-DDDD-EEEE-c2a686367791", + "created_at": "2015-05-22T17:59:43Z", + "hostname": "9f7eafab.packethost.net", + "updated_at": "2015-05-22T17:59:43.972Z", + "project": { "href": "/projects/746ea6dd-CCCC-DDDD-EEEE-728784671fbf" }, + "provisioning_percentage": 0.0, + "state": "queued", + "billing_cycle": "hourly", + "user": "core", + "ip_addresses": [], + "facility": { "id": "e1e9c52e-a0bc-4117-b996-0fc94843ea09" }, + "id": "9f7eafab-6f6b-4ae4-988d-c2a686367791", + "provisioning_events": [ + { + "body": "Provisioning started", + "relationships": [], + "interpolated": "Provisioning started", + "created_at": null, + "type": "provisioning.101", + "id": null + }, + { + "body": "Network configured", + "relationships": [], + "interpolated": "Network configured", + "created_at": null, + "type": "provisioning.102", + "id": null + }, + { + "body": "Configuration written, restarting device", + "relationships": [], + "interpolated": "Configuration written, restarting device", + "created_at": null, + "type": "provisioning.103", + "id": null + }, + { + "body": "Device phoned home and is ready to go", + "relationships": [], + "interpolated": "Device phoned home and is ready to go", + "created_at": null, + "type": "provisioning.110", + "id": null + }], + "plan": + { + "slug": "baremetal_1", + "description": "Our Type 1 configuration is a zippy general use server", + "id": "6d1f1ffa-7912-4b78-b50d-88cc7c8ab40f", + "pricing": { "hourly": 0.4 }, + "line": "baremetal", + "specs": + { + "nics": [{"count": 2, "type": "gigabit"}], + "drives": [{"count": 2, "type": "SSD", "size": "120GB"}], + "features": {"txt": true, "raid": true}, + "cpus": [{"count": 1, "type": "Intel E3-1240 v3"}], + "memory": {"total": "16GB"} + }, + "name": "Type 1" + } +} http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/libcloud/test/compute/fixtures/packet/devices.json ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/packet/devices.json b/libcloud/test/compute/fixtures/packet/devices.json new file mode 100644 index 0000000..d5b8c5e --- /dev/null +++ b/libcloud/test/compute/fixtures/packet/devices.json @@ -0,0 +1,57 @@ +{ + "devices": [ + { + "id": "1e52437e-bbbb-cccc-dddd-74a9dfd3d3bb", + "hostname": "test-node", + "state": "active", + "tags": [], + "billing_cycle": "hourly", + "user": "root", + "userdata": "", + "locked": false, + "created_at": "2015-05-03T15:50:49Z", + "updated_at": "2015-05-03T16:00:08Z", + "operating_system": + { + "slug": "ubuntu_14_04", + "name": "Ubuntu 14.04 LTS", + "distro": "ubuntu", + "version": "14.04" + }, + "project": { "href": "/projects/project-id" }, + "facility": { "id": "e1e9c52e-a0bc-4117-b996-0fc94843ea09" }, + "plan": + { + "id": "6d1f1ffa-7912-4b78-b50d-88cc7c8ab40f", + "slug": "baremetal_1", + "name": "Type 1", + "description": "Our Type 1 configuration is a zippy general use server", + "line": "baremetal", + "specs": + { + "cpus": [{"count":1,"type":"Intel E3-1240 v3"}], + "memory": {"total":"16GB" }, + "drives": [{"count":2,"size":"120GB","type":"SSD"}], + "nics": [{"count":2,"type":"gigabit"}], + "features": {"raid":true, "txt":true} + }, + "pricing": { "hourly":0.4 } + }, + "ip_addresses": [ + { "address_family": 4,"netmask":"255.255.255.255","cidr":32,"address":"147.75.255.255","gateway":"147.75.255.255","public":true }, + { "address_family": 6,"netmask":"ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe","cidr":32,"address":"2604:EEEE::EE","gateway":"2604:1380::EE","public":true }, + { "address_family": 4,"netmask":"255.255.255.255","cidr":32,"address":"10.0.0.255","gateway":"10.0.0.255","public":false } + ], + "href": "/devices/1e52437e-bbbb-cccc-dddd-74a9dfd3d3bb" + } + ], + "meta": + { + "first": { "href":"/projects/project-id/devices?page=1" }, + "previous":null, + "self": { "href":"/projects/project-id/devices?page=1" }, + "next": null, + "last": { "href":"/projects/project-id/devices?page=1" }, + "total": 1 + } +} http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/libcloud/test/compute/fixtures/packet/facilities.json ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/packet/facilities.json b/libcloud/test/compute/fixtures/packet/facilities.json new file mode 100644 index 0000000..4b0014c --- /dev/null +++ b/libcloud/test/compute/fixtures/packet/facilities.json @@ -0,0 +1,12 @@ +{ + "facilities": [ + { + "id": "e1e9c52e-a0bc-4117-b996-0fc94843ea09", + "name": "Parsippany, NJ", + "code": "ewr1", + "features": ["baremetal"], + "address": null, + "href": "/facilities/e1e9c52e-a0bc-4117-b996-0fc94843ea09" + } + ] +} http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/libcloud/test/compute/fixtures/packet/operatingsystems.json ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/packet/operatingsystems.json b/libcloud/test/compute/fixtures/packet/operatingsystems.json new file mode 100644 index 0000000..5c0bc8f --- /dev/null +++ b/libcloud/test/compute/fixtures/packet/operatingsystems.json @@ -0,0 +1,28 @@ +{ + "operating_systems": [ + { + "slug": "centos_7", + "name": "CentOS 7", + "distro": "centos", + "version": "7" + }, + { + "slug": "coreos_stable", + "name": "CoreOS (stable)", + "distro": "coreos", + "version": "stable" + }, + { + "slug": "ubuntu_14_04", + "name": "Ubuntu 14.04 LTS", + "distro": "ubuntu", + "version": "14.04" + }, + { + "slug": "debian_7", + "name": "Debian 7", + "distro": "debian", + "version": "7" + } + ] +} http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/libcloud/test/compute/fixtures/packet/plans.json ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/packet/plans.json b/libcloud/test/compute/fixtures/packet/plans.json new file mode 100644 index 0000000..af95446 --- /dev/null +++ b/libcloud/test/compute/fixtures/packet/plans.json @@ -0,0 +1,21 @@ +{ + "plans": [ + { + "id": "6d1f1ffa-7912-4b78-b50d-88cc7c8ab40f", + "slug": "baremetal_1", + "name": "Type 1", + "description": "Our Type 1 configuration is a zippy general use server", + "line": "baremetal", + "specs": { + "cpus":[{"count":1,"type":"Intel E3-1240 v3"}], + "memory":{"total":"16GB"}, + "drives":[{"count":2,"size":"120GB","type":"SSD"}], + "nics":[{"count":2,"type":"gigabit"}], + "features":{"raid":true,"txt":true} + }, + "pricing": { + "hourly":0.4,"monthly":250.0 + } + } + ] +} http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/libcloud/test/compute/fixtures/packet/sshkey_create.json ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/packet/sshkey_create.json b/libcloud/test/compute/fixtures/packet/sshkey_create.json new file mode 100644 index 0000000..8e11fdf --- /dev/null +++ b/libcloud/test/compute/fixtures/packet/sshkey_create.json @@ -0,0 +1,10 @@ +{ + "id": "2c1a7f23-1dc6-4a37-948e-d9857d9f607c", + "label": "ubuntu1404-201505221415a4c7757e-5198-4f49-82d4-35eb2d06eb27", + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDI4pIqzpb5g3992h+yr527VRcaB68KE4vPjWPPoiQws49KIs2NMcOzS9QE4641uW1u5ML2HgQdfYKMF/YFGnI1Y6xV637DjhDyZYV9LasUH49npSSJjsBcsk9JGfUpNAOdcgpFzK8V90eiOrOC5YncxdwwG8pwjFI9nNVPCl4hYEu1iXdyysHvkFfS2fklsNjLWrzfafPlaen+qcBxygCA0sFdW/7er50aJeghdBHnE2WhIKLUkJxnKadznfAge7oEe+3LLAPfP+3yHyvp2+H0IzmVfYvAjnzliYetqQ8pg5ZW2BiJzvqz5PebGS70y/ySCNW1qQmJURK/Wc1bt9en [email protected]\n", + "fingerprint": "aa:49:46:57:2a:07:64:56:33:07:ef:76:1d:54:a3:41", + "created_at": "2015-05-22T18:15:04Z", + "updated_at":"2015-05-22T18:15:04Z", + "user": { "href":"/users/userid" }, + "href": "/ssh-keys/2c1a7f23-1dc6-4a37-948e-d9857d9f607c" +} http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/libcloud/test/compute/fixtures/packet/sshkeys.json ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/fixtures/packet/sshkeys.json b/libcloud/test/compute/fixtures/packet/sshkeys.json new file mode 100644 index 0000000..9152195 --- /dev/null +++ b/libcloud/test/compute/fixtures/packet/sshkeys.json @@ -0,0 +1,34 @@ +{ + "ssh_keys":[ + { + "id": "2c1a7f23-1dc6-4a37-948e-d9857d9f607c", + "label": "ubuntu1404-201505221415a4c7757e-5198-4f49-82d4-35eb2d06eb27", + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDI4pIqzpb5g3992h+yr527VRcaB68KE4vPjWPPoiQws49KIs2NMcOzS9QE4641uW1u5ML2HgQdfYKMF/YFGnI1Y6xV637DjhDyZYV9LasUH49npSSJjsBcsk9JGfUpNAOdcgpFzK8V90eiOrOC5YncxdwwG8pwjFI9nNVPCl4hYEu1iXdyysHvkFfS2fklsNjLWrzfafPlaen+qcBxygCA0sFdW/7er50aJeghdBHnE2WhIKLUkJxnKadznfAge7oEe+3LLAPfP+3yHyvp2+H0IzmVfYvAjnzliYetqQ8pg5ZW2BiJzvqz5PebGS70y/ySCNW1qQmJURK/Wc1bt9en [email protected]\n", + "fingerprint": "aa:49:46:57:2a:07:64:56:33:07:ef:76:1d:54:a3:41", + "created_at": "2015-05-22T18:15:04Z", + "updated_at":"2015-05-22T18:15:04Z", + "user": { "href":"/users/userid" }, + "href": "/ssh-keys/2c1a7f23-1dc6-4a37-948e-d9857d9f607c" + }, + { + "id": "e5ee91f4-ecf7-4a68-9a4e-6443cf2d7eb0", + "label": "ubuntu1404-201505212115f8161afd-7034-498f-aa04-a8d5562d3455", + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDc7qwbxJetidi4PnM0hxBLXfW+u/h2boNJZdEd5Bky2CRwIlMwPFqw3zEHrZyh05Ypw3wchvhxLVAC++5XbB7dbKPs7WAtQaZWiqJXVfacaIywyiuNgmdGv7V7gJLOZwLF1sFVisTjAtSLkroidzwX3Btxba+NcGlCVt2Zg2fPbHSUV4tnvzWpQsUBejoJ4pWxP84ty7GPymrRwnjm+qAztCy3RVGtrAAYp04Q/UeIZfi2TBrjZ8y39T8hx8RaQjA1H/+47IEDe+U7rJpxNR9tcZdEryhpH7YP5XFoHo8Y8IiLOKJo6gN0tK1zajoXw7/2oXdGE0Qqx2/VIvivdu6J [email protected]\n", + "fingerprint": "83:b8:0a:30:08:5e:27:50:db:25:d7:a7:ff:ab:aa:0a", + "created_at": "2015-05-22T01:15:04Z", + "updated_at": "2015-05-22T01:15:04Z", + "user": { "href":"/users/userid" }, + "href": "/ssh-keys/e5ee91f4-ecf7-4a68-9a4e-6443cf2d7eb0" + }, + { + "id": "561b54e7-4a2b-4832-a165-567ebb8c8bfb", + "label": "ubuntu1404-201505211245623a7e97-0826-4f62-b337-e7fc592b748a", + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCd+HRs6t4/n3LRnvzObeph2ggNNu7P+U8xMJNVE2qfjbrdJP26D4ELDVFbaSCBetYoU6G0IOlUnggZ4g7MPB6eicB5RZEOvAh58pIEgUqnWdZgDbLLY+ZGRwuaFAk6aof3bWDDqd3PUn+HtzNz3EK6Ow09vuYe1RFXLyUcDdb/LJG1bSUw/W+bEjBi/gMIcvomkSz5px40zJL4Bulqy3XPvJyxPweZbsT6LsQkBSstqTNkPH+IYWpUrOVoWy4+etVQ0OOWUXbgMyPtM5qh8JovhkQe5wn1bEV+Fw1LAJ5MF8UKr45k7hZrWfjuyCK1EA3o2Ptn+LpZW4CbCfKuFDg3 [email protected]\n", + "fingerprint": "ed:17:56:d0:03:66:39:f6:3c:03:c5:e6:ec:ac:c4:32", + "created_at": "2015-05-21T16:45:03Z", + "updated_at": "2015-05-21T16:45:03Z", + "user": { "href":"/users/userid" }, + "href": "/ssh-keys/561b54e7-4a2b-4832-a165-567ebb8c8bfb" + } + ] +} http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/libcloud/test/compute/test_packet.py ---------------------------------------------------------------------- diff --git a/libcloud/test/compute/test_packet.py b/libcloud/test/compute/test_packet.py new file mode 100644 index 0000000..3a17b11 --- /dev/null +++ b/libcloud/test/compute/test_packet.py @@ -0,0 +1,184 @@ +# 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. +# +# Maintainer: Aaron Welch <[email protected]> +# Based on code written by Jed Smith <[email protected]> who based it on +# code written by Alex Polvi <[email protected]> +# + +import sys +import unittest +from libcloud.utils.py3 import httplib + +from libcloud.compute.drivers.packet import PacketNodeDriver +from libcloud.compute.base import Node, KeyPair +from libcloud.compute.types import NodeState + +from libcloud.test import MockHttp +from libcloud.test.compute import TestCaseMixin +from libcloud.test.file_fixtures import ComputeFileFixtures + + +class PacketTest(unittest.TestCase, TestCaseMixin): + def setUp(self): + PacketNodeDriver.connectionCls.conn_classes = (None, PacketMockHttp) + self.driver = PacketNodeDriver('foo') + + def test_list_nodes(self): + nodes = self.driver.list_nodes('project-id') + self.assertEqual(len(nodes), 1) + node = nodes[0] + self.assertEqual(node.id, '1e52437e-bbbb-cccc-dddd-74a9dfd3d3bb') + self.assertEqual(node.name, 'test-node') + self.assertEqual(node.state, NodeState.RUNNING) + self.assertTrue('147.75.255.255' in node.public_ips) + self.assertTrue('2604:EEEE::EE' in node.public_ips) + self.assertTrue('10.0.0.255' in node.private_ips) + self.assertEqual(node.extra['created_at'], '2015-05-03T15:50:49Z') + self.assertEqual(node.extra['updated_at'], '2015-05-03T16:00:08Z') + self.assertEqual(node.extra['billing_cycle'], 'hourly') + self.assertEqual(node.extra['locked'], False) + self.assertEqual(node.size.id, 'baremetal_1') + self.assertEqual(node.size.name, 'Type 1') + self.assertEqual(node.size.ram, 16384) + self.assertEqual(node.size.disk, 240) + self.assertEqual(node.size.price, 0.4) + self.assertEqual(node.size.extra['line'], 'baremetal') + self.assertEqual(node.image.id, 'ubuntu_14_04') + self.assertEqual(node.image.name, 'Ubuntu 14.04 LTS') + self.assertEqual(node.image.extra['distro'], 'ubuntu') + self.assertEqual(node.image.extra['version'], '14.04') + + def test_list_nodes_response(self): + nodes = self.driver.list_nodes('project-id') + self.assertTrue(isinstance(nodes, list)) + for node in nodes: + self.assertTrue(isinstance(node, Node)) + + def test_list_locations(self): + locations = self.driver.list_locations() + self.assertEqual(len(locations), 1) + + def test_list_images(self): + images = self.driver.list_images() + self.assertEqual(len(images), 4) + + def test_list_sizes(self): + sizes = self.driver.list_sizes() + self.assertEqual(len(sizes), 1) + + def test_create_node(self): + node = self.driver.create_node(ex_project_id="project-id", + name="node-name", + size=self.driver.list_sizes()[0], + image=self.driver.list_images()[0], + location=self.driver.list_locations()[ + 0]) + self.assertTrue(isinstance(node, Node)) + + def test_create_node_response(self): + size = self.driver.list_sizes()[0] + image = self.driver.list_images()[0] + location = self.driver.list_locations()[0] + node = self.driver.create_node(ex_project_id="project-id", + name='node-name', + image=image, + size=size, + location=location) + self.assertTrue(isinstance(node, Node)) + + def test_reboot_node(self): + node = self.driver.list_nodes('project-id')[0] + self.driver.reboot_node(node) + + def test_reboot_node_response(self): + node = self.driver.list_nodes('project-id')[0] + self.driver.reboot_node(node) + + def test_destroy_node(self): + node = self.driver.list_nodes('project-id')[0] + self.driver.destroy_node(node) + + def test_destroy_node_response(self): + node = self.driver.list_nodes('project-id')[0] + self.driver.destroy_node(node) + + def test_list_key_pairs(self): + keys = self.driver.list_key_pairs() + self.assertEqual(len(keys), 3) + + def test_create_key_pair(self): + key = self.driver.create_key_pair(name="sshkey-name", + public_key="ssh-rsa AAAAB3NzaC1yc2EA\ +AAADAQABAAABAQDI4pIqzpb5g3992h+yr527VRcaB68KE4vPjWPPoiQws49KIs2NMcOzS9QE4641uW\ +1u5ML2HgQdfYKMF/YFGnI1Y6xV637DjhDyZYV9LasUH49npSSJjsBcsk9JGfUpNAOdcgpFzK8V90ei\ +OrOC5YncxdwwG8pwjFI9nNVPCl4hYEu1iXdyysHvkFfS2fklsNjLWrzfafPlaen+qcBxygCA0sFdW/\ +7er50aJeghdBHnE2WhIKLUkJxnKadznfAge7oEe+3LLAPfP+3yHyvp2+H0IzmVfYvAjnzliYetqQ8p\ +g5ZW2BiJzvqz5PebGS70y/ySCNW1qQmJURK/Wc1bt9en root@libcloud") + self.assertTrue(isinstance(key, KeyPair)) + + def test_delete_key_pair(self): + key = self.driver.list_key_pairs()[0] + self.driver.delete_key_pair(key) + + +class PacketMockHttp(MockHttp): + fixtures = ComputeFileFixtures('packet') + + def _facilities(self, method, url, body, headers): + body = self.fixtures.load('facilities.json') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _plans(self, method, url, body, headers): + body = self.fixtures.load('plans.json') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _operating_systems(self, method, url, body, headers): + body = self.fixtures.load('operatingsystems.json') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _ssh_keys(self, method, url, body, headers): + if method == 'GET': + body = self.fixtures.load('sshkeys.json') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + if method == 'POST': + body = self.fixtures.load('sshkey_create.json') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _ssh_keys_2c1a7f23_1dc6_4a37_948e_d9857d9f607c(self, method, url, + body, headers): + if method == 'DELETE': + return (httplib.OK, '', {}, httplib.responses[httplib.OK]) + + def _projects_project_id_devices(self, method, url, body, headers): + if method == 'POST': + body = self.fixtures.load('device_create.json') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + elif method == 'GET': + body = self.fixtures.load('devices.json') + return (httplib.OK, body, {}, httplib.responses[httplib.OK]) + + def _devices_1e52437e_bbbb_cccc_dddd_74a9dfd3d3bb(self, method, url, + body, headers): + if method == 'DELETE': + return (httplib.OK, '', {}, httplib.responses[httplib.OK]) + + def _devices_1e52437e_bbbb_cccc_dddd_74a9dfd3d3bb_actions( + self, method, url, body, headers): + return (httplib.OK, '', {}, httplib.responses[httplib.OK]) + + +if __name__ == '__main__': + sys.exit(unittest.main()) http://git-wip-us.apache.org/repos/asf/libcloud/blob/4d51ede1/libcloud/test/secrets.py-dist ---------------------------------------------------------------------- diff --git a/libcloud/test/secrets.py-dist b/libcloud/test/secrets.py-dist index d6ea913..83e28d1 100644 --- a/libcloud/test/secrets.py-dist +++ b/libcloud/test/secrets.py-dist @@ -48,6 +48,7 @@ DIGITALOCEAN_v2_PARAMS = ('token',) CLOUDFRAMES_PARAMS = ('key', 'secret', False, 'host', 8888) PROFIT_BRICKS_PARAMS = ('user', 'key') VULTR_PARAMS = ('key') +PACKET_PARAMS = ('api_key') # Storage STORAGE_S3_PARAMS = ('key', 'secret')
