Skip to content

Commit 007189c

Browse files
authored
Merge pull request #80 from grahamc/fixup-project-ssh-keys
2 parents 023f839 + fbaf181 commit 007189c

File tree

3 files changed

+59
-12
lines changed

3 files changed

+59
-12
lines changed

packet/Manager.py

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from packet.Vlan import Vlan
44
from .baseapi import BaseAPI
55
from .baseapi import Error as PacketError
6+
from .baseapi import ResponseError
67
from .Batch import Batch
78
from .Plan import Plan
89
from .Device import Device
@@ -197,11 +198,46 @@ def create_ssh_key(self, label, public_key):
197198
return SSHKey(data, self)
198199

199200
def create_project_ssh_key(self, project_id, label, public_key):
200-
params = {"key": public_key, "label": label}
201-
data = self.call_api(
202-
"projects/%s/ssh-keys" % project_id, type="POST", params=params
203-
)
204-
return SSHKey(data, self)
201+
"""
202+
Successfully creating an SSH key with a Project API Token results
203+
in a 404 from the API. If we get a 404, we try the request again.
204+
205+
If the request actually failed with a 404, we will get another 404
206+
which we raise.
207+
208+
If the request actually succeeded, we will get a 422. In this case,
209+
we will try to list all the keys and find the SSHKey we just
210+
received.
211+
212+
Customer Report Reference: TUVD-0107-UIKB
213+
"""
214+
215+
def issue_req():
216+
try:
217+
params = {"key": public_key, "label": label}
218+
data = self.call_api(
219+
"projects/%s/ssh-keys" % project_id, type="POST", params=params
220+
)
221+
return SSHKey(data, self)
222+
except ResponseError as e:
223+
if e.response.status_code == 422:
224+
# Try to pluck the SSH key from the listing API
225+
keys = [
226+
key
227+
for key in self.list_ssh_keys()
228+
if key.key.strip() == public_key.strip()
229+
]
230+
if len(keys) == 1:
231+
return keys.pop()
232+
raise
233+
234+
try:
235+
return issue_req()
236+
except ResponseError as e:
237+
if e.response.status_code == 404:
238+
return issue_req()
239+
else:
240+
raise
205241

206242
def list_volumes(self, project_id, params={}):
207243
params["include"] = "facility,attachments.device"

packet/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@
2626
from .Organization import Organization # noqa
2727
from .Provider import Provider # noqa
2828
from .baseapi import Error # noqa
29+
from .baseapi import ResponseError # noqa

packet/baseapi.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,21 @@ def cause(self):
1919
return self._cause
2020

2121

22+
class ResponseError(Error):
23+
def __init__(self, resp, data, exception=None):
24+
if not data:
25+
msg = "(empty response)"
26+
elif "errors" in data:
27+
msg = ", ".join(data["errors"])
28+
super().__init__("Error {0}: {1}".format(resp.status_code, msg), exception)
29+
self._response = resp
30+
31+
@property
32+
def response(self):
33+
"""The Requests response which failed"""
34+
return self._response
35+
36+
2237
class JSONReadError(Error):
2338
pass
2439

@@ -84,17 +99,12 @@ def call_api(self, method, type="GET", params=None): # noqa
8499
data = resp.content # pragma: no cover
85100

86101
if not resp.ok: # pragma: no cover
87-
msg = data
88-
if not data:
89-
msg = "(empty response)"
90-
elif "errors" in data:
91-
msg = ", ".join(data["errors"])
92-
raise Error("Error {0}: {1}".format(resp.status_code, msg))
102+
raise ResponseError(resp, data)
93103

94104
try:
95105
resp.raise_for_status()
96106
except requests.HTTPError as e: # pragma: no cover
97-
raise Error("Error {0}: {1}".format(resp.status_code, resp.reason), e)
107+
raise ResponseError(resp, data, e)
98108

99109
self.meta = None
100110
try:

0 commit comments

Comments
 (0)