You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by qu...@apache.org on 2018/07/06 06:12:30 UTC
[1/2] libcloud git commit: implement OpenStackv2 port
attaching/detaching
Repository: libcloud
Updated Branches:
refs/heads/trunk 1ac9467a9 -> b2b7684a7
implement OpenStackv2 port attaching/detaching
Adds Port Interface calls for the OpenStack v2 driver. Similar in
functionality to a floating IPs (can be attached / detached from a
compute instance to move IPs between instances) but a bit different.
> A port is a connection point for attaching a single device, such as the
> NIC of a server, to a network. The port also describes the associated
> network configuration, such as the MAC and IP addresses to be used on
> that port.
https://docs.openstack.org/python-openstackclient/pike/cli/command-objects/port.html
Also see:
https://developer.openstack.org/api-ref/compute/#port-interfaces-servers-os-interface
This commit adds:
- a connection to the neutron network API for functionality that is not exposed through
the nova compute api
- an OpenStack_2_PortInterface object
- an OpenStack_2_PortInterfaceState object for port interface states
- an ex_list_ports method (via the neutron api)
- an ex_delete_port method (via the neutron api)
- an ex_detach_port_interface method (via the nova api)
- an ex_attach_port_interface method (via the nova api)
Signed-off-by: Quentin Pradet <qu...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/c24c71fd
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/c24c71fd
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/c24c71fd
Branch: refs/heads/trunk
Commit: c24c71fd3265270cc2df0ab08f53239d7a06063c
Parents: 1ac9467
Author: Rick van de Loo <ri...@gmail.com>
Authored: Thu Jul 5 17:18:27 2018 +0200
Committer: Quentin Pradet <qu...@apache.org>
Committed: Fri Jul 6 10:02:23 2018 +0400
----------------------------------------------------------------------
libcloud/compute/drivers/openstack.py | 209 ++++++++++++++++++-
libcloud/test/common/test_openstack_identity.py | 7 +-
.../compute/fixtures/openstack/_v2_0__auth.json | 22 ++
.../fixtures/openstack_v1.1/_ports_v2.json | 185 ++++++++++++++++
libcloud/test/compute/test_openstack.py | 83 +++++++-
5 files changed, 499 insertions(+), 7 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/libcloud/blob/c24c71fd/libcloud/compute/drivers/openstack.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/openstack.py b/libcloud/compute/drivers/openstack.py
index 5307376..e0a5ff0 100644
--- a/libcloud/compute/drivers/openstack.py
+++ b/libcloud/compute/drivers/openstack.py
@@ -38,12 +38,13 @@ from libcloud.common.openstack import OpenStackDriverMixin
from libcloud.common.openstack import OpenStackException
from libcloud.common.openstack import OpenStackResponse
from libcloud.utils.networking import is_public_subnet
-from libcloud.compute.base import NodeSize, NodeImage, NodeImageMember
+from libcloud.compute.base import NodeSize, NodeImage, NodeImageMember, \
+ UuidMixin
from libcloud.compute.base import (NodeDriver, Node, NodeLocation,
StorageVolume, VolumeSnapshot)
from libcloud.compute.base import KeyPair
from libcloud.compute.types import NodeState, StorageVolumeState, Provider, \
- VolumeSnapshotState
+ VolumeSnapshotState, Type
from libcloud.pricing import get_size_price
from libcloud.utils.xml import findall
from libcloud.utils.py3 import ET
@@ -59,6 +60,8 @@ __all__ = [
'OpenStack_1_1_NodeDriver',
'OpenStack_1_1_FloatingIpPool',
'OpenStack_1_1_FloatingIpAddress',
+ 'OpenStack_2_PortInterfaceState',
+ 'OpenStack_2_PortInterface',
'OpenStackNodeDriver'
]
@@ -80,6 +83,12 @@ class OpenStackImageConnection(OpenStackBaseConnection):
service_region = 'RegionOne'
+class OpenStackNetworkConnection(OpenStackBaseConnection):
+ service_type = 'network'
+ service_name = 'neutron'
+ service_region = 'RegionOne'
+
+
class OpenStackNodeDriver(NodeDriver, OpenStackDriverMixin):
"""
Base OpenStack node driver. Should not be used directly.
@@ -2491,6 +2500,25 @@ class OpenStack_2_ImageConnection(OpenStackImageConnection):
return json.dumps(data)
+class OpenStack_2_NetworkConnection(OpenStackNetworkConnection):
+ responseCls = OpenStack_1_1_Response
+ accept_format = 'application/json'
+ default_content_type = 'application/json; charset=UTF-8'
+
+ def encode_data(self, data):
+ return json.dumps(data)
+
+
+class OpenStack_2_PortInterfaceState(Type):
+ """
+ Standard states of OpenStack_2_PortInterfaceState
+ """
+ BUILD = 'build'
+ ACTIVE = 'active'
+ DOWN = 'down'
+ UNKNOWN = 'unknown'
+
+
class OpenStack_2_NodeDriver(OpenStack_1_1_NodeDriver):
"""
OpenStack node driver.
@@ -2514,11 +2542,33 @@ class OpenStack_2_NodeDriver(OpenStack_1_1_NodeDriver):
# image/v2/index.html#list-image-members
image_connectionCls = OpenStack_2_ImageConnection
image_connection = None
+
+ # Similarly not all node-related operations are exposed through the
+ # compute API
+ # See https://developer.openstack.org/api-ref/compute/
+ # For example, creating a new node in an OpenStack that is configured to
+ # create a new port for every new instance will make it so that if that
+ # port is detached it disappears. But if the port is manually created
+ # beforehand using the neutron network API and node is booted with that
+ # port pre-specified, then detaching that port later will result in that
+ # becoming a re-attachable resource much like a floating ip. So because
+ # even though this is the compute driver, we do connect to the networking
+ # API here because some operations relevant for compute can only be
+ # accessed from there.
+ network_connectionCls = OpenStack_2_NetworkConnection
+ network_connection = None
type = Provider.OPENSTACK
features = {"create_node": ["generates_password"]}
_networks_url_prefix = '/os-networks'
+ PORT_INTERFACE_MAP = {
+ 'BUILD': OpenStack_2_PortInterfaceState.BUILD,
+ 'ACTIVE': OpenStack_2_PortInterfaceState.ACTIVE,
+ 'DOWN': OpenStack_2_PortInterfaceState.DOWN,
+ 'UNKNOWN': OpenStack_2_PortInterfaceState.UNKNOWN
+ }
+
def __init__(self, *args, **kwargs):
original_connectionCls = self.connectionCls
self._ex_force_api_version = str(kwargs.pop('ex_force_api_version',
@@ -2532,11 +2582,47 @@ class OpenStack_2_NodeDriver(OpenStack_1_1_NodeDriver):
super(OpenStack_2_NodeDriver, self).__init__(*args, **kwargs)
self.image_connection = self.connection
- # We run the init again to get the compute API connection
+ # We run the init again to get the Neutron V2 API connection
+ # and put that on the object under self.network_connection.
+ self.connectionCls = self.network_connectionCls
+ super(OpenStack_2_NodeDriver, self).__init__(*args, **kwargs)
+ self.network_connection = self.connection
+
+ # We run the init once again to get the compute API connection
# and that's put under self.connection as normal.
self.connectionCls = original_connectionCls
super(OpenStack_2_NodeDriver, self).__init__(*args, **kwargs)
+ def _to_port(self, element):
+ created = element['created_at']
+ updated = element.get('updated_at')
+ return OpenStack_2_PortInterface(
+ id=element['id'],
+ state=self.PORT_INTERFACE_MAP.get(
+ element.get('status'), OpenStack_2_PortInterfaceState.UNKNOWN
+ ),
+ created=created,
+ driver=self,
+ extra=dict(
+ allowed_address_pairs=element['allowed_address_pairs'],
+ binding_vnic_type=element['binding:vnic_type'],
+ device_id=element['device_id'],
+ description=element['description'],
+ device_owner=element['device_owner'],
+ fixed_ips=element['fixed_ips'],
+ mac_address=element['mac_address'],
+ name=element['name'],
+ network_id=element['network_id'],
+ project_id=element['project_id'],
+ port_security_enabled=element['port_security_enabled'],
+ revision_number=element['revision_number'],
+ security_groups=element['security_groups'],
+ tags=element['tags'],
+ tenant_id=element['tenant_id'],
+ updated=updated,
+ )
+ )
+
def get_image(self, image_id):
"""
Get a NodeImage using the V2 Glance API
@@ -2696,6 +2782,73 @@ class OpenStack_2_NodeDriver(OpenStack_1_1_NodeDriver):
)
return self._to_image_member(response.object)
+ def ex_list_ports(self):
+ """
+ List all OpenStack_2_PortInterfaces
+
+ https://developer.openstack.org/api-ref/network/v2/#list-ports
+
+ :rtype: ``list`` of :class:`OpenStack_2_PortInterface`
+ """
+ response = self.network_connection.request(
+ '/v2.0/ports'
+ )
+ return [self._to_port(port) for port in response.object['ports']]
+
+ def ex_delete_port(self, port):
+ """
+ Delete an OpenStack_2_PortInterface
+
+ https://developer.openstack.org/api-ref/network/v2/#delete-port
+
+ :param port: port interface to remove
+ :type port: :class:`OpenStack_2_PortInterface`
+
+ :rtype: ``bool``
+ """
+ response = self.network_connection.request(
+ '/v2.0/ports/%s' % port.id, method='DELETE'
+ )
+ return response.success()
+
+ def ex_detach_port_interface(self, node, port):
+ """
+ Detaches an OpenStack_2_PortInterface interface from a Node.
+ :param node: node
+ :type node: :class:`Node`
+
+ :param port: port interface to remove
+ :type port: :class:`OpenStack_2_PortInterface`
+
+ :rtype: ``bool``
+ """
+ return self.connection.request(
+ '/servers/%s/os-interface/%s' % (node.id, port.id),
+ method='DELETE'
+ ).success()
+
+ def ex_attach_port_interface(self, node, port):
+ """
+ Attaches an OpenStack_2_PortInterface to a Node.
+
+ :param node: node
+ :type node: :class:`Node`
+
+ :param port: port interface to remove
+ :type port: :class:`OpenStack_2_PortInterface`
+
+ :rtype: ``bool``
+ """
+ data = {
+ 'interfaceAttachment': {
+ 'port_id': port.id
+ }
+ }
+ return self.connection.request(
+ '/servers/{}/os-interface'.format(node.id),
+ method='POST', data=data
+ ).success()
+
class OpenStack_1_1_FloatingIpPool(object):
"""
@@ -2800,3 +2953,53 @@ class OpenStack_1_1_FloatingIpAddress(object):
return ('<OpenStack_1_1_FloatingIpAddress: id=%s, ip_addr=%s,'
' pool=%s, driver=%s>'
% (self.id, self.ip_address, self.pool, self.driver))
+
+
+class OpenStack_2_PortInterface(UuidMixin):
+ """
+ Port Interface info. Similar in functionality to a floating IP (can be
+ attached / detached from a compute instance) but implementation-wise a
+ bit different.
+
+ > A port is a connection point for attaching a single device, such as the
+ > NIC of a server, to a network. The port also describes the associated
+ > network configuration, such as the MAC and IP addresses to be used on
+ > that port.
+ https://docs.openstack.org/python-openstackclient/pike/cli/command-objects/port.html
+
+ Also see:
+ https://developer.openstack.org/api-ref/compute/#port-interfaces-servers-os-interface
+ """
+
+ def __init__(self, id, state, driver, created=None, extra=None):
+ """
+ :param id: Port Interface ID.
+ :type id: ``str``
+ :param state: State of the OpenStack_2_PortInterface.
+ :type state: :class:`.OpenStack_2_PortInterfaceState`
+ :param created: A datetime object that represents when the
+ port interface was created
+ :type created: ``datetime.datetime``
+ :param extra: Optional provided specific attributes associated with
+ this image.
+ :type extra: ``dict``
+ """
+ self.id = str(id)
+ self.state = state
+ self.driver = driver
+ self.created = created
+ self.extra = extra or {}
+ UuidMixin.__init__(self)
+
+ def delete(self):
+ """
+ Delete this Port Interface
+
+ :rtype: ``bool``
+ """
+ return self.driver.ex_delete_port(self)
+
+ def __repr__(self):
+ return (('<OpenStack_2_PortInterface: id=%s, state=%s, '
+ 'driver=%s ...>')
+ % (self.id, self.state, self.driver.name))
http://git-wip-us.apache.org/repos/asf/libcloud/blob/c24c71fd/libcloud/test/common/test_openstack_identity.py
----------------------------------------------------------------------
diff --git a/libcloud/test/common/test_openstack_identity.py b/libcloud/test/common/test_openstack_identity.py
index 9ac042c..c36f13a 100644
--- a/libcloud/test/common/test_openstack_identity.py
+++ b/libcloud/test/common/test_openstack_identity.py
@@ -525,7 +525,7 @@ class OpenStackServiceCatalogTestCase(unittest.TestCase):
catalog = OpenStackServiceCatalog(service_catalog=service_catalog,
auth_version='2.0')
entries = catalog.get_entries()
- self.assertEqual(len(entries), 7)
+ self.assertEqual(len(entries), 8)
entry = [e for e in entries if e.service_name == 'cloudServers'][0]
self.assertEqual(entry.service_type, 'compute')
@@ -591,8 +591,8 @@ class OpenStackServiceCatalogTestCase(unittest.TestCase):
catalog = OpenStackServiceCatalog(service_catalog=service_catalog,
auth_version='2.0')
service_types = catalog.get_service_types()
- self.assertEqual(service_types, ['compute', 'image', 'object-store',
- 'rax:object-cdn'])
+ self.assertEqual(service_types, ['compute', 'image', 'network',
+ 'object-store', 'rax:object-cdn'])
service_types = catalog.get_service_types(region='ORD')
self.assertEqual(service_types, ['rax:object-cdn'])
@@ -611,6 +611,7 @@ class OpenStackServiceCatalogTestCase(unittest.TestCase):
'cloudServersOpenStack',
'cloudServersPreprod',
'glance',
+ 'neutron',
'nova'])
service_names = catalog.get_service_names(service_type='compute')
http://git-wip-us.apache.org/repos/asf/libcloud/blob/c24c71fd/libcloud/test/compute/fixtures/openstack/_v2_0__auth.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/openstack/_v2_0__auth.json b/libcloud/test/compute/fixtures/openstack/_v2_0__auth.json
index 91fe35b..79c6776 100644
--- a/libcloud/test/compute/fixtures/openstack/_v2_0__auth.json
+++ b/libcloud/test/compute/fixtures/openstack/_v2_0__auth.json
@@ -101,6 +101,28 @@
{
"endpoints": [
{
+ "region": "RegionOne",
+ "tenantId": "1337",
+ "publicURL": "https://test_endpoint.com/v2/1337",
+ "versionInfo": "https://test_endpoint.com/v2/",
+ "versionList": "https://test_endpoint.com/",
+ "versionId": "2"
+ },
+ {
+ "region": "fr1",
+ "tenantId": "1337",
+ "publicURL": "https://test_endpoint.com/v2/1337",
+ "versionInfo": "https://test_endpoint.com/v2/",
+ "versionList": "https://test_endpoint.com/",
+ "versionId": "2"
+ }
+ ],
+ "name": "neutron",
+ "type": "network"
+ },
+ {
+ "endpoints": [
+ {
"region": "DFW",
"tenantId": "613469",
"publicURL": "https://dfw.servers.api.rackspacecloud.com/v2/1337",
http://git-wip-us.apache.org/repos/asf/libcloud/blob/c24c71fd/libcloud/test/compute/fixtures/openstack_v1.1/_ports_v2.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/openstack_v1.1/_ports_v2.json b/libcloud/test/compute/fixtures/openstack_v1.1/_ports_v2.json
new file mode 100644
index 0000000..e31f8f3
--- /dev/null
+++ b/libcloud/test/compute/fixtures/openstack_v1.1/_ports_v2.json
@@ -0,0 +1,185 @@
+{
+ "ports": [
+ {
+ "status": "BUILD",
+ "extra_dhcp_opts": [],
+ "description": "",
+ "allowed_address_pairs": [],
+ "tags": [],
+ "network_id": "123c8a8c-6427-4e8f-a805-2035365f4d43",
+ "tenant_id": "abcdec85bee34bb0a44ab8255eb36abc",
+ "created_at": "2018-07-04T14:38:18Z",
+ "admin_state_up": true,
+ "updated_at": "2018-07-05T14:40:43Z",
+ "binding:vnic_type": "normal",
+ "device_owner": "compute:nova",
+ "name": "",
+ "revision_number": 2036,
+ "mac_address": "ba:12:12:8a:b2:73",
+ "port_security_enabled": true,
+ "project_id": "abcdec85bee34bb0a44ab8255eb36abc",
+ "fixed_ips": [
+ {
+ "subnet_id": "1231a12a-125b-4329-a3c5-312ea86a7577",
+ "ip_address": "12.123.12.32"
+ }
+ ],
+ "id": "126da55e-cfcb-41c8-ae39-a26cb8a7e723",
+ "security_groups": [
+ "abcfb112-5b5c-4c6b-8b3f-dbaee57df440"
+ ],
+ "device_id": "95e75643-2008-123f-ad13-e20ea64e3c87"
+ },
+ {
+ "status": "BUILD",
+ "extra_dhcp_opts": [],
+ "description": "porttest",
+ "allowed_address_pairs": [],
+ "tags": [],
+ "network_id": "123c8a8c-6427-4e8f-a805-2035365f4d43",
+ "tenant_id": "abcdec85bee34bb0a44ab8255eb36abc",
+ "created_at": "2018-07-05T12:38:50Z",
+ "admin_state_up": true,
+ "updated_at": "2018-07-05T14:40:43Z",
+ "binding:vnic_type": "normal",
+ "device_owner": "compute:nova",
+ "name": "porttest",
+ "revision_number": 865,
+ "mac_address": "ba:12:12:48:42:9b",
+ "port_security_enabled": true,
+ "project_id": "abcdec85bee34bb0a44ab8255eb36abc",
+ "fixed_ips": [
+ {
+ "subnet_id": "1231a12a-125b-4329-a3c5-312ea86a7577",
+ "ip_address": "12.123.12.31"
+ }
+ ],
+ "id": "a8f3ddbe-9b29-41ac-9c0a-9ea7cc012dfb",
+ "security_groups": [
+ "abcfb112-5b5c-4c6b-8b3f-dbaee57df440"
+ ],
+ "device_id": "7b4743a6-f7f7-4764-9854-cf43312e6d49"
+ },
+ {
+ "status": "DOWN",
+ "extra_dhcp_opts": [],
+ "description": "",
+ "allowed_address_pairs": [],
+ "tags": [],
+ "network_id": "123c8a8c-6427-4e8f-a805-2035365f4d43",
+ "tenant_id": "abcdec85bee34bb0a44ab8255eb36abc",
+ "created_at": "2018-07-05T13:09:27Z",
+ "admin_state_up": true,
+ "updated_at": "2018-07-05T13:29:38Z",
+ "binding:vnic_type": "normal",
+ "device_owner": "compute:nova",
+ "name": "",
+ "revision_number": 10,
+ "mac_address": "ba:12:12:95:13:cc",
+ "port_security_enabled": true,
+ "project_id": "abcdec85bee34bb0a44ab8255eb36abc",
+ "fixed_ips": [
+ {
+ "subnet_id": "1231a12a-125b-4329-a3c5-312ea86a7577",
+ "ip_address": "12.123.12.44"
+ }
+ ],
+ "id": "bad9af6a-121d-4772-9ae0-7d127b712f5d",
+ "security_groups": [
+ "abcfb112-5b5c-4c6b-8b3f-dbaee57df440"
+ ],
+ "device_id": "500d78d1-f84f-4949-12da-5205c1237121"
+ },
+ {
+ "status": "DOWN",
+ "extra_dhcp_opts": [],
+ "description": "testport",
+ "allowed_address_pairs": [],
+ "tags": [],
+ "network_id": "123c8a8c-6427-4e8f-a805-2035365f4d43",
+ "tenant_id": "abcdec85bee34bb0a44ab8255eb36abc",
+ "created_at": "2018-07-05T11:59:13Z",
+ "admin_state_up": true,
+ "updated_at": "2018-07-05T12:39:48Z",
+ "binding:vnic_type": "normal",
+ "device_owner": "",
+ "name": "testport",
+ "revision_number": 32,
+ "mac_address": "ba:12:12:6f:ea:12",
+ "port_security_enabled": true,
+ "project_id": "abcdec85bee34bb0a44ab8255eb36abc",
+ "fixed_ips": [
+ {
+ "subnet_id": "1231a12a-125b-4329-a3c5-312ea86a7577",
+ "ip_address": "12.123.12.12"
+ }
+ ],
+ "id": "c21297ca-4e68-4384-badf-10903cd2cbb0",
+ "security_groups": [
+ "abcfb112-5b5c-4c6b-8b3f-dbaee57df440"
+ ],
+ "device_id": ""
+ },
+ {
+ "status": "DOWN",
+ "extra_dhcp_opts": [],
+ "description": "testport",
+ "allowed_address_pairs": [],
+ "tags": [],
+ "network_id": "123c8a8c-6427-4e8f-a805-2035365f4d43",
+ "tenant_id": "abcdec85bee34bb0a44ab8255eb36abc",
+ "created_at": "2018-07-05T11:56:59Z",
+ "admin_state_up": true,
+ "updated_at": "2018-07-05T11:57:00Z",
+ "binding:vnic_type": "normal",
+ "device_owner": "",
+ "name": "testport",
+ "revision_number": 3,
+ "mac_address": "ba:12:12:e6:03:ba",
+ "port_security_enabled": true,
+ "project_id": "abcdec85bee34bb0a44ab8255eb36abc",
+ "fixed_ips": [
+ {
+ "subnet_id": "1231a12a-125b-4329-a3c5-312ea86a7577",
+ "ip_address": "12.123.12.28"
+ }
+ ],
+ "id": "ca335147-273c-4c72-9bab-11a122a95ce1",
+ "security_groups": [
+ "abcfb112-5b5c-4c6b-8b3f-dbaee57df440"
+ ],
+ "device_id": ""
+ },
+ {
+ "status": "DOWN",
+ "extra_dhcp_opts": [],
+ "description": "testport",
+ "allowed_address_pairs": [],
+ "tags": [],
+ "network_id": "123c8a8c-6427-4e8f-a805-2035365f4d43",
+ "tenant_id": "abcdec85bee34bb0a44ab8255eb36abc",
+ "created_at": "2018-07-05T11:12:17Z",
+ "admin_state_up": true,
+ "updated_at": "2018-07-05T11:12:17Z",
+ "binding:vnic_type": "normal",
+ "device_owner": "",
+ "name": "testport",
+ "revision_number": 3,
+ "mac_address": "ba:12:12:12:12:12",
+ "port_security_enabled": true,
+ "project_id": "abcdec85bee34bb0a44ab8255eb36abc",
+ "fixed_ips": [
+ {
+ "subnet_id": "1231a12a-125b-4329-a3c5-312ea86a7577",
+ "ip_address": "12.123.12.12"
+ }
+ ],
+ "id": "a128dec6-4f3a-45c4-a89c-678f69a72044",
+ "security_groups": [
+ "abcfb112-5b5c-4c6b-8b3f-dbaee57df440"
+ ],
+ "device_id": ""
+ }
+ ]
+}
+
http://git-wip-us.apache.org/repos/asf/libcloud/blob/c24c71fd/libcloud/test/compute/test_openstack.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_openstack.py b/libcloud/test/compute/test_openstack.py
index 54606ef..19b75e7 100644
--- a/libcloud/test/compute/test_openstack.py
+++ b/libcloud/test/compute/test_openstack.py
@@ -47,7 +47,7 @@ from libcloud.compute.drivers.openstack import (
OpenStack_1_1_FloatingIpAddress, OpenStackKeyPair,
OpenStack_1_0_Connection,
OpenStackNodeDriver,
- OpenStack_2_NodeDriver)
+ OpenStack_2_NodeDriver, OpenStack_2_PortInterfaceState)
from libcloud.compute.base import Node, NodeImage, NodeSize
from libcloud.pricing import set_pricing, clear_pricing_data
@@ -1578,6 +1578,11 @@ class OpenStack_2_Tests(OpenStack_1_1_Tests):
# normally authentication happens lazily, but we force it here
self.driver.image_connection._populate_hosts_and_request_paths()
+ self.driver_klass.network_connectionCls.conn_class = OpenStack_2_0_MockHttp
+ self.driver_klass.network_connectionCls.auth_url = "https://auth.api.example.com"
+ # normally authentication happens lazily, but we force it here
+ self.driver.network_connection._populate_hosts_and_request_paths()
+
def test_ex_force_auth_token_passed_to_connection(self):
base_url = 'https://servers.api.rackspacecloud.com/v1.1/slug'
kwargs = {
@@ -1692,6 +1697,57 @@ class OpenStack_2_Tests(OpenStack_1_1_Tests):
self.assertEqual(image_member.extra['updated'], '2018-03-02T14:20:37Z')
self.assertEqual(image_member.extra['schema'], '/v2/schemas/member')
+ def test_ex_list_ports(self):
+ ports = self.driver.ex_list_ports()
+
+ port = ports[0]
+ self.assertEqual(port.id, '126da55e-cfcb-41c8-ae39-a26cb8a7e723')
+ self.assertEqual(port.state, OpenStack_2_PortInterfaceState.BUILD)
+ self.assertEqual(port.created, '2018-07-04T14:38:18Z')
+ self.assertEqual(
+ port.extra['network_id'],
+ '123c8a8c-6427-4e8f-a805-2035365f4d43'
+ )
+ self.assertEqual(
+ port.extra['project_id'],
+ 'abcdec85bee34bb0a44ab8255eb36abc'
+ )
+ self.assertEqual(
+ port.extra['tenant_id'],
+ 'abcdec85bee34bb0a44ab8255eb36abc'
+ )
+ self.assertEqual(port.extra['name'], '')
+
+ def test_ex_delete_port(self):
+ ports = self.driver.ex_list_ports()
+ port = ports[0]
+
+ ret = self.driver.ex_delete_port(port)
+
+ self.assertTrue(ret)
+
+ def test_detach_port_interface(self):
+ node = Node(id='1c01300f-ef97-4937-8f03-ac676d6234be', name=None,
+ state=None, public_ips=None, private_ips=None,
+ driver=self.driver)
+ ports = self.driver.ex_list_ports()
+ port = ports[0]
+
+ ret = self.driver.ex_detach_port_interface(node, port)
+
+ self.assertTrue(ret)
+
+ def test_attach_port_interface(self):
+ node = Node(id='1c01300f-ef97-4937-8f03-ac676d6234be', name=None,
+ state=None, public_ips=None, private_ips=None,
+ driver=self.driver)
+ ports = self.driver.ex_list_ports()
+ port = ports[0]
+
+ ret = self.driver.ex_attach_port_interface(node, port)
+
+ self.assertTrue(ret)
+
class OpenStack_1_1_FactoryMethodTests(OpenStack_1_1_Tests):
should_list_locations = False
@@ -1905,6 +1961,31 @@ class OpenStack_1_1_MockHttp(MockHttp, unittest.TestCase):
else:
raise NotImplementedError()
+ def _v2_1337_v2_0_ports(self, method, url, body, headers):
+ if method == "GET":
+ body = self.fixtures.load('_ports_v2.json')
+ return (httplib.OK, body, self.json_content_headers, httplib.responses[httplib.OK])
+ else:
+ raise NotImplementedError()
+
+ def _v2_1337_v2_0_ports_126da55e_cfcb_41c8_ae39_a26cb8a7e723(self, method, url, body, headers):
+ if method == "DELETE":
+ return (httplib.NO_CONTENT, "", {}, httplib.responses[httplib.NO_CONTENT])
+ else:
+ raise NotImplementedError()
+
+ def _v2_1337_servers_1c01300f_ef97_4937_8f03_ac676d6234be_os_interface_126da55e_cfcb_41c8_ae39_a26cb8a7e723(self, method, url, body, headers):
+ if method == "DELETE":
+ return (httplib.NO_CONTENT, "", {}, httplib.responses[httplib.NO_CONTENT])
+ else:
+ raise NotImplementedError()
+
+ def _v2_1337_servers_1c01300f_ef97_4937_8f03_ac676d6234be_os_interface(self, method, url, body, headers):
+ if method == "POST":
+ return (httplib.NO_CONTENT, "", {}, httplib.responses[httplib.NO_CONTENT])
+ else:
+ raise NotImplementedError()
+
def _v1_1_slug_servers_1c01300f_ef97_4937_8f03_ac676d6234be_os_security_groups(self, method, url, body, headers):
if method == "GET":
body = self.fixtures.load(
[2/2] libcloud git commit: Add changes for #1225
Posted by qu...@apache.org.
Add changes for #1225
Closes #1225
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/b2b7684a
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/b2b7684a
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/b2b7684a
Branch: refs/heads/trunk
Commit: b2b7684a72aeca77d35b64a011dc022efb0761b9
Parents: c24c71f
Author: Quentin Pradet <qu...@apache.org>
Authored: Fri Jul 6 10:11:56 2018 +0400
Committer: Quentin Pradet <qu...@apache.org>
Committed: Fri Jul 6 10:11:56 2018 +0400
----------------------------------------------------------------------
CHANGES.rst | 3 +++
1 file changed, 3 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/libcloud/blob/b2b7684a/CHANGES.rst
----------------------------------------------------------------------
diff --git a/CHANGES.rst b/CHANGES.rst
index 0e1925a..296a52b 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -87,6 +87,9 @@ Compute
- [OpenStack] Fix API doc for delete_floating_ip (GITHUB-1218)
[Ken Dreyer]
+- [OpenStack] Implement port attaching/detaching (GITHUB-1225)
+ [Rick van de Loo]
+
- [Scaleway] New Scaleway driver (GITHUB-1121)
[Daniel Hunsaker, Nándor István Krácser, Rémy Léone]