Skip to content

Commit a99ea66

Browse files
authored
Merge pull request #110 from packethost/metro
Add support for Metros
2 parents 84dab69 + 275314f commit a99ea66

12 files changed

+274
-15
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ manager = packet.Manager(auth_token="yourapiauthtoken")
8989

9090
device = manager.create_device(project_id='project-id',
9191
hostname='node-name-of-your-choice',
92-
plan='baremetal_1', facility='ewr1',
92+
plan='baremetal_1', metro='sv',
9393
operating_system='ubuntu_18_04')
9494
print(device)
9595
```

packet/Device.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def __init__(self, data, manager):
2828
self.customdata = data.get("customdata", None)
2929
self.operating_system = OperatingSystem(data["operating_system"])
3030
self.facility = data.get("facility")
31+
self.metro = data.get("metro")
3132
self.project = data.get("project")
3233
self.ssh_keys = data.get("ssh_keys")
3334
self.project_lite = data.get("project_lite")

packet/DeviceBatch.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ def __init__(self, data):
88
self.plan = data.get("plan")
99
self.operating_system = data.get("operating_system")
1010
self.facility = data.get("facility")
11+
self.metro = data.get("metro")
1112
self.quantity = data.get("quantity")
1213

1314
def __str__(self):

packet/IPAddress.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# SPDX-License-Identifier: LGPL-3.0-only
33

44
from .Facility import Facility
5+
from .Metro import Metro
56

67

78
class IPAddress:
@@ -22,14 +23,18 @@ def __init__(self, data, manager):
2223
self.customdata = data.get("customdata")
2324
self.project = data.get("project")
2425
self.project_lite = data.get("project_lite")
25-
self.facility = Facility(data.get("facility"))
2626
self.details = data.get("details")
2727
self.assigned_to = data.get("assigned_to")
2828
self.interface = data.get("interface")
2929
self.network = data.get("network")
3030
self.address = data.get("address")
3131
self.gateway = data.get("gateway")
3232

33+
facility = data.get("facility")
34+
self.facility = Facility(facility) if facility else None
35+
metro = data.get("metro")
36+
self.metro = Metro(metro) if metro else None
37+
3338
def delete(self):
3439
return self.manager.call_api("ips/%s" % self.id, type="DELETE")
3540

packet/Manager.py

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from .SSHKey import SSHKey
1111
from .Project import Project
1212
from .Facility import Facility
13+
from .Metro import Metro
1314
from .OperatingSystem import OperatingSystem
1415
from .Volume import Volume
1516
from .BGPConfig import BGPConfig
@@ -41,6 +42,14 @@ def list_facilities(self, params={}):
4142
facilities.append(facility)
4243
return facilities
4344

45+
def list_metros(self, params={}):
46+
data = self.call_api("metros", params=params)
47+
metros = list()
48+
for jsoned in data["metros"]:
49+
metro = Metro(jsoned)
50+
metros.append(metro)
51+
return metros
52+
4453
def list_plans(self, params={}):
4554
data = self.call_api("plans", params=params)
4655
plans = list()
@@ -121,8 +130,8 @@ def create_device(
121130
project_id,
122131
hostname,
123132
plan,
124-
facility,
125-
operating_system,
133+
facility="",
134+
operating_system="",
126135
always_pxe=False,
127136
billing_cycle="hourly",
128137
features={},
@@ -139,11 +148,11 @@ def create_device(
139148
hardware_reservation_id="",
140149
storage={},
141150
customdata={},
151+
metro="",
142152
):
143153

144154
params = {
145155
"billing_cycle": billing_cycle,
146-
"facility": facility,
147156
"features": features,
148157
"hostname": hostname,
149158
"locked": locked,
@@ -157,6 +166,10 @@ def create_device(
157166
"userdata": userdata,
158167
}
159168

169+
if metro != "":
170+
params["metro"] = metro
171+
if facility != "":
172+
params["facility"] = facility
160173
if hardware_reservation_id != "":
161174
params["hardware_reservation_id"] = hardware_reservation_id
162175
if storage:
@@ -319,6 +332,23 @@ def validate_capacity(self, servers):
319332
else:
320333
raise e
321334

335+
# servers is a list of tuples of metro, plan, and quantity.
336+
def validate_metro_capacity(self, servers):
337+
params = {"servers": []}
338+
for server in servers:
339+
params["servers"].append(
340+
{"facility": server[0], "plan": server[1], "quantity": server[2]}
341+
)
342+
343+
try:
344+
data = self.call_api("/capacity/metros", "POST", params)
345+
return all(s["available"] for s in data["servers"])
346+
except PacketError as e: # pragma: no cover
347+
if e.args[0] == "Error 503: Service Unavailable":
348+
return False
349+
else:
350+
raise e
351+
322352
def get_spot_market_prices(self, params={}):
323353
data = self.call_api("/market/spot/prices", params=params)
324354
return data["spot_market_prices"]
@@ -405,20 +435,24 @@ def reserve_ip_address(
405435
project_id,
406436
type,
407437
quantity,
408-
facility,
438+
facility="",
409439
details=None,
410440
comments=None,
411441
tags=list(),
442+
metro="",
412443
):
413444
request = {
414445
"type": type,
415446
"quantity": quantity,
416-
"facility": facility,
417447
"details": details,
418448
"comments": comments,
419449
"tags": tags,
420450
}
421451

452+
if facility != "":
453+
request["facility"] = facility
454+
if metro != "":
455+
request["metro"] = metro
422456
data = self.call_api(
423457
"/projects/%s/ips" % project_id, params=request, type="POST"
424458
)
@@ -575,15 +609,18 @@ def list_vlans(self, project_id, params=None):
575609
return vlans
576610

577611
def create_vlan(
578-
self, project_id, facility, vxlan=None, vlan=None, description=None
612+
self, project_id, facility="", vxlan=None, vlan=None, description=None, metro=""
579613
):
580614
params = {
581615
"project_id": project_id,
582-
"facility": facility,
583616
"vxlan": vxlan,
584617
"vlan": vlan,
585618
"description": description,
586619
}
620+
if facility != "":
621+
params["facility"] = facility
622+
if metro != "":
623+
params["metro"] = metro
587624
data = self.call_api(
588625
"projects/%s/virtual-networks" % project_id, type="POST", params=params
589626
)
@@ -638,14 +675,12 @@ def create_packet_connections(self, params):
638675
"project_id": params["project_id"],
639676
"provider_id": params["provider_id"],
640677
"provider_payload": params["provider_payload"],
641-
"facility": params["facility"],
642678
"port_speed": params["port_speed"],
643679
"vlan": params["vlan"],
644680
}
645-
if "tags" in params:
646-
body["tags"] = params["tags"]
647-
if "description" in params:
648-
body["description"] = params["description"]
681+
for opt in ["tags", "description", "facility", "metro"]:
682+
if opt in params:
683+
body[opt] = params[opt]
649684

650685
data = self.call_api("/packet-connect/connections", type="POST", params=body)
651686
return data

packet/Metro.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# -*- coding: utf-8 -*-
2+
# SPDX-License-Identifier: LGPL-3.0-only
3+
4+
5+
class Metro:
6+
def __init__(self, data):
7+
self.id = data.get("id")
8+
self.code = data.get("code")
9+
self.name = data.get("name")
10+
self.country = data.get("country")
11+
12+
def __str__(self):
13+
return "%s" % self.code
14+
15+
def __repr__(self):
16+
return "{}: {}".format(self.__class__.__name__, self.id)

packet/Vlan.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# SPDX-License-Identifier: LGPL-3.0-only
33
from packet import Project
44
from .Facility import Facility
5+
from .Metro import Metro
56

67

78
class Vlan:
@@ -15,9 +16,13 @@ def __init__(self, data, manager):
1516
self.vxlan = data.get("vxlan")
1617
self.internet_gateway = data.get("internet_gateway")
1718
self.facility_code = data.get("facility_code")
19+
self.metro_code = data.get("metro_code")
1820
self.created_at = data.get("created_at")
21+
facility = data.get("facility", None)
22+
self.facility = Facility(facility) if facility else None
23+
metro = data.get("metro", None)
24+
self.metro = Metro(metro) if metro else None
1925

20-
self.facility = Facility(data.get("facility"))
2126
try:
2227
project_data = self.manager.call_api(
2328
data["assigned_to"]["href"], type="GET"

packet/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from .Email import Email # noqa
1414
from .Event import Event # noqa
1515
from .Facility import Facility # noqa
16+
from .Metro import Metro # noqa
1617
from .OperatingSystem import OperatingSystem # noqa
1718
from .Plan import Plan # noqa
1819
from .Project import Project # noqa

test/fixtures/get_metros.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"metros":[{"id":"0446ac38-aae0-45f5-959c-54d26c4fc3c7","name":"Phoenix","code":"px","country":"US"},{"id":"833225d2-a35a-49cf-a67c-1f84d5d11654","name":"Marseille","code":"mr","country":"FR"},{"id":"96a57b6d-c62c-41b5-ab8e-f8d63a7f9887","name":"Washington DC","code":"dc","country":"US"},{"id":"a04e45e4-4356-458c-b25a-b72cc54bdad1","name":"Atlanta","code":"at","country":"US"},{"id":"932eecda-6808-44b9-a3be-3abef49796ef","name":"New York","code":"ny","country":"US"},{"id":"108b2cfb-246b-45e3-885a-bf3e82fce1a0","name":"Amsterdam","code":"am","country":"NL"},{"id":"5afb3744-f80d-4b49-bf21-50ede9252cfd","name":"Toronto","code":"tr","country":"CA"},{"id":"d2a8e94f-2b42-4440-9c8e-8ef01defcd27","name":"Seoul","code":"sl","country":"KR"},{"id":"d50fd052-34ec-4977-a173-ad6f9266995d","name":"Hong Kong","code":"hk","country":"HK"},{"id":"f6ada324-8226-4bfc-99a8-453d47caf2dc","name":"Singapore","code":"sg","country":"SG"},{"id":"5f72cbf6-96e4-44f2-ae60-213888fa2b9f","name":"Tokyo","code":"ty","country":"JP"},{"id":"b1ac82b2-616c-4405-9424-457ef6edf9ae","name":"Frankfurt","code":"fr","country":"DE"},{"id":"d2f09853-a1aa-4b29-aa9d-682462fd8d1d","name":"Sydney","code":"sy","country":"AU"},{"id":"5f1d3910-2059-4737-8e7d-d4907cfbf27f","name":"London","code":"ld","country":"GB"},{"id":"91fa81e8-db1a-4da1-b218-7beeaab6f8bc","name":"Kansas City","code":"kc","country":"US"},{"id":"f2f0f0b3-5359-4296-a402-56abad842f56","name":"Paris","code":"pa","country":"FR"},{"id":"56c55e99-8125-4f65-af21-a8682e033804","name":"Houston","code":"ho","country":"US"},{"id":"b8ffa6c9-3da2-4cf1-b48d-049002b208fe","name":"Seattle","code":"se","country":"US"},{"id":"2991b022-b8c4-497e-8db7-5a407c3a209b","name":"Silicon Valley","code":"sv","country":"US"},{"id":"bb059cc0-0b2a-4f5b-8a55-219e6b4240da","name":"Los Angeles","code":"la","country":"US"},{"id":"60666d92-e00f-43a8-a9f8-fddf665390ca","name":"Chicago","code":"ch","country":"US"},{"id":"d3d6b29f-042d-43b7-b3ce-0bf53d5754ca","name":"Dallas","code":"da","country":"US"},{"id":"543f8059-65f6-4c2c-b7ad-6dac5eb87085","name":"Pittsburgh","code":"pi","country":"US"},{"id":"583a553a-465a-49f3-a8a9-5fa6b44aa519","name":"Detroit","code":"dt","country":"US"}]}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
{"ip_addresses": [{
2+
"id": "99d5d741-3756-4ebe-a014-34ea7a2e2be1",
3+
"address_family": 4,
4+
"netmask": "255.255.255.254",
5+
"created_at": "2019-07-18T08:46:38Z",
6+
"details": null,
7+
"tags": [],
8+
"public": true,
9+
"cidr": 31,
10+
"management": true,
11+
"manageable": true,
12+
"enabled": true,
13+
"global_ip": null,
14+
"customdata": {},
15+
"project": {},
16+
"project_lite": {},
17+
"facility": {
18+
"id": "8e6470b3-b75e-47d1-bb93-45b225750975",
19+
"name": "Amsterdam, NL",
20+
"code": "ams1",
21+
"features": [
22+
"baremetal",
23+
"storage",
24+
"global_ipv4",
25+
"backend_transfer",
26+
"layer_2"
27+
],
28+
"address": {
29+
"href": "#0688e909-647e-4b21-bdf2-fc056d993fc5"
30+
},
31+
"ip_ranges": [
32+
"2604:1380:2000::/36",
33+
"147.75.204.0/23",
34+
"147.75.100.0/22",
35+
"147.75.80.0/22",
36+
"147.75.32.0/23"
37+
]
38+
},
39+
"assigned_to": {
40+
"href": "/devices/54ffd20d-d972-4c8d-8628-9da18e67ae17"
41+
},
42+
"interface": {
43+
"href": "/ports/02ea0556-df04-4554-b339-760a0d227b44"
44+
},
45+
"network": "147.75.84.94",
46+
"address": "147.75.84.95",
47+
"gateway": "147.75.84.94",
48+
"href": "/ips/99d5d741-3756-4ebe-a014-34ea7a2e2be1"
49+
},
50+
{
51+
"id": "99d5d741-3756-4ebe-a014-34ea7a2e2be2",
52+
"address_family": 4,
53+
"netmask": "255.255.255.254",
54+
"created_at": "2019-07-18T08:46:38Z",
55+
"details": null,
56+
"tags": [],
57+
"public": true,
58+
"cidr": 31,
59+
"management": true,
60+
"manageable": true,
61+
"enabled": true,
62+
"global_ip": null,
63+
"customdata": {},
64+
"project": {},
65+
"project_lite": {},
66+
"facility": {
67+
"id": "8e6470b3-b75e-47d1-bb93-45b225750975",
68+
"name": "Amsterdam, NL",
69+
"code": "ams1",
70+
"features": [
71+
"baremetal",
72+
"storage",
73+
"global_ipv4",
74+
"backend_transfer",
75+
"layer_2"
76+
],
77+
"address": {
78+
"href": "#0688e909-647e-4b21-bdf2-fc056d993fc5"
79+
},
80+
"ip_ranges": [
81+
"2604:1380:2000::/36",
82+
"147.75.204.0/23",
83+
"147.75.100.0/22",
84+
"147.75.80.0/22",
85+
"147.75.32.0/23"
86+
]
87+
},
88+
"assigned_to": {
89+
"href": "/devices/54ffd20d-d972-4c8d-8628-9da18e67ae17"
90+
},
91+
"interface": {
92+
"href": "/ports/02ea0556-df04-4554-b339-760a0d227b44"
93+
},
94+
"network": "147.75.84.94",
95+
"address": "147.75.84.95",
96+
"gateway": "147.75.84.94",
97+
"href": "/ips/99d5d741-3756-4ebe-a014-34ea7a2e2be1"
98+
}]}

0 commit comments

Comments
 (0)