Skip to content

Commit 7626da4

Browse files
committed
fix(ssh): don't raise exception when default ssh keys can't be found
PR canonical#406 broke some end consumers/users of pycloudlib on systems where 1) ssh keys are not set in the pycloudlib.toml and the ssh key is later set using the Cloud.use_key() method 2) no ssh keys exist at the default paths of '~/.ssh/id_rsa.pub' or '~/.ssh/id_ed25519.pub'. This commit removes/reverts the error that gets raised at the Cloud class instantation when those two cases are true. There was no way for an end user to override/prevent pycloudlib from erroring out besides for creating a fake ssh key at one of the two default paths. Now, a warning is just logged instead, restoring the flexibility pycloudlib preivously provided to end users for setting their ssh keys.
1 parent d856bad commit 7626da4

File tree

4 files changed

+50
-5
lines changed

4 files changed

+50
-5
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1!10.4.0
1+
1!10.5.0

pycloudlib/cloud.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
PycloudlibError,
2020
)
2121
from pycloudlib.instance import BaseInstance
22-
from pycloudlib.key import KeyPair
22+
from pycloudlib.key import KeyPair, UnsetKeyPair
2323
from pycloudlib.util import (
2424
get_timestamped_tag,
2525
log_exception_list,
@@ -251,7 +251,12 @@ def use_key(self, public_key_path, private_key_path=None, name=None):
251251
name: name to reference key by
252252
"""
253253
self._log.debug("using SSH key from %s", public_key_path)
254-
self.key_pair = KeyPair(public_key_path, private_key_path, name)
254+
self.config["public_key_path"] = public_key_path
255+
if private_key_path:
256+
self.config["private_key_path"] = private_key_path
257+
if name:
258+
self.config["key_name"] = name
259+
self._get_ssh_keys()
255260

256261
def _check_and_set_config(
257262
self,
@@ -325,10 +330,12 @@ def _get_ssh_keys(self) -> KeyPair:
325330
public_key_path = pubkey
326331
break
327332
if not public_key_path:
328-
raise PycloudlibError(
333+
self._log.warning(
329334
"No public key path provided and no key found in default locations: "
330-
"'~/.ssh/id_rsa.pub' or '~/.ssh/id_ed25519.pub'"
335+
"'~/.ssh/id_rsa.pub' or '~/.ssh/id_ed25519.pub'. SSH key authentication will "
336+
"not be possible unless a key is later provided with the 'use_key' method."
331337
)
338+
return UnsetKeyPair()
332339
if not os.path.exists(os.path.expanduser(public_key_path)):
333340
raise PycloudlibError(f"Provided public key path '{public_key_path}' does not exist")
334341
if public_key_path not in possible_default_keys:

pycloudlib/errors.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,11 @@ def __init__(self, tag: str, rules_failed: List[str]):
156156
def __str__(self) -> str:
157157
"""Return string representation of the error."""
158158
return f"Tag '{self.tag}' failed the following rules: {', '.join(self.rules_failed)}"
159+
160+
161+
class UnsetSSHKeyError(PycloudlibException):
162+
"""Raised when a SSH key is unset and no default key can be found."""
163+
164+
def __str__(self) -> str:
165+
"""Return string representation of the error."""
166+
return "No SSH key provided and no default key could be found."

pycloudlib/key.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
import os
55

6+
from pycloudlib.errors import UnsetSSHKeyError
7+
68

79
class KeyPair:
810
"""Key Class."""
@@ -44,3 +46,31 @@ def public_key_content(self):
4446
4547
"""
4648
return open(self.public_key_path, encoding="utf-8").read()
49+
50+
51+
class UnsetKeyPair(KeyPair):
52+
"""
53+
Placeholder for unset key pair when no key is provided and default keys can't be found.
54+
55+
This class is a subclass of KeyPair and is used to represent an unset key pair when no key is
56+
provided in the pycloudlib.toml and default keys can't be found on the system.
57+
"""
58+
59+
def __init__(self):
60+
"""Initialize unset key pair."""
61+
self.name = None
62+
self.public_key_path = None
63+
self.private_key_path = None
64+
65+
def __str__(self):
66+
"""Create string representation of class."""
67+
return "UnsetKeyPair()"
68+
69+
@property
70+
def public_key_content(self):
71+
"""
72+
Raise a ValueError when trying to access the public key content for an unset key pair.
73+
74+
This
75+
"""
76+
raise UnsetSSHKeyError("No public key content available for unset key pair")

0 commit comments

Comments
 (0)