-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for Metros #110
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
3e608dc
add support for Metros
displague 35da575
add get_metros fixtures
displague 8b5722c
handle null facility and metro in ip/vlan responses
displague 33bc6b1
remove redundant None in data.get(foo, None)
displague 275314f
Add support empty Facility for IPAddress
tyzhnenko File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ | |
from .SSHKey import SSHKey | ||
from .Project import Project | ||
from .Facility import Facility | ||
from .Metro import Metro | ||
from .OperatingSystem import OperatingSystem | ||
from .Volume import Volume | ||
from .BGPConfig import BGPConfig | ||
|
@@ -41,6 +42,14 @@ def list_facilities(self, params={}): | |
facilities.append(facility) | ||
return facilities | ||
|
||
def list_metros(self, params={}): | ||
data = self.call_api("metros", params=params) | ||
metros = list() | ||
for jsoned in data["metros"]: | ||
metro = Metro(jsoned) | ||
metros.append(metro) | ||
return metros | ||
|
||
def list_plans(self, params={}): | ||
data = self.call_api("plans", params=params) | ||
plans = list() | ||
|
@@ -121,8 +130,8 @@ def create_device( | |
project_id, | ||
hostname, | ||
plan, | ||
facility, | ||
operating_system, | ||
facility="", | ||
operating_system="", | ||
always_pxe=False, | ||
billing_cycle="hourly", | ||
features={}, | ||
|
@@ -139,11 +148,11 @@ def create_device( | |
hardware_reservation_id="", | ||
storage={}, | ||
customdata={}, | ||
metro="", | ||
): | ||
|
||
params = { | ||
"billing_cycle": billing_cycle, | ||
"facility": facility, | ||
"features": features, | ||
"hostname": hostname, | ||
"locked": locked, | ||
|
@@ -157,6 +166,10 @@ def create_device( | |
"userdata": userdata, | ||
} | ||
|
||
if metro != "": | ||
params["metro"] = metro | ||
if facility != "": | ||
params["facility"] = facility | ||
if hardware_reservation_id != "": | ||
params["hardware_reservation_id"] = hardware_reservation_id | ||
if storage: | ||
|
@@ -319,6 +332,23 @@ def validate_capacity(self, servers): | |
else: | ||
raise e | ||
|
||
# servers is a list of tuples of metro, plan, and quantity. | ||
def validate_metro_capacity(self, servers): | ||
params = {"servers": []} | ||
for server in servers: | ||
params["servers"].append( | ||
{"facility": server[0], "plan": server[1], "quantity": server[2]} | ||
) | ||
|
||
try: | ||
data = self.call_api("/capacity/metros", "POST", params) | ||
return all(s["available"] for s in data["servers"]) | ||
except PacketError as e: # pragma: no cover | ||
if e.args[0] == "Error 503: Service Unavailable": | ||
return False | ||
else: | ||
raise e | ||
|
||
def get_spot_market_prices(self, params={}): | ||
data = self.call_api("/market/spot/prices", params=params) | ||
return data["spot_market_prices"] | ||
|
@@ -405,20 +435,24 @@ def reserve_ip_address( | |
project_id, | ||
type, | ||
quantity, | ||
facility, | ||
facility="", | ||
details=None, | ||
comments=None, | ||
tags=list(), | ||
metro="", | ||
): | ||
request = { | ||
"type": type, | ||
"quantity": quantity, | ||
"facility": facility, | ||
"details": details, | ||
"comments": comments, | ||
"tags": tags, | ||
} | ||
|
||
if facility != "": | ||
request["facility"] = facility | ||
if metro != "": | ||
request["metro"] = metro | ||
Comment on lines
+452
to
+455
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto |
||
data = self.call_api( | ||
"/projects/%s/ips" % project_id, params=request, type="POST" | ||
) | ||
|
@@ -575,15 +609,18 @@ def list_vlans(self, project_id, params=None): | |
return vlans | ||
|
||
def create_vlan( | ||
self, project_id, facility, vxlan=None, vlan=None, description=None | ||
self, project_id, facility="", vxlan=None, vlan=None, description=None, metro="" | ||
): | ||
params = { | ||
"project_id": project_id, | ||
"facility": facility, | ||
"vxlan": vxlan, | ||
"vlan": vlan, | ||
"description": description, | ||
} | ||
if facility != "": | ||
params["facility"] = facility | ||
if metro != "": | ||
params["metro"] = metro | ||
Comment on lines
+620
to
+623
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto |
||
data = self.call_api( | ||
"projects/%s/virtual-networks" % project_id, type="POST", params=params | ||
) | ||
|
@@ -638,14 +675,12 @@ def create_packet_connections(self, params): | |
"project_id": params["project_id"], | ||
"provider_id": params["provider_id"], | ||
"provider_payload": params["provider_payload"], | ||
"facility": params["facility"], | ||
"port_speed": params["port_speed"], | ||
"vlan": params["vlan"], | ||
} | ||
if "tags" in params: | ||
body["tags"] = params["tags"] | ||
if "description" in params: | ||
body["description"] = params["description"] | ||
for opt in ["tags", "description", "facility", "metro"]: | ||
if opt in params: | ||
body[opt] = params[opt] | ||
|
||
data = self.call_api("/packet-connect/connections", type="POST", params=body) | ||
return data | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# -*- coding: utf-8 -*- | ||
# SPDX-License-Identifier: LGPL-3.0-only | ||
|
||
|
||
class Metro: | ||
def __init__(self, data): | ||
self.id = data.get("id") | ||
self.code = data.get("code") | ||
self.name = data.get("name") | ||
self.country = data.get("country") | ||
|
||
def __str__(self): | ||
return "%s" % self.code | ||
|
||
def __repr__(self): | ||
return "{}: {}".format(self.__class__.__name__, self.id) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -2,6 +2,7 @@ | |||||||||||||
# SPDX-License-Identifier: LGPL-3.0-only | ||||||||||||||
from packet import Project | ||||||||||||||
from .Facility import Facility | ||||||||||||||
from .Metro import Metro | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
class Vlan: | ||||||||||||||
|
@@ -15,9 +16,13 @@ def __init__(self, data, manager): | |||||||||||||
self.vxlan = data.get("vxlan") | ||||||||||||||
self.internet_gateway = data.get("internet_gateway") | ||||||||||||||
self.facility_code = data.get("facility_code") | ||||||||||||||
self.metro_code = data.get("metro_code") | ||||||||||||||
self.created_at = data.get("created_at") | ||||||||||||||
facility = data.get("facility", None) | ||||||||||||||
self.facility = Facility(facility) if facility else None | ||||||||||||||
metro = data.get("metro", None) | ||||||||||||||
Comment on lines
+21
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
self.metro = Metro(metro) if metro else None | ||||||||||||||
|
||||||||||||||
self.facility = Facility(data.get("facility")) | ||||||||||||||
try: | ||||||||||||||
project_data = self.manager.call_api( | ||||||||||||||
data["assigned_to"]["href"], type="GET" | ||||||||||||||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +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"}]} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
{"ip_addresses": [{ | ||
"id": "99d5d741-3756-4ebe-a014-34ea7a2e2be1", | ||
"address_family": 4, | ||
"netmask": "255.255.255.254", | ||
"created_at": "2019-07-18T08:46:38Z", | ||
"details": null, | ||
"tags": [], | ||
"public": true, | ||
"cidr": 31, | ||
"management": true, | ||
"manageable": true, | ||
"enabled": true, | ||
"global_ip": null, | ||
"customdata": {}, | ||
"project": {}, | ||
"project_lite": {}, | ||
"facility": { | ||
"id": "8e6470b3-b75e-47d1-bb93-45b225750975", | ||
"name": "Amsterdam, NL", | ||
"code": "ams1", | ||
"features": [ | ||
"baremetal", | ||
"storage", | ||
"global_ipv4", | ||
"backend_transfer", | ||
"layer_2" | ||
], | ||
"address": { | ||
"href": "#0688e909-647e-4b21-bdf2-fc056d993fc5" | ||
}, | ||
"ip_ranges": [ | ||
"2604:1380:2000::/36", | ||
"147.75.204.0/23", | ||
"147.75.100.0/22", | ||
"147.75.80.0/22", | ||
"147.75.32.0/23" | ||
] | ||
}, | ||
"assigned_to": { | ||
"href": "/devices/54ffd20d-d972-4c8d-8628-9da18e67ae17" | ||
}, | ||
"interface": { | ||
"href": "/ports/02ea0556-df04-4554-b339-760a0d227b44" | ||
}, | ||
"network": "147.75.84.94", | ||
"address": "147.75.84.95", | ||
"gateway": "147.75.84.94", | ||
"href": "/ips/99d5d741-3756-4ebe-a014-34ea7a2e2be1" | ||
}, | ||
{ | ||
"id": "99d5d741-3756-4ebe-a014-34ea7a2e2be2", | ||
"address_family": 4, | ||
"netmask": "255.255.255.254", | ||
"created_at": "2019-07-18T08:46:38Z", | ||
"details": null, | ||
"tags": [], | ||
"public": true, | ||
"cidr": 31, | ||
"management": true, | ||
"manageable": true, | ||
"enabled": true, | ||
"global_ip": null, | ||
"customdata": {}, | ||
"project": {}, | ||
"project_lite": {}, | ||
"facility": { | ||
"id": "8e6470b3-b75e-47d1-bb93-45b225750975", | ||
"name": "Amsterdam, NL", | ||
"code": "ams1", | ||
"features": [ | ||
"baremetal", | ||
"storage", | ||
"global_ipv4", | ||
"backend_transfer", | ||
"layer_2" | ||
], | ||
"address": { | ||
"href": "#0688e909-647e-4b21-bdf2-fc056d993fc5" | ||
}, | ||
"ip_ranges": [ | ||
"2604:1380:2000::/36", | ||
"147.75.204.0/23", | ||
"147.75.100.0/22", | ||
"147.75.80.0/22", | ||
"147.75.32.0/23" | ||
] | ||
}, | ||
"assigned_to": { | ||
"href": "/devices/54ffd20d-d972-4c8d-8628-9da18e67ae17" | ||
}, | ||
"interface": { | ||
"href": "/ports/02ea0556-df04-4554-b339-760a0d227b44" | ||
}, | ||
"network": "147.75.84.94", | ||
"address": "147.75.84.95", | ||
"gateway": "147.75.84.94", | ||
"href": "/ips/99d5d741-3756-4ebe-a014-34ea7a2e2be1" | ||
}]} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would it be ok to have both metro and facility? What if they are incompatible? IIRC for these types of things we let the API handle the error checking/response right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, there's no check to ensure at least one of facility or metro is specified. This can be seen as a bit of change in behavior where previously facility was required and check by Python.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't want to send
{"metro": "", "facility": "ewr1"}
, for example. It results in" is not a valid metro"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we avoid sending an empty string for metro or facility, by not including it in the JSON payload.
We're deliberately working around the previously required
facility
field.Perhaps
facility = None
andmetro = None
would be better defaults? We don't get the same API error with{"metro": null}
as payload.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sending
null
for this field should probably mean something else, and we would be getting lucky that the API treats this as a field omission (in this case). It's not documented.I think we should try to avoid sending any value if we don't want a value (not include metro or facility in the payload in the presence of the other).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about:
Why? It seems to me that one of metro or facility must be required, otherwise the request is garbage right?
I guess similarly, we can choose to require one-and-only-one of metro or facility to be provided (though I'm on the fence on this tbh, the user could call
metro = NY
,facility = NY5
and thats fine (if those are actually valid values), so I'm ok with letting the API do the validity check here))There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The API does not allow for metro + facility in the request, even if the facility is currently included in that metro.
It's not enough to send empty strings for the opposite value. And sending
null
for the opposite value relies on undefined behavior.The request that we send must either contain a non-empty facility or a non-empty metro or else the request is not valid according to the API.
One of those fields (
facility
) was previously required, so now it has been made optional with a default value.This client needs to accept both fields in the parameter list and omit one of those fields from the request. The user can't toggle that behavior with the param list alone, so the function needs logic to do it.
In Packngo we got this for free at serialization time via:
The conditional
params
setting increate_device
is mimicking that behavior.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It results in " is not a valid metro"
-- this is an API error (I didn't make that clear before).The API is handling the validation in all cases, python is not going to throw an early error.
facility
andmetro
tocreate_device
, we'll pass it along to the API. And you'll get an error.create_device
, the API will give you the error.""
to either, the API will give you the error.