diff --git a/libcloud/compute/drivers/__init__.py b/libcloud/compute/drivers/__init__.py index 90dc411d5b..39aa15df7c 100644 --- a/libcloud/compute/drivers/__init__.py +++ b/libcloud/compute/drivers/__init__.py @@ -33,4 +33,5 @@ "vcloud", "vpsnet", "onapp", + "equinixmetal" ] diff --git a/libcloud/compute/drivers/equinixmetal.py b/libcloud/compute/drivers/equinixmetal.py index d97caa2215..e3dd5d5607 100644 --- a/libcloud/compute/drivers/equinixmetal.py +++ b/libcloud/compute/drivers/equinixmetal.py @@ -238,7 +238,7 @@ def ex_list_nodes_for_project(self, ex_project_id, include="plan", page=1, per_p return list(map(self._to_node, data)) def list_locations(self): - data = self.connection.request("/metal/v1/facilities").object["facilities"] + data = self.connection.request("/metal/v1/locations/metros").object["metros"] return list(map(self._to_location, data)) def list_images(self): @@ -285,12 +285,15 @@ def create_node( if not ex_project_id: raise Exception("ex_project_id needs to be specified") - facility = location.extra["code"] + location_code = location.extra["code"] + if not self._valid_location: + raise ValueError("Failed to create node: valid parameter metro [code] is required in the input") + params = { "hostname": name, "plan": size.id, "operating_system": image.id, - "facility": facility, + "metro": location_code, "include": "plan", "billing_cycle": "hourly", } @@ -453,6 +456,8 @@ def _to_node(self, data): size = None if "facility" in data: extra["facility"] = data["facility"] + if "metro" in data and data["metro"] is not None: + extra["metro"] = data["metro"] for key in extra_keys: if key in data: @@ -491,8 +496,8 @@ def _to_size(self, data): except KeyError: cpus = None regions = [ - region.get("href").replace("/metal/v1/facilities/", "") - for region in data.get("available_in", []) + region.get("href").replace("/metal/v1/locations/metros", "") + for region in data.get("available_in_metros", []) ] extra = { "description": data["description"], @@ -675,7 +680,7 @@ def ex_request_address_reservation( "quantity": quantity, } if location_id: - params["facility"] = location_id + params["metro"] = location_id if comments: params["comments"] = comments if customdata: @@ -746,10 +751,8 @@ def create_volume( ): """ Create a new volume. - :param size: Size of volume in gigabytes (required) :type size: ``int`` - :param location: Which data center to create a volume in. If empty, undefined behavior will be selected. (optional) @@ -778,10 +781,8 @@ def create_volume( def destroy_volume(self, volume): """ Destroys a storage volume. - :param volume: Volume to be destroyed :type volume: :class:`StorageVolume` - :rtype: ``bool`` """ path = "/metal/v1/storage/%s" % volume.id @@ -791,13 +792,10 @@ def destroy_volume(self, volume): def attach_volume(self, node, volume): """ Attaches volume to node. - :param node: Node to attach volume to. :type node: :class:`.Node` - :param volume: Volume to attach. :type volume: :class:`.StorageVolume` - :rytpe: ``bool`` """ path = "/metal/v1/storage/%s/attachments" % volume.id @@ -808,14 +806,11 @@ def attach_volume(self, node, volume): def detach_volume(self, volume, ex_node=None, ex_attachment_id=""): """ Detaches a volume from a node. - :param volume: Volume to be detached :type volume: :class:`.StorageVolume` - :param ex_attachment_id: Attachment id to be detached, if empty detach all attachments :type name: ``str`` - :rtype: ``bool`` """ path = "/metal/v1/storage/%s/attachments" % volume.id @@ -841,10 +836,8 @@ def detach_volume(self, volume, ex_node=None, ex_attachment_id=""): def create_volume_snapshot(self, volume, name=""): """ Create a new volume snapshot. - :param volume: Volume to create a snapshot for :type volume: class:`StorageVolume` - :return: The newly created volume snapshot. :rtype: :class:`VolumeSnapshot` """ @@ -856,10 +849,8 @@ def create_volume_snapshot(self, volume, name=""): def destroy_volume_snapshot(self, snapshot): """ Delete a volume snapshot - :param snapshot: volume snapshot to delete :type snapshot: class:`VolumeSnapshot` - :rtype: ``bool`` """ volume_id = snapshot.extra["volume"]["href"].split("/")[-1] @@ -870,10 +861,8 @@ def destroy_volume_snapshot(self, snapshot): def list_volume_snapshots(self, volume, include=""): """ List snapshots for a volume. - :param volume: Volume to list snapshots for :type volume: class:`StorageVolume` - :return: List of volume snapshots. :rtype: ``list`` of :class: `VolumeSnapshot` """ @@ -885,7 +874,7 @@ def list_volume_snapshots(self, volume, include=""): return list(map(self._to_volume_snapshot, data)) def _to_volume_snapshot(self, data): - created = datetime.datetime.strptime(data["created_at"], "%Y-%m-%dT%H:%M:%S") + created = datetime.strptime(data["created_at"], "%Y-%m-%dT%H:%M:%S") return VolumeSnapshot( id=data["id"], name=data["id"], @@ -941,6 +930,14 @@ def ex_describe_attachment(self, attachment_id): data = self.connection.request(path).object return data + def _valid_location(self, metro_code): + if metro_code == None or metro_code == "": + return False + metros = self.connection.request("/metal/v1/locations/metros").object["metros"] + for metro in metros: + if metro["code"] == metro_code: + return True + return False class Project: def __init__(self, project): diff --git a/libcloud/test/compute/fixtures/equinixmetal/facilities.json b/libcloud/test/compute/fixtures/equinixmetal/facilities.json deleted file mode 100644 index 4b0014c4eb..0000000000 --- a/libcloud/test/compute/fixtures/equinixmetal/facilities.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "facilities": [ - { - "id": "e1e9c52e-a0bc-4117-b996-0fc94843ea09", - "name": "Parsippany, NJ", - "code": "ewr1", - "features": ["baremetal"], - "address": null, - "href": "/facilities/e1e9c52e-a0bc-4117-b996-0fc94843ea09" - } - ] -} diff --git a/libcloud/test/compute/fixtures/equinixmetal/metros.json b/libcloud/test/compute/fixtures/equinixmetal/metros.json new file mode 100644 index 0000000000..a2fa6c804d --- /dev/null +++ b/libcloud/test/compute/fixtures/equinixmetal/metros.json @@ -0,0 +1,10 @@ +{ + "metros": [ + { + "id": "d3d6b29f-042d-43b7-b3ce-0bf53d5754ca", + "name": "Dallas", + "code": "da", + "country": "US" + } + ] +} diff --git a/libcloud/test/compute/test_equinixmetal.py b/libcloud/test/compute/test_equinixmetal.py index de12942038..d90c095726 100644 --- a/libcloud/test/compute/test_equinixmetal.py +++ b/libcloud/test/compute/test_equinixmetal.py @@ -303,8 +303,8 @@ def test_destroy_volume(self): class EquinixMetalMockHttp(MockHttp): fixtures = ComputeFileFixtures("equinixmetal") - def _metal_v1_facilities(self, method, url, body, headers): - body = self.fixtures.load("facilities.json") + def _metal_v1_metros(self, method, url, body, headers): + body = self.fixtures.load("metros.json") return (httplib.OK, body, {}, httplib.responses[httplib.OK]) def _metal_v1_plans(self, method, url, body, headers):