Reformat everything with black.

I had to undo the u string prefix removals to not drop Python 2 compatibility.
That's why black isn't enabled in antsibull-nox.toml yet.
This commit is contained in:
Felix Fontein
2025-04-28 09:51:33 +02:00
parent 04a0d38e3b
commit aec1826c34
118 changed files with 11780 additions and 7565 deletions

View File

@@ -44,17 +44,24 @@ def safe_atomic_move(module, path, destination):
def _restore_all_on_failure(f):
def backup_and_restore(self, sources_and_destinations, *args, **kwargs):
backups = [(d, self.module.backup_local(d)) for s, d in sources_and_destinations if os.path.exists(d)]
backups = [
(d, self.module.backup_local(d))
for s, d in sources_and_destinations
if os.path.exists(d)
]
try:
f(self, sources_and_destinations, *args, **kwargs)
except Exception:
for destination, backup in backups:
self.module.atomic_move(os.path.abspath(backup), os.path.abspath(destination))
self.module.atomic_move(
os.path.abspath(backup), os.path.abspath(destination)
)
raise
else:
for destination, backup in backups:
self.module.add_cleanup_file(backup)
return backup_and_restore
@@ -85,10 +92,10 @@ class OpensshModule(object):
def result(self):
result = self._result
result['changed'] = self.changed
result["changed"] = self.changed
if self.module._diff:
result['diff'] = self.diff
result["diff"] = self.diff
return result
@@ -107,6 +114,7 @@ class OpensshModule(object):
def wrapper(self, *args, **kwargs):
if not self.check_mode:
f(self, *args, **kwargs)
return wrapper
@staticmethod
@@ -114,72 +122,92 @@ class OpensshModule(object):
def wrapper(self, *args, **kwargs):
f(self, *args, **kwargs)
self.changed = True
return wrapper
def _check_if_base_dir(self, path):
base_dir = os.path.dirname(path) or '.'
base_dir = os.path.dirname(path) or "."
if not os.path.isdir(base_dir):
self.module.fail_json(
name=base_dir,
msg='The directory %s does not exist or the file is not a directory' % base_dir
msg="The directory %s does not exist or the file is not a directory"
% base_dir,
)
def _get_ssh_version(self):
ssh_bin = self.module.get_bin_path('ssh')
ssh_bin = self.module.get_bin_path("ssh")
if not ssh_bin:
return ""
return parse_openssh_version(self.module.run_command([ssh_bin, '-V', '-q'], check_rc=True)[2].strip())
return parse_openssh_version(
self.module.run_command([ssh_bin, "-V", "-q"], check_rc=True)[2].strip()
)
@_restore_all_on_failure
def _safe_secure_move(self, sources_and_destinations):
"""Moves a list of files from 'source' to 'destination' and restores 'destination' from backup upon failure.
If 'destination' does not already exist, then 'source' permissions are preserved to prevent
exposing protected data ('atomic_move' uses the 'destination' base directory mask for
permissions if 'destination' does not already exists).
If 'destination' does not already exist, then 'source' permissions are preserved to prevent
exposing protected data ('atomic_move' uses the 'destination' base directory mask for
permissions if 'destination' does not already exists).
"""
for source, destination in sources_and_destinations:
if os.path.exists(destination):
self.module.atomic_move(os.path.abspath(source), os.path.abspath(destination))
self.module.atomic_move(
os.path.abspath(source), os.path.abspath(destination)
)
else:
self.module.preserved_copy(source, destination)
def _update_permissions(self, path):
file_args = self.module.load_file_common_arguments(self.module.params)
file_args['path'] = path
file_args["path"] = path
if not self.module.check_file_absent_if_check_mode(path):
self.changed = self.module.set_fs_attributes_if_different(file_args, self.changed)
self.changed = self.module.set_fs_attributes_if_different(
file_args, self.changed
)
else:
self.changed = True
class KeygenCommand(object):
def __init__(self, module):
self._bin_path = module.get_bin_path('ssh-keygen', True)
self._bin_path = module.get_bin_path("ssh-keygen", True)
self._run_command = module.run_command
def generate_certificate(self, certificate_path, identifier, options, pkcs11_provider, principals,
serial_number, signature_algorithm, signing_key_path, type,
time_parameters, use_agent, **kwargs):
args = [self._bin_path, '-s', signing_key_path, '-P', '', '-I', identifier]
def generate_certificate(
self,
certificate_path,
identifier,
options,
pkcs11_provider,
principals,
serial_number,
signature_algorithm,
signing_key_path,
type,
time_parameters,
use_agent,
**kwargs
):
args = [self._bin_path, "-s", signing_key_path, "-P", "", "-I", identifier]
if options:
for option in options:
args.extend(['-O', option])
args.extend(["-O", option])
if pkcs11_provider:
args.extend(['-D', pkcs11_provider])
args.extend(["-D", pkcs11_provider])
if principals:
args.extend(['-n', ','.join(principals)])
args.extend(["-n", ",".join(principals)])
if serial_number is not None:
args.extend(['-z', str(serial_number)])
if type == 'host':
args.extend(['-h'])
args.extend(["-z", str(serial_number)])
if type == "host":
args.extend(["-h"])
if use_agent:
args.extend(['-U'])
args.extend(["-U"])
if time_parameters.validity_string:
args.extend(['-V', time_parameters.validity_string])
args.extend(["-V", time_parameters.validity_string])
if signature_algorithm:
args.extend(['-t', signature_algorithm])
args.extend(["-t", signature_algorithm])
args.append(certificate_path)
return self._run_command(args, **kwargs)
@@ -187,44 +215,62 @@ class KeygenCommand(object):
def generate_keypair(self, private_key_path, size, type, comment, **kwargs):
args = [
self._bin_path,
'-q',
'-N', '',
'-b', str(size),
'-t', type,
'-f', private_key_path,
'-C', comment or ''
"-q",
"-N",
"",
"-b",
str(size),
"-t",
type,
"-f",
private_key_path,
"-C",
comment or "",
]
# "y" must be entered in response to the "overwrite" prompt
data = 'y' if os.path.exists(private_key_path) else None
data = "y" if os.path.exists(private_key_path) else None
return self._run_command(args, data=data, **kwargs)
def get_certificate_info(self, certificate_path, **kwargs):
return self._run_command([self._bin_path, '-L', '-f', certificate_path], **kwargs)
return self._run_command(
[self._bin_path, "-L", "-f", certificate_path], **kwargs
)
def get_matching_public_key(self, private_key_path, **kwargs):
return self._run_command([self._bin_path, '-P', '', '-y', '-f', private_key_path], **kwargs)
return self._run_command(
[self._bin_path, "-P", "", "-y", "-f", private_key_path], **kwargs
)
def get_private_key(self, private_key_path, **kwargs):
return self._run_command([self._bin_path, '-l', '-f', private_key_path], **kwargs)
return self._run_command(
[self._bin_path, "-l", "-f", private_key_path], **kwargs
)
def update_comment(self, private_key_path, comment, force_new_format=True, **kwargs):
if os.path.exists(private_key_path) and not os.access(private_key_path, os.W_OK):
def update_comment(
self, private_key_path, comment, force_new_format=True, **kwargs
):
if os.path.exists(private_key_path) and not os.access(
private_key_path, os.W_OK
):
try:
os.chmod(private_key_path, stat.S_IWUSR + stat.S_IRUSR)
except (IOError, OSError) as e:
raise e("The private key at %s is not writeable preventing a comment update" % private_key_path)
raise e(
"The private key at %s is not writeable preventing a comment update"
% private_key_path
)
command = [self._bin_path, '-q']
command = [self._bin_path, "-q"]
if force_new_format:
command.append('-o')
command.extend(['-c', '-C', comment, '-f', private_key_path])
command.append("-o")
command.extend(["-c", "-C", comment, "-f", private_key_path])
return self._run_command(command, **kwargs)
class PrivateKey(object):
def __init__(self, size, key_type, fingerprint, format=''):
def __init__(self, size, key_type, fingerprint, format=""):
self._size = size
self._type = key_type
self._fingerprint = fingerprint
@@ -258,10 +304,10 @@ class PrivateKey(object):
def to_dict(self):
return {
'size': self._size,
'type': self._type,
'fingerprint': self._fingerprint,
'format': self._format,
"size": self._size,
"type": self._type,
"fingerprint": self._fingerprint,
"format": self._format,
}
@@ -275,11 +321,17 @@ class PublicKey(object):
if not isinstance(other, type(self)):
return NotImplemented
return all([
self._type_string == other._type_string,
self._data == other._data,
(self._comment == other._comment) if self._comment is not None and other._comment is not None else True
])
return all(
[
self._type_string == other._type_string,
self._data == other._data,
(
(self._comment == other._comment)
if self._comment is not None and other._comment is not None
else True
),
]
)
def __ne__(self, other):
return not self == other
@@ -305,19 +357,19 @@ class PublicKey(object):
@classmethod
def from_string(cls, string):
properties = string.strip('\n').split(' ', 2)
properties = string.strip("\n").split(" ", 2)
return cls(
type_string=properties[0],
data=properties[1],
comment=properties[2] if len(properties) > 2 else ""
comment=properties[2] if len(properties) > 2 else "",
)
@classmethod
def load(cls, path):
try:
with open(path, 'r') as f:
properties = f.read().strip(' \n').split(' ', 2)
with open(path, "r") as f:
properties = f.read().strip(" \n").split(" ", 2)
except (IOError, OSError):
raise
@@ -327,25 +379,25 @@ class PublicKey(object):
return cls(
type_string=properties[0],
data=properties[1],
comment='' if len(properties) <= 2 else properties[2],
comment="" if len(properties) <= 2 else properties[2],
)
def to_dict(self):
return {
'comment': self._comment,
'public_key': self._data,
"comment": self._comment,
"public_key": self._data,
}
def parse_private_key_format(path):
with open(path, 'r') as file:
with open(path, "r") as file:
header = file.readline().strip()
if header == '-----BEGIN OPENSSH PRIVATE KEY-----':
return 'SSH'
elif header == '-----BEGIN PRIVATE KEY-----':
return 'PKCS8'
elif header == '-----BEGIN RSA PRIVATE KEY-----':
return 'PKCS1'
if header == "-----BEGIN OPENSSH PRIVATE KEY-----":
return "SSH"
elif header == "-----BEGIN PRIVATE KEY-----":
return "PKCS8"
elif header == "-----BEGIN RSA PRIVATE KEY-----":
return "PKCS1"
return ''
return ""

View File

@@ -48,14 +48,18 @@ class KeypairBackend(OpensshModule):
def __init__(self, module):
super(KeypairBackend, self).__init__(module)
self.comment = self.module.params['comment']
self.private_key_path = self.module.params['path']
self.public_key_path = self.private_key_path + '.pub'
self.regenerate = self.module.params['regenerate'] if not self.module.params['force'] else 'always'
self.state = self.module.params['state']
self.type = self.module.params['type']
self.comment = self.module.params["comment"]
self.private_key_path = self.module.params["path"]
self.public_key_path = self.private_key_path + ".pub"
self.regenerate = (
self.module.params["regenerate"]
if not self.module.params["force"]
else "always"
)
self.state = self.module.params["state"]
self.type = self.module.params["type"]
self.size = self._get_size(self.module.params['size'])
self.size = self._get_size(self.module.params["size"])
self._validate_path()
self.original_private_key = None
@@ -64,31 +68,35 @@ class KeypairBackend(OpensshModule):
self.public_key = None
def _get_size(self, size):
if self.type in ('rsa', 'rsa1'):
if self.type in ("rsa", "rsa1"):
result = 4096 if size is None else size
if result < 1024:
return self.module.fail_json(
msg="For RSA keys, the minimum size is 1024 bits and the default is 4096 bits. " +
"Attempting to use bit lengths under 1024 will cause the module to fail."
msg="For RSA keys, the minimum size is 1024 bits and the default is 4096 bits. "
+ "Attempting to use bit lengths under 1024 will cause the module to fail."
)
elif self.type == 'dsa':
elif self.type == "dsa":
result = 1024 if size is None else size
if result != 1024:
return self.module.fail_json(msg="DSA keys must be exactly 1024 bits as specified by FIPS 186-2.")
elif self.type == 'ecdsa':
return self.module.fail_json(
msg="DSA keys must be exactly 1024 bits as specified by FIPS 186-2."
)
elif self.type == "ecdsa":
result = 256 if size is None else size
if result not in (256, 384, 521):
return self.module.fail_json(
msg="For ECDSA keys, size determines the key length by selecting from one of " +
"three elliptic curve sizes: 256, 384 or 521 bits. " +
"Attempting to use bit lengths other than these three values for ECDSA keys will " +
"cause this module to fail."
msg="For ECDSA keys, size determines the key length by selecting from one of "
+ "three elliptic curve sizes: 256, 384 or 521 bits. "
+ "Attempting to use bit lengths other than these three values for ECDSA keys will "
+ "cause this module to fail."
)
elif self.type == 'ed25519':
elif self.type == "ed25519":
# User input is ignored for `key size` when `key type` is ed25519
result = 256
else:
return self.module.fail_json(msg="%s is not a valid value for key type" % self.type)
return self.module.fail_json(
msg="%s is not a valid value for key type" % self.type
)
return result
@@ -96,13 +104,16 @@ class KeypairBackend(OpensshModule):
self._check_if_base_dir(self.private_key_path)
if os.path.isdir(self.private_key_path):
self.module.fail_json(msg='%s is a directory. Please specify a path to a file.' % self.private_key_path)
self.module.fail_json(
msg="%s is a directory. Please specify a path to a file."
% self.private_key_path
)
def _execute(self):
self.original_private_key = self._load_private_key()
self.original_public_key = self._load_public_key()
if self.state == 'present':
if self.state == "present":
self._validate_key_load()
if self._should_generate():
@@ -149,13 +160,15 @@ class KeypairBackend(OpensshModule):
return os.path.exists(self.public_key_path)
def _validate_key_load(self):
if (self._private_key_exists()
and self.regenerate in ('never', 'fail', 'partial_idempotence')
and (self.original_private_key is None or not self._private_key_readable())):
if (
self._private_key_exists()
and self.regenerate in ("never", "fail", "partial_idempotence")
and (self.original_private_key is None or not self._private_key_readable())
):
self.module.fail_json(
msg="Unable to read the key. The key is protected with a passphrase or broken. " +
"Will not proceed. To force regeneration, call the module with `generate` " +
"set to `full_idempotence` or `always`, or with `force=true`."
msg="Unable to read the key. The key is protected with a passphrase or broken. "
+ "Will not proceed. To force regeneration, call the module with `generate` "
+ "set to `full_idempotence` or `always`, or with `force=true`."
)
@abc.abstractmethod
@@ -165,17 +178,17 @@ class KeypairBackend(OpensshModule):
def _should_generate(self):
if self.original_private_key is None:
return True
elif self.regenerate == 'never':
elif self.regenerate == "never":
return False
elif self.regenerate == 'fail':
elif self.regenerate == "fail":
if not self._private_key_valid():
self.module.fail_json(
msg="Key has wrong type and/or size. Will not proceed. " +
"To force regeneration, call the module with `generate` set to " +
"`partial_idempotence`, `full_idempotence` or `always`, or with `force=true`."
msg="Key has wrong type and/or size. Will not proceed. "
+ "To force regeneration, call the module with `generate` set to "
+ "`partial_idempotence`, `full_idempotence` or `always`, or with `force=true`."
)
return False
elif self.regenerate in ('partial_idempotence', 'full_idempotence'):
elif self.regenerate in ("partial_idempotence", "full_idempotence"):
return not self._private_key_valid()
else:
return True
@@ -184,11 +197,13 @@ class KeypairBackend(OpensshModule):
if self.original_private_key is None:
return False
return all([
self.size == self.original_private_key.size,
self.type == self.original_private_key.type,
self._private_key_valid_backend(),
])
return all(
[
self.size == self.original_private_key.size,
self.type == self.original_private_key.type,
self._private_key_valid_backend(),
]
)
@abc.abstractmethod
def _private_key_valid_backend(self):
@@ -200,13 +215,20 @@ class KeypairBackend(OpensshModule):
temp_private_key, temp_public_key = self._generate_temp_keypair()
try:
self._safe_secure_move([(temp_private_key, self.private_key_path), (temp_public_key, self.public_key_path)])
self._safe_secure_move(
[
(temp_private_key, self.private_key_path),
(temp_public_key, self.public_key_path),
]
)
except OSError as e:
self.module.fail_json(msg=to_native(e))
def _generate_temp_keypair(self):
temp_private_key = os.path.join(self.module.tmpdir, os.path.basename(self.private_key_path))
temp_public_key = temp_private_key + '.pub'
temp_private_key = os.path.join(
self.module.tmpdir, os.path.basename(self.private_key_path)
)
temp_public_key = temp_private_key + ".pub"
try:
self._generate_keypair(temp_private_key)
@@ -239,27 +261,33 @@ class KeypairBackend(OpensshModule):
@OpensshModule.skip_if_check_mode
def _restore_public_key(self):
try:
temp_public_key = self._create_temp_public_key(str(self._get_public_key()) + '\n')
self._safe_secure_move([
(temp_public_key, self.public_key_path)
])
temp_public_key = self._create_temp_public_key(
str(self._get_public_key()) + "\n"
)
self._safe_secure_move([(temp_public_key, self.public_key_path)])
except (IOError, OSError):
self.module.fail_json(
msg="The public key is missing or does not match the private key. " +
"Unable to regenerate the public key."
msg="The public key is missing or does not match the private key. "
+ "Unable to regenerate the public key."
)
if self.comment:
self._update_comment()
def _create_temp_public_key(self, content):
temp_public_key = os.path.join(self.module.tmpdir, os.path.basename(self.public_key_path))
temp_public_key = os.path.join(
self.module.tmpdir, os.path.basename(self.public_key_path)
)
default_permissions = 0o644
existing_permissions = file_mode(self.public_key_path)
try:
secure_write(temp_public_key, existing_permissions or default_permissions, to_bytes(content))
secure_write(
temp_public_key,
existing_permissions or default_permissions,
to_bytes(content),
)
except (IOError, OSError) as e:
self.module.fail_json(msg=to_native(e))
self.module.add_cleanup_file(temp_public_key)
@@ -290,25 +318,29 @@ class KeypairBackend(OpensshModule):
public_key = self.public_key or self.original_public_key
return {
'size': self.size,
'type': self.type,
'filename': self.private_key_path,
'fingerprint': private_key.fingerprint if private_key else '',
'public_key': str(public_key) if public_key else '',
'comment': public_key.comment if public_key else '',
"size": self.size,
"type": self.type,
"filename": self.private_key_path,
"fingerprint": private_key.fingerprint if private_key else "",
"public_key": str(public_key) if public_key else "",
"comment": public_key.comment if public_key else "",
}
@property
def diff(self):
before = self.original_private_key.to_dict() if self.original_private_key else {}
before.update(self.original_public_key.to_dict() if self.original_public_key else {})
before = (
self.original_private_key.to_dict() if self.original_private_key else {}
)
before.update(
self.original_public_key.to_dict() if self.original_public_key else {}
)
after = self.private_key.to_dict() if self.private_key else {}
after.update(self.public_key.to_dict() if self.public_key else {})
return {
'before': before,
'after': after,
"before": before,
"after": after,
}
@@ -316,36 +348,59 @@ class KeypairBackendOpensshBin(KeypairBackend):
def __init__(self, module):
super(KeypairBackendOpensshBin, self).__init__(module)
if self.module.params['private_key_format'] != 'auto':
if self.module.params["private_key_format"] != "auto":
self.module.fail_json(
msg="'auto' is the only valid option for " +
"'private_key_format' when 'backend' is not 'cryptography'"
msg="'auto' is the only valid option for "
+ "'private_key_format' when 'backend' is not 'cryptography'"
)
self.ssh_keygen = KeygenCommand(self.module)
def _generate_keypair(self, private_key_path):
self.ssh_keygen.generate_keypair(private_key_path, self.size, self.type, self.comment, check_rc=True)
self.ssh_keygen.generate_keypair(
private_key_path, self.size, self.type, self.comment, check_rc=True
)
def _get_private_key(self):
rc, private_key_content, err = self.ssh_keygen.get_private_key(self.private_key_path, check_rc=False)
rc, private_key_content, err = self.ssh_keygen.get_private_key(
self.private_key_path, check_rc=False
)
if rc != 0:
raise ValueError(err)
return PrivateKey.from_string(private_key_content)
def _get_public_key(self):
public_key_content = self.ssh_keygen.get_matching_public_key(self.private_key_path, check_rc=True)[1]
public_key_content = self.ssh_keygen.get_matching_public_key(
self.private_key_path, check_rc=True
)[1]
return PublicKey.from_string(public_key_content)
def _private_key_readable(self):
rc, stdout, stderr = self.ssh_keygen.get_matching_public_key(self.private_key_path, check_rc=False)
return not (rc == 255 or any_in(stderr, 'is not a public key file', 'incorrect passphrase', 'load failed'))
rc, stdout, stderr = self.ssh_keygen.get_matching_public_key(
self.private_key_path, check_rc=False
)
return not (
rc == 255
or any_in(
stderr,
"is not a public key file",
"incorrect passphrase",
"load failed",
)
)
def _update_comment(self):
try:
ssh_version = self._get_ssh_version() or "7.8"
force_new_format = LooseVersion('6.5') <= LooseVersion(ssh_version) < LooseVersion('7.8')
self.ssh_keygen.update_comment(self.private_key_path, self.comment, force_new_format=force_new_format, check_rc=True)
force_new_format = (
LooseVersion("6.5") <= LooseVersion(ssh_version) < LooseVersion("7.8")
)
self.ssh_keygen.update_comment(
self.private_key_path,
self.comment,
force_new_format=force_new_format,
check_rc=True,
)
except (IOError, OSError) as e:
self.module.fail_json(msg=to_native(e))
@@ -357,30 +412,41 @@ class KeypairBackendCryptography(KeypairBackend):
def __init__(self, module):
super(KeypairBackendCryptography, self).__init__(module)
if self.type == 'rsa1':
self.module.fail_json(msg="RSA1 keys are not supported by the cryptography backend")
if self.type == "rsa1":
self.module.fail_json(
msg="RSA1 keys are not supported by the cryptography backend"
)
self.passphrase = to_bytes(module.params['passphrase']) if module.params['passphrase'] else None
self.private_key_format = self._get_key_format(module.params['private_key_format'])
self.passphrase = (
to_bytes(module.params["passphrase"])
if module.params["passphrase"]
else None
)
self.private_key_format = self._get_key_format(
module.params["private_key_format"]
)
def _get_key_format(self, key_format):
result = 'SSH'
result = "SSH"
if key_format == 'auto':
if key_format == "auto":
# Default to OpenSSH 7.8 compatibility when OpenSSH is not installed
ssh_version = self._get_ssh_version() or "7.8"
if LooseVersion(ssh_version) < LooseVersion("7.8") and self.type != 'ed25519':
if (
LooseVersion(ssh_version) < LooseVersion("7.8")
and self.type != "ed25519"
):
# OpenSSH made SSH formatted private keys available in version 6.5,
# but still defaulted to PKCS1 format with the exception of ed25519 keys
result = 'PKCS1'
result = "PKCS1"
if result == 'SSH' and not HAS_OPENSSH_PRIVATE_FORMAT:
if result == "SSH" and not HAS_OPENSSH_PRIVATE_FORMAT:
self.module.fail_json(
msg=missing_required_lib(
'cryptography >= 3.0',
reason="to load/dump private keys in the default OpenSSH format for OpenSSH >= 7.8 " +
"or for ed25519 keys"
"cryptography >= 3.0",
reason="to load/dump private keys in the default OpenSSH format for OpenSSH >= 7.8 "
+ "or for ed25519 keys",
)
)
else:
@@ -393,7 +459,7 @@ class KeypairBackendCryptography(KeypairBackend):
keytype=self.type,
size=self.size,
passphrase=self.passphrase,
comment=self.comment or '',
comment=self.comment or "",
)
encoded_private_key = OpensshKeypair.encode_openssh_privatekey(
@@ -401,22 +467,28 @@ class KeypairBackendCryptography(KeypairBackend):
)
secure_write(private_key_path, 0o600, encoded_private_key)
public_key_path = private_key_path + '.pub'
public_key_path = private_key_path + ".pub"
secure_write(public_key_path, 0o644, keypair.public_key)
def _get_private_key(self):
keypair = OpensshKeypair.load(path=self.private_key_path, passphrase=self.passphrase, no_public_key=True)
keypair = OpensshKeypair.load(
path=self.private_key_path, passphrase=self.passphrase, no_public_key=True
)
return PrivateKey(
size=keypair.size,
key_type=keypair.key_type,
fingerprint=keypair.fingerprint,
format=parse_private_key_format(self.private_key_path)
format=parse_private_key_format(self.private_key_path),
)
def _get_public_key(self):
try:
keypair = OpensshKeypair.load(path=self.private_key_path, passphrase=self.passphrase, no_public_key=True)
keypair = OpensshKeypair.load(
path=self.private_key_path,
passphrase=self.passphrase,
no_public_key=True,
)
except OpenSSHError:
# Simulates the null output of ssh-keygen
return ""
@@ -425,7 +497,11 @@ class KeypairBackendCryptography(KeypairBackend):
def _private_key_readable(self):
try:
OpensshKeypair.load(path=self.private_key_path, passphrase=self.passphrase, no_public_key=True)
OpensshKeypair.load(
path=self.private_key_path,
passphrase=self.passphrase,
no_public_key=True,
)
except (InvalidPrivateKeyFileError, InvalidPassphraseError):
return False
@@ -433,7 +509,9 @@ class KeypairBackendCryptography(KeypairBackend):
# when loading an unencrypted key
if self.passphrase:
try:
OpensshKeypair.load(path=self.private_key_path, passphrase=None, no_public_key=True)
OpensshKeypair.load(
path=self.private_key_path, passphrase=None, no_public_key=True
)
except (InvalidPrivateKeyFileError, InvalidPassphraseError):
return True
else:
@@ -442,14 +520,16 @@ class KeypairBackendCryptography(KeypairBackend):
return True
def _update_comment(self):
keypair = OpensshKeypair.load(path=self.private_key_path, passphrase=self.passphrase, no_public_key=True)
keypair = OpensshKeypair.load(
path=self.private_key_path, passphrase=self.passphrase, no_public_key=True
)
try:
keypair.comment = self.comment
except InvalidCommentError as e:
self.module.fail_json(msg=to_native(e))
try:
temp_public_key = self._create_temp_public_key(keypair.public_key + b'\n')
temp_public_key = self._create_temp_public_key(keypair.public_key + b"\n")
self._safe_secure_move([(temp_public_key, self.public_key_path)])
except (IOError, OSError) as e:
self.module.fail_json(msg=to_native(e))
@@ -457,7 +537,7 @@ class KeypairBackendCryptography(KeypairBackend):
def _private_key_valid_backend(self):
# avoids breaking behavior and prevents
# automatic conversions with OpenSSH upgrades
if self.module.params['private_key_format'] == 'auto':
if self.module.params["private_key_format"] == "auto":
return True
return self.private_key_format == self.original_private_key.format
@@ -465,24 +545,26 @@ class KeypairBackendCryptography(KeypairBackend):
def select_backend(module, backend):
can_use_cryptography = HAS_OPENSSH_SUPPORT
can_use_opensshbin = bool(module.get_bin_path('ssh-keygen'))
can_use_opensshbin = bool(module.get_bin_path("ssh-keygen"))
if backend == 'auto':
if can_use_opensshbin and not module.params['passphrase']:
backend = 'opensshbin'
if backend == "auto":
if can_use_opensshbin and not module.params["passphrase"]:
backend = "opensshbin"
elif can_use_cryptography:
backend = 'cryptography'
backend = "cryptography"
else:
module.fail_json(msg="Cannot find either the OpenSSH binary in the PATH " +
"or cryptography >= 2.6 installed on this system")
module.fail_json(
msg="Cannot find either the OpenSSH binary in the PATH "
+ "or cryptography >= 2.6 installed on this system"
)
if backend == 'opensshbin':
if backend == "opensshbin":
if not can_use_opensshbin:
module.fail_json(msg="Cannot find the OpenSSH binary in the PATH")
return backend, KeypairBackendOpensshBin(module)
elif backend == 'cryptography':
elif backend == "cryptography":
if not can_use_cryptography:
module.fail_json(msg=missing_required_lib("cryptography >= 2.6"))
return backend, KeypairBackendCryptography(module)
else:
raise ValueError('Unsupported value for backend: {0}'.format(backend))
raise ValueError("Unsupported value for backend: {0}".format(backend))