Reformat everything.

This commit is contained in:
Felix Fontein
2025-11-01 12:08:41 +01:00
parent 3f2213791a
commit 340ff8586d
1008 changed files with 61301 additions and 58309 deletions

View File

@@ -84,7 +84,6 @@ display = Display()
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
self.set_options(var_options=variables, direct=kwargs)
not_exist = self.get_option("not_exist")

View File

@@ -131,8 +131,7 @@ class BitwardenException(AnsibleError):
class Bitwarden:
def __init__(self, path='bw'):
def __init__(self, path="bw"):
self._cli_path = path
self._session = None
@@ -150,54 +149,56 @@ class Bitwarden:
@property
def unlocked(self):
out, err = self._run(['status'], stdin="")
out, err = self._run(["status"], stdin="")
decoded = AnsibleJSONDecoder().raw_decode(out)[0]
return decoded['status'] == 'unlocked'
return decoded["status"] == "unlocked"
def _run(self, args, stdin=None, expected_rc=0):
if self.session:
args += ['--session', self.session]
args += ["--session", self.session]
p = Popen([self.cli_path] + args, stdout=PIPE, stderr=PIPE, stdin=PIPE)
out, err = p.communicate(to_bytes(stdin))
rc = p.wait()
if rc != expected_rc:
if len(args) > 2 and args[0] == 'get' and args[1] == 'item' and b'Not found.' in err:
return 'null', ''
if len(args) > 2 and args[0] == "get" and args[1] == "item" and b"Not found." in err:
return "null", ""
raise BitwardenException(err)
return to_text(out, errors='surrogate_or_strict'), to_text(err, errors='surrogate_or_strict')
return to_text(out, errors="surrogate_or_strict"), to_text(err, errors="surrogate_or_strict")
def _get_matches(self, search_value, search_field, collection_id=None, organization_id=None):
"""Return matching records whose search_field is equal to key.
"""
"""Return matching records whose search_field is equal to key."""
# Prepare set of params for Bitwarden CLI
if search_field == 'id':
params = ['get', 'item', search_value]
if search_field == "id":
params = ["get", "item", search_value]
else:
params = ['list', 'items']
params = ["list", "items"]
if search_value:
params.extend(['--search', search_value])
params.extend(["--search", search_value])
if collection_id:
params.extend(['--collectionid', collection_id])
params.extend(["--collectionid", collection_id])
if organization_id:
params.extend(['--organizationid', organization_id])
params.extend(["--organizationid", organization_id])
out, err = self._run(params)
# This includes things that matched in different fields.
initial_matches = AnsibleJSONDecoder().raw_decode(out)[0]
if search_field == 'id':
if search_field == "id":
if initial_matches is None:
initial_matches = []
else:
initial_matches = [initial_matches]
# Filter to only include results from the right field, if a search is requested by value or field
return [item for item in initial_matches
if not search_value or not search_field or item.get(search_field) == search_value]
return [
item
for item in initial_matches
if not search_value or not search_field or item.get(search_field) == search_value
]
def get_field(self, field, search_value, search_field="name", collection_id=None, organization_id=None):
"""Return a list of the specified field for records whose search_field match search_value
@@ -211,17 +212,17 @@ class Bitwarden:
field_matches = []
for match in matches:
# if there are no custom fields, then `match` has no key 'fields'
if 'fields' in match:
if "fields" in match:
custom_field_found = False
for custom_field in match['fields']:
if field == custom_field['name']:
field_matches.append(custom_field['value'])
for custom_field in match["fields"]:
if field == custom_field["name"]:
field_matches.append(custom_field["value"])
custom_field_found = True
break
if custom_field_found:
continue
if 'login' in match and field in match['login']:
field_matches.append(match['login'][field])
if "login" in match and field in match["login"]:
field_matches.append(match["login"][field])
continue
if field in match:
field_matches.append(match[field])
@@ -236,10 +237,10 @@ class Bitwarden:
"""Return matching IDs of collections whose name is equal to collection_name."""
# Prepare set of params for Bitwarden CLI
params = ['list', 'collections', '--search', collection_name]
params = ["list", "collections", "--search", collection_name]
if organization_id:
params.extend(['--organizationid', organization_id])
params.extend(["--organizationid", organization_id])
out, err = self._run(params)
@@ -247,21 +248,19 @@ class Bitwarden:
initial_matches = AnsibleJSONDecoder().raw_decode(out)[0] # type: ignore[operator]
# Filter to only return the ID of a collections with exactly matching name
return [item['id'] for item in initial_matches
if str(item.get('name')).lower() == collection_name.lower()]
return [item["id"] for item in initial_matches if str(item.get("name")).lower() == collection_name.lower()]
class LookupModule(LookupBase):
def run(self, terms=None, variables=None, **kwargs):
self.set_options(var_options=variables, direct=kwargs)
field = self.get_option('field')
search_field = self.get_option('search')
collection_id = self.get_option('collection_id')
collection_name = self.get_option('collection_name')
organization_id = self.get_option('organization_id')
result_count = self.get_option('result_count')
_bitwarden.session = self.get_option('bw_session')
field = self.get_option("field")
search_field = self.get_option("search")
collection_id = self.get_option("collection_id")
collection_name = self.get_option("collection_name")
organization_id = self.get_option("organization_id")
result_count = self.get_option("result_count")
_bitwarden.session = self.get_option("bw_session")
if not _bitwarden.unlocked:
raise AnsibleError("Bitwarden Vault locked. Run 'bw unlock'.")
@@ -287,7 +286,8 @@ class LookupModule(LookupBase):
for result in results:
if result_count is not None and len(result) != result_count:
raise BitwardenException(
f"Number of results doesn't match result_count! ({len(result)} != {result_count})")
f"Number of results doesn't match result_count! ({len(result)} != {result_count})"
)
return results

View File

@@ -83,7 +83,7 @@ class BitwardenSecretsManagerException(AnsibleLookupError):
class BitwardenSecretsManager:
def __init__(self, path='bws'):
def __init__(self, path="bws"):
self._cli_path = path
self._max_retries = 3
self._retry_delay = 1
@@ -100,7 +100,7 @@ class BitwardenSecretsManager:
raise BitwardenSecretsManagerException("Max retries exceeded. Unable to retrieve secret.")
if "Too many requests" in err:
delay = self._retry_delay * (2 ** retries)
delay = self._retry_delay * (2**retries)
sleep(delay)
return self._run_with_retry(args, stdin, retries + 1)
else:
@@ -112,36 +112,31 @@ class BitwardenSecretsManager:
p = Popen([self.cli_path] + args, stdout=PIPE, stderr=PIPE, stdin=PIPE)
out, err = p.communicate(stdin)
rc = p.wait()
return to_text(out, errors='surrogate_or_strict'), to_text(err, errors='surrogate_or_strict'), rc
return to_text(out, errors="surrogate_or_strict"), to_text(err, errors="surrogate_or_strict"), rc
def get_bws_version(self):
"""Get the version of the Bitwarden Secrets Manager CLI.
"""
out, err, rc = self._run(['--version'])
"""Get the version of the Bitwarden Secrets Manager CLI."""
out, err, rc = self._run(["--version"])
if rc != 0:
raise BitwardenSecretsManagerException(to_text(err))
# strip the prefix and grab the last segment, the version number
return out.split()[-1]
def get_secret(self, secret_id, bws_access_token):
"""Get and return the secret with the given secret_id.
"""
"""Get and return the secret with the given secret_id."""
# Prepare set of params for Bitwarden Secrets Manager CLI
# Color output was not always disabled correctly with the default 'auto' setting so explicitly disable it.
params = [
'--color', 'no',
'--access-token', bws_access_token
]
params = ["--color", "no", "--access-token", bws_access_token]
# bws version 0.3.0 introduced a breaking change in the command line syntax:
# pre-0.3.0: verb noun
# 0.3.0 and later: noun verb
bws_version = self.get_bws_version()
if LooseVersion(bws_version) < LooseVersion('0.3.0'):
params.extend(['get', 'secret', secret_id])
if LooseVersion(bws_version) < LooseVersion("0.3.0"):
params.extend(["get", "secret", secret_id])
else:
params.extend(['secret', 'get', secret_id])
params.extend(["secret", "get", secret_id])
out, err, rc = self._run_with_retry(params)
if rc != 0:
@@ -153,7 +148,7 @@ class BitwardenSecretsManager:
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
self.set_options(var_options=variables, direct=kwargs)
bws_access_token = self.get_option('bws_access_token')
bws_access_token = self.get_option("bws_access_token")
return [_bitwarden_secrets_manager.get_secret(term, bws_access_token) for term in terms]

View File

@@ -47,6 +47,7 @@ from ansible.parsing.splitter import parse_kv
try:
import chef
HAS_CHEF = True
except ImportError as missing_module:
HAS_CHEF = False
@@ -56,8 +57,8 @@ class LookupModule(LookupBase):
"""
Chef data bag lookup module
"""
def __init__(self, loader=None, templar=None, **kwargs):
def __init__(self, loader=None, templar=None, **kwargs):
super().__init__(loader, templar, **kwargs)
# setup vars for data bag name and data bag item
@@ -77,18 +78,14 @@ class LookupModule(LookupBase):
parsed = str(arg_raw)
setattr(self, arg, parsed)
except ValueError:
raise AnsibleError(
f"can't parse arg {arg}={arg_raw} as string"
)
raise AnsibleError(f"can't parse arg {arg}={arg_raw} as string")
if args:
raise AnsibleError(
f"unrecognized arguments to with_sequence: {list(args.keys())!r}"
)
raise AnsibleError(f"unrecognized arguments to with_sequence: {list(args.keys())!r}")
def run(self, terms, variables=None, **kwargs):
# Ensure pychef has been loaded
if not HAS_CHEF:
raise AnsibleError('PyChef needed for lookup plugin, try `pip install pychef`')
raise AnsibleError("PyChef needed for lookup plugin, try `pip install pychef`")
for term in terms:
self.parse_kv_args(parse_kv(term))
@@ -96,7 +93,7 @@ class LookupModule(LookupBase):
api_object = chef.autoconfigure()
if not isinstance(api_object, chef.api.ChefAPI):
raise AnsibleError('Unable to connect to Chef Server API.')
raise AnsibleError("Unable to connect to Chef Server API.")
data_bag_object = chef.DataBag(self.name)

View File

@@ -66,35 +66,35 @@ from ansible.errors import AnsibleLookupError
from ansible.plugins.lookup import LookupBase
FQCN_RE = re.compile(r'^[A-Za-z0-9_]+\.[A-Za-z0-9_]+$')
FQCN_RE = re.compile(r"^[A-Za-z0-9_]+\.[A-Za-z0-9_]+$")
def load_collection_meta_manifest(manifest_path):
with open(manifest_path, 'rb') as f:
with open(manifest_path, "rb") as f:
meta = json.load(f)
return {
'version': meta['collection_info']['version'],
"version": meta["collection_info"]["version"],
}
def load_collection_meta_galaxy(galaxy_path, no_version='*'):
with open(galaxy_path, 'rb') as f:
def load_collection_meta_galaxy(galaxy_path, no_version="*"):
with open(galaxy_path, "rb") as f:
meta = yaml.safe_load(f)
return {
'version': meta.get('version') or no_version,
"version": meta.get("version") or no_version,
}
def load_collection_meta(collection_pkg, no_version='*'):
def load_collection_meta(collection_pkg, no_version="*"):
path = os.path.dirname(collection_pkg.__file__)
# Try to load MANIFEST.json
manifest_path = os.path.join(path, 'MANIFEST.json')
manifest_path = os.path.join(path, "MANIFEST.json")
if os.path.exists(manifest_path):
return load_collection_meta_manifest(manifest_path)
# Try to load galaxy.yml
galaxy_path = os.path.join(path, 'galaxy.yml')
galaxy_path = os.path.join(path, "galaxy.yml")
if os.path.exists(galaxy_path):
return load_collection_meta_galaxy(galaxy_path, no_version=no_version)
@@ -105,15 +105,15 @@ class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
result = []
self.set_options(var_options=variables, direct=kwargs)
not_found = self.get_option('result_not_found')
no_version = self.get_option('result_no_version')
not_found = self.get_option("result_not_found")
no_version = self.get_option("result_no_version")
for term in terms:
if not FQCN_RE.match(term):
raise AnsibleLookupError(f'"{term}" is not a FQCN')
try:
collection_pkg = import_module(f'ansible_collections.{term}')
collection_pkg = import_module(f"ansible_collections.{term}")
except ImportError:
# Collection not found
result.append(not_found)
@@ -122,8 +122,8 @@ class LookupModule(LookupBase):
try:
data = load_collection_meta(collection_pkg, no_version=no_version)
except Exception as exc:
raise AnsibleLookupError(f'Error while loading metadata for {term}: {exc}')
raise AnsibleLookupError(f"Error while loading metadata for {term}: {exc}")
result.append(data.get('version', no_version))
result.append(data.get("version", no_version))
return result

View File

@@ -125,20 +125,19 @@ except ImportError as e:
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
if not HAS_CONSUL:
raise AnsibleError(
'py-consul is required for consul_kv lookup. see https://github.com/criteo/py-consul?tab=readme-ov-file#installation')
"py-consul is required for consul_kv lookup. see https://github.com/criteo/py-consul?tab=readme-ov-file#installation"
)
# get options
self.set_options(direct=kwargs)
scheme = self.get_option('scheme')
host = self.get_option('host')
port = self.get_option('port')
url = self.get_option('url')
scheme = self.get_option("scheme")
host = self.get_option("host")
port = self.get_option("port")
url = self.get_option("url")
if url is not None:
u = urlparse(url)
if u.scheme:
@@ -147,8 +146,8 @@ class LookupModule(LookupBase):
if u.port is not None:
port = u.port
validate_certs = self.get_option('validate_certs')
client_cert = self.get_option('client_cert')
validate_certs = self.get_option("validate_certs")
client_cert = self.get_option("client_cert")
values = []
try:
@@ -156,40 +155,41 @@ class LookupModule(LookupBase):
params = self.parse_params(term)
consul_api = consul.Consul(host=host, port=port, scheme=scheme, verify=validate_certs, cert=client_cert)
results = consul_api.kv.get(params['key'],
token=params['token'],
index=params['index'],
recurse=params['recurse'],
dc=params['datacenter'])
results = consul_api.kv.get(
params["key"],
token=params["token"],
index=params["index"],
recurse=params["recurse"],
dc=params["datacenter"],
)
if results[1]:
# responds with a single or list of result maps
if isinstance(results[1], list):
for r in results[1]:
values.append(to_text(r['Value']))
values.append(to_text(r["Value"]))
else:
values.append(to_text(results[1]['Value']))
values.append(to_text(results[1]["Value"]))
except Exception as e:
raise AnsibleError(
f"Error locating '{term}' in kv store. Error was {e}")
raise AnsibleError(f"Error locating '{term}' in kv store. Error was {e}")
return values
def parse_params(self, term):
params = term.split(' ')
params = term.split(" ")
paramvals = {
'key': params[0],
'token': self.get_option('token'),
'recurse': self.get_option('recurse'),
'index': self.get_option('index'),
'datacenter': self.get_option('datacenter')
"key": params[0],
"token": self.get_option("token"),
"recurse": self.get_option("recurse"),
"index": self.get_option("index"),
"datacenter": self.get_option("datacenter"),
}
# parameters specified?
try:
for param in params[1:]:
if param and len(param) > 0:
name, value = param.split('=')
name, value = param.split("=")
if name not in paramvals:
raise AnsibleAssertionError(f"{name} not a valid consul lookup parameter")
paramvals[name] = value

View File

@@ -98,6 +98,7 @@ CREDSTASH_INSTALLED = False
try:
import credstash
CREDSTASH_INSTALLED = True
except ImportError:
CREDSTASH_INSTALLED = False
@@ -106,28 +107,38 @@ except ImportError:
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
if not CREDSTASH_INSTALLED:
raise AnsibleError('The credstash lookup plugin requires credstash to be installed.')
raise AnsibleError("The credstash lookup plugin requires credstash to be installed.")
self.set_options(var_options=variables, direct=kwargs)
version = self.get_option('version')
region = self.get_option('region')
table = self.get_option('table')
profile_name = self.get_option('profile_name')
aws_access_key_id = self.get_option('aws_access_key_id')
aws_secret_access_key = self.get_option('aws_secret_access_key')
aws_session_token = self.get_option('aws_session_token')
version = self.get_option("version")
region = self.get_option("region")
table = self.get_option("table")
profile_name = self.get_option("profile_name")
aws_access_key_id = self.get_option("aws_access_key_id")
aws_secret_access_key = self.get_option("aws_secret_access_key")
aws_session_token = self.get_option("aws_session_token")
context = {
k: v for k, v in kwargs.items()
if k not in ('version', 'region', 'table', 'profile_name', 'aws_access_key_id', 'aws_secret_access_key', 'aws_session_token')
k: v
for k, v in kwargs.items()
if k
not in (
"version",
"region",
"table",
"profile_name",
"aws_access_key_id",
"aws_secret_access_key",
"aws_session_token",
)
}
kwargs_pass = {
'profile_name': profile_name,
'aws_access_key_id': aws_access_key_id,
'aws_secret_access_key': aws_secret_access_key,
'aws_session_token': aws_session_token,
"profile_name": profile_name,
"aws_access_key_id": aws_access_key_id,
"aws_secret_access_key": aws_secret_access_key,
"aws_session_token": aws_session_token,
}
ret = []
@@ -135,8 +146,8 @@ class LookupModule(LookupBase):
try:
ret.append(credstash.getSecret(term, version, region, table, context=context, **kwargs_pass))
except credstash.ItemNotFound:
raise AnsibleError(f'Key {term} not found')
raise AnsibleError(f"Key {term} not found")
except Exception as e:
raise AnsibleError(f'Encountered exception while fetching {term}: {e}')
raise AnsibleError(f"Encountered exception while fetching {term}: {e}")
return ret

View File

@@ -89,13 +89,11 @@ from ansible.utils.display import Display
display = Display()
CLIPASSWORDSDK_CMD = os.getenv('AIM_CLIPASSWORDSDK_CMD', '/opt/CARKaim/sdk/clipasswordsdk')
CLIPASSWORDSDK_CMD = os.getenv("AIM_CLIPASSWORDSDK_CMD", "/opt/CARKaim/sdk/clipasswordsdk")
class CyberarkPassword:
def __init__(self, appid=None, query=None, output=None, **kwargs):
self.appid = appid
self.query = query
self.output = output
@@ -104,7 +102,7 @@ class CyberarkPassword:
# FailRequestOnPasswordChange, Queryformat, Reason, etc.
self.extra_parms = []
for key, value in kwargs.items():
self.extra_parms.append('-p')
self.extra_parms.append("-p")
self.extra_parms.append(f"{key}={value}")
if self.appid is None:
@@ -123,17 +121,21 @@ class CyberarkPassword:
self.b_delimiter = b"@#@" # Known delimiter to split output results
def get(self):
result_dict = {}
try:
all_parms = [
CLIPASSWORDSDK_CMD,
'GetPassword',
'-p', f'AppDescs.AppID={self.appid}',
'-p', f'Query={self.query}',
'-o', self.output,
'-d', self.b_delimiter]
"GetPassword",
"-p",
f"AppDescs.AppID={self.appid}",
"-p",
f"Query={self.query}",
"-o",
self.output,
"-d",
self.b_delimiter,
]
all_parms.extend(self.extra_parms)
b_credential = b""
@@ -146,7 +148,7 @@ class CyberarkPassword:
if tmp_error:
raise AnsibleError(f"ERROR => {tmp_error} ")
if b_credential and b_credential.endswith(b'\n'):
if b_credential and b_credential.endswith(b"\n"):
b_credential = b_credential[:-1]
output_names = self.output.split(",")
@@ -164,13 +166,14 @@ class CyberarkPassword:
except subprocess.CalledProcessError as e:
raise AnsibleError(e.output)
except OSError as e:
raise AnsibleError(f"ERROR - AIM not installed or clipasswordsdk not in standard location. ERROR=({e.errno}) => {e.strerror} ")
raise AnsibleError(
f"ERROR - AIM not installed or clipasswordsdk not in standard location. ERROR=({e.errno}) => {e.strerror} "
)
return [result_dict]
class LookupModule(LookupBase):
"""
USAGE:

View File

@@ -125,6 +125,7 @@ from ansible.template import Templar
try:
from ansible.template import trust_as_template as _trust_as_template
HAS_DATATAGGING = True
except ImportError:
HAS_DATATAGGING = False
@@ -145,7 +146,7 @@ class LookupModule(LookupBase):
"""
templar.available_variables = variables or {}
quoted_expression = "{0}{1}{2}".format("{{", expression, "}}")
if hasattr(templar, 'evaluate_expression'):
if hasattr(templar, "evaluate_expression"):
# This is available since the Data Tagging PR has been merged
return templar.evaluate_expression(_make_safe(expression))
return templar.template(quoted_expression)
@@ -169,12 +170,11 @@ class LookupModule(LookupBase):
if expression is not None:
# Evaluate expression in current context
vars = variables.copy()
vars['item'] = current.copy()
vars["item"] = current.copy()
try:
values = self.__evaluate(expression, templar, variables=vars)
except Exception as e:
raise AnsibleLookupError(
f'Caught "{e}" while evaluating {key!r} with item == {current!r}')
raise AnsibleLookupError(f'Caught "{e}" while evaluating {key!r} with item == {current!r}')
if isinstance(values, Mapping):
for idx, val in sorted(values.items()):
@@ -186,7 +186,8 @@ class LookupModule(LookupBase):
self.__process(result, terms, index + 1, current, templar, variables)
else:
raise AnsibleLookupError(
f'Did not obtain dictionary or list while evaluating {key!r} with item == {current!r}, but {type(values)}')
f"Did not obtain dictionary or list while evaluating {key!r} with item == {current!r}, but {type(values)}"
)
def run(self, terms, variables=None, **kwargs):
"""Generate list."""
@@ -202,15 +203,14 @@ class LookupModule(LookupBase):
vars_so_far = set()
for index, term in enumerate(terms):
if not isinstance(term, Mapping):
raise AnsibleLookupError(
f'Parameter {index} must be a dictionary, got {type(term)}')
raise AnsibleLookupError(f"Parameter {index} must be a dictionary, got {type(term)}")
if len(term) != 1:
raise AnsibleLookupError(
f'Parameter {index} must be a one-element dictionary, got {len(term)} elements')
f"Parameter {index} must be a one-element dictionary, got {len(term)} elements"
)
k, v = list(term.items())[0]
if k in vars_so_far:
raise AnsibleLookupError(
f'The variable {k!r} appears more than once')
raise AnsibleLookupError(f"The variable {k!r} appears more than once")
vars_so_far.add(k)
if isinstance(v, str):
data.append((k, v, None))
@@ -218,6 +218,7 @@ class LookupModule(LookupBase):
data.append((k, None, v))
else:
raise AnsibleLookupError(
f'Parameter {k!r} (index {index}) must have a value of type string, dictionary or list, got type {type(v)}')
f"Parameter {k!r} (index {index}) must have a value of type string, dictionary or list, got type {type(v)}"
)
self.__process(result, data, 0, {}, templar, variables)
return result

View File

@@ -252,8 +252,30 @@ try:
import dns.resolver
import dns.reversename
import dns.rdataclass
from dns.rdatatype import (A, AAAA, CAA, CNAME, DNAME, DNSKEY, DS, HINFO, LOC,
MX, NAPTR, NS, NSEC3PARAM, PTR, RP, SOA, SPF, SRV, SSHFP, TLSA, TXT)
from dns.rdatatype import (
A,
AAAA,
CAA,
CNAME,
DNAME,
DNSKEY,
DS,
HINFO,
LOC,
MX,
NAPTR,
NS,
NSEC3PARAM,
PTR,
RP,
SOA,
SPF,
SRV,
SSHFP,
TLSA,
TXT,
)
HAVE_DNS = True
except ImportError:
HAVE_DNS = False
@@ -263,35 +285,35 @@ display = Display()
def make_rdata_dict(rdata):
''' While the 'dig' lookup plugin supports anything which dnspython supports
out of the box, the following supported_types list describes which
DNS query types we can convert to a dict.
"""While the 'dig' lookup plugin supports anything which dnspython supports
out of the box, the following supported_types list describes which
DNS query types we can convert to a dict.
Note: adding support for RRSIG is hard work. :)
'''
Note: adding support for RRSIG is hard work. :)
"""
supported_types = {
A: ['address'],
AAAA: ['address'],
CAA: ['flags', 'tag', 'value'],
CNAME: ['target'],
DNAME: ['target'],
DNSKEY: ['flags', 'algorithm', 'protocol', 'key'],
DS: ['algorithm', 'digest_type', 'key_tag', 'digest'],
HINFO: ['cpu', 'os'],
LOC: ['latitude', 'longitude', 'altitude', 'size', 'horizontal_precision', 'vertical_precision'],
MX: ['preference', 'exchange'],
NAPTR: ['order', 'preference', 'flags', 'service', 'regexp', 'replacement'],
NS: ['target'],
NSEC3PARAM: ['algorithm', 'flags', 'iterations', 'salt'],
PTR: ['target'],
RP: ['mbox', 'txt'],
A: ["address"],
AAAA: ["address"],
CAA: ["flags", "tag", "value"],
CNAME: ["target"],
DNAME: ["target"],
DNSKEY: ["flags", "algorithm", "protocol", "key"],
DS: ["algorithm", "digest_type", "key_tag", "digest"],
HINFO: ["cpu", "os"],
LOC: ["latitude", "longitude", "altitude", "size", "horizontal_precision", "vertical_precision"],
MX: ["preference", "exchange"],
NAPTR: ["order", "preference", "flags", "service", "regexp", "replacement"],
NS: ["target"],
NSEC3PARAM: ["algorithm", "flags", "iterations", "salt"],
PTR: ["target"],
RP: ["mbox", "txt"],
# RRSIG: ['type_covered', 'algorithm', 'labels', 'original_ttl', 'expiration', 'inception', 'key_tag', 'signer', 'signature'],
SOA: ['mname', 'rname', 'serial', 'refresh', 'retry', 'expire', 'minimum'],
SPF: ['strings'],
SRV: ['priority', 'weight', 'port', 'target'],
SSHFP: ['algorithm', 'fp_type', 'fingerprint'],
TLSA: ['usage', 'selector', 'mtype', 'cert'],
TXT: ['strings'],
SOA: ["mname", "rname", "serial", "refresh", "retry", "expire", "minimum"],
SPF: ["strings"],
SRV: ["priority", "weight", "port", "target"],
SSHFP: ["algorithm", "fp_type", "fingerprint"],
TLSA: ["usage", "selector", "mtype", "cert"],
TXT: ["strings"],
}
rd = {}
@@ -304,18 +326,18 @@ def make_rdata_dict(rdata):
if isinstance(val, dns.name.Name):
val = dns.name.Name.to_text(val)
if rdata.rdtype == DS and f == 'digest':
val = dns.rdata._hexify(rdata.digest).replace(' ', '')
if rdata.rdtype == DNSKEY and f == 'algorithm':
if rdata.rdtype == DS and f == "digest":
val = dns.rdata._hexify(rdata.digest).replace(" ", "")
if rdata.rdtype == DNSKEY and f == "algorithm":
val = int(val)
if rdata.rdtype == DNSKEY and f == 'key':
val = dns.rdata._base64ify(rdata.key).replace(' ', '')
if rdata.rdtype == NSEC3PARAM and f == 'salt':
val = dns.rdata._hexify(rdata.salt).replace(' ', '')
if rdata.rdtype == SSHFP and f == 'fingerprint':
val = dns.rdata._hexify(rdata.fingerprint).replace(' ', '')
if rdata.rdtype == TLSA and f == 'cert':
val = dns.rdata._hexify(rdata.cert).replace(' ', '')
if rdata.rdtype == DNSKEY and f == "key":
val = dns.rdata._base64ify(rdata.key).replace(" ", "")
if rdata.rdtype == NSEC3PARAM and f == "salt":
val = dns.rdata._hexify(rdata.salt).replace(" ", "")
if rdata.rdtype == SSHFP and f == "fingerprint":
val = dns.rdata._hexify(rdata.fingerprint).replace(" ", "")
if rdata.rdtype == TLSA and f == "cert":
val = dns.rdata._hexify(rdata.cert).replace(" ", "")
rd[f] = val
@@ -327,11 +349,10 @@ def make_rdata_dict(rdata):
#
# --------------------------------------------------------------
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
'''
"""
terms contains a string with things to `dig' for. We support the
following formats:
example.com # A record
@@ -344,7 +365,7 @@ class LookupModule(LookupBase):
^^^ can be comma-sep list of names/addresses
... flat=0 # returns a dict; default is 1 == string
'''
"""
if HAVE_DNS is False:
raise AnsibleError("The dig lookup requires the python 'dnspython' library and it is not installed")
@@ -357,21 +378,21 @@ class LookupModule(LookupBase):
domains = []
nameservers = []
qtype = self.get_option('qtype')
flat = self.get_option('flat')
fail_on_error = self.get_option('fail_on_error')
real_empty = self.get_option('real_empty')
tcp = self.get_option('tcp')
port = self.get_option('port')
qtype = self.get_option("qtype")
flat = self.get_option("flat")
fail_on_error = self.get_option("fail_on_error")
real_empty = self.get_option("real_empty")
tcp = self.get_option("tcp")
port = self.get_option("port")
try:
rdclass = dns.rdataclass.from_text(self.get_option('class'))
rdclass = dns.rdataclass.from_text(self.get_option("class"))
except Exception as e:
raise AnsibleError(f"dns lookup illegal CLASS: {e}")
myres.retry_servfail = self.get_option('retry_servfail')
myres.retry_servfail = self.get_option("retry_servfail")
for t in terms:
if t.startswith('@'): # e.g. "@10.0.1.2,192.0.2.1" is ok.
nsset = t[1:].split(',')
if t.startswith("@"): # e.g. "@10.0.1.2,192.0.2.1" is ok.
nsset = t[1:].split(",")
for ns in nsset:
# Check if we have a valid IP address. If so, use that, otherwise
# try to resolve name to address using system's resolver. If that
@@ -386,35 +407,35 @@ class LookupModule(LookupBase):
except Exception as e:
raise AnsibleError(f"dns lookup NS: {e}")
continue
if '=' in t:
if "=" in t:
try:
opt, arg = t.split('=', 1)
opt, arg = t.split("=", 1)
except Exception:
pass
if opt == 'qtype':
if opt == "qtype":
qtype = arg.upper()
elif opt == 'flat':
elif opt == "flat":
flat = int(arg)
elif opt == 'class':
elif opt == "class":
try:
rdclass = dns.rdataclass.from_text(arg)
except Exception as e:
raise AnsibleError(f"dns lookup illegal CLASS: {e}")
elif opt == 'retry_servfail':
elif opt == "retry_servfail":
myres.retry_servfail = boolean(arg)
elif opt == 'fail_on_error':
elif opt == "fail_on_error":
fail_on_error = boolean(arg)
elif opt == 'real_empty':
elif opt == "real_empty":
real_empty = boolean(arg)
elif opt == 'tcp':
elif opt == "tcp":
tcp = boolean(arg)
continue
if '/' in t:
if "/" in t:
try:
domain, qtype = t.split('/')
domain, qtype = t.split("/")
domains.append(domain)
except Exception:
domains.append(t)
@@ -428,7 +449,7 @@ class LookupModule(LookupBase):
if len(nameservers) > 0:
myres.nameservers = nameservers
if qtype.upper() == 'PTR':
if qtype.upper() == "PTR":
reversed_domains = []
for domain in domains:
try:
@@ -450,7 +471,7 @@ class LookupModule(LookupBase):
answers = myres.query(domain, qtype, rdclass=rdclass, tcp=tcp)
for rdata in answers:
s = rdata.to_text()
if qtype.upper() == 'TXT':
if qtype.upper() == "TXT":
s = s[1:-1] # Strip outside quotes on TXT rdata
if flat:
@@ -458,10 +479,10 @@ class LookupModule(LookupBase):
else:
try:
rd = make_rdata_dict(rdata)
rd['owner'] = answers.canonical_name.to_text()
rd['type'] = dns.rdatatype.to_text(rdata.rdtype)
rd['ttl'] = answers.rrset.ttl
rd['class'] = dns.rdataclass.to_text(rdata.rdclass)
rd["owner"] = answers.canonical_name.to_text()
rd["type"] = dns.rdatatype.to_text(rdata.rdtype)
rd["ttl"] = answers.rrset.ttl
rd["class"] = dns.rdataclass.to_text(rdata.rdclass)
ret.append(rd)
except Exception as err:
@@ -473,7 +494,7 @@ class LookupModule(LookupBase):
if fail_on_error:
raise AnsibleError(f"Lookup failed: {err}")
if not real_empty:
ret.append('NXDOMAIN')
ret.append("NXDOMAIN")
except (dns.resolver.NoAnswer, dns.resolver.Timeout, dns.resolver.NoNameservers) as err:
if fail_on_error:
raise AnsibleError(f"Lookup failed: {err}")

View File

@@ -57,6 +57,7 @@ HAVE_DNS = False
try:
import dns.resolver
from dns.exception import DNSException
HAVE_DNS = True
except ImportError:
pass
@@ -73,21 +74,20 @@ from ansible.plugins.lookup import LookupBase
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
self.set_options(var_options=variables, direct=kwargs)
if HAVE_DNS is False:
raise AnsibleError("Can't LOOKUP(dnstxt): module dns.resolver is not installed")
real_empty = self.get_option('real_empty')
real_empty = self.get_option("real_empty")
ret = []
for term in terms:
domain = term.split()[0]
string = []
try:
answers = dns.resolver.query(domain, 'TXT')
answers = dns.resolver.query(domain, "TXT")
for rdata in answers:
s = rdata.to_text()
string.append(s[1:-1]) # Strip outside quotes on TXT rdata
@@ -95,18 +95,18 @@ class LookupModule(LookupBase):
except dns.resolver.NXDOMAIN:
if real_empty:
continue
string = 'NXDOMAIN'
string = "NXDOMAIN"
except dns.resolver.Timeout:
if real_empty:
continue
string = ''
string = ""
except dns.resolver.NoAnswer:
if real_empty:
continue
string = ''
string = ""
except DNSException as e:
raise AnsibleError(f"dns.resolver unhandled exception {e}")
ret.append(''.join(string))
ret.append("".join(string))
return ret

View File

@@ -140,7 +140,5 @@ class LookupModule(LookupBase):
display.vvv(f"DevOps Secrets Vault GET /secrets/{path}")
result.append(vault.get_secret_json(path))
except SecretsVaultError as error:
raise AnsibleError(
f"DevOps Secrets Vault lookup failure: {error.message}"
)
raise AnsibleError(f"DevOps Secrets Vault lookup failure: {error.message}")
return result

View File

@@ -102,7 +102,7 @@ class Etcd:
def __init__(self, url, version, validate_certs):
self.url = url
self.version = version
self.baseurl = f'{self.url}/{self.version}/keys'
self.baseurl = f"{self.url}/{self.version}/keys"
self.validate_certs = validate_certs
def _parse_node(self, node):
@@ -113,12 +113,12 @@ class Etcd:
# the function will create a key-value at this level and
# undoing the loop.
path = {}
if node.get('dir', False):
for n in node.get('nodes', []):
path[n['key'].split('/')[-1]] = self._parse_node(n)
if node.get("dir", False):
for n in node.get("nodes", []):
path[n["key"].split("/")[-1]] = self._parse_node(n)
else:
path = node['value']
path = node["value"]
return path
@@ -135,16 +135,16 @@ class Etcd:
try:
# I will not support Version 1 of etcd for folder parsing
item = json.loads(data)
if self.version == 'v1':
if self.version == "v1":
# When ETCD are working with just v1
if 'value' in item:
value = item['value']
if "value" in item:
value = item["value"]
else:
if 'node' in item:
if "node" in item:
# When a usual result from ETCD
value = self._parse_node(item['node'])
value = self._parse_node(item["node"])
if 'errorCode' in item:
if "errorCode" in item:
# Here return an error when an unknown entry responds
value = "ENOENT"
except Exception:
@@ -154,14 +154,12 @@ class Etcd:
class LookupModule(LookupBase):
def run(self, terms, variables, **kwargs):
self.set_options(var_options=variables, direct=kwargs)
validate_certs = self.get_option('validate_certs')
url = self.get_option('url')
version = self.get_option('version')
validate_certs = self.get_option("validate_certs")
url = self.get_option("url")
version = self.get_option("version")
etcd = Etcd(url=url, version=version, validate_certs=validate_certs)

View File

@@ -142,6 +142,7 @@ from ansible.utils.display import Display
try:
import etcd3
HAS_ETCD = True
except ImportError:
HAS_ETCD = False
@@ -149,14 +150,14 @@ except ImportError:
display = Display()
etcd3_cnx_opts = (
'host',
'port',
'ca_cert',
'cert_key',
'cert_cert',
'timeout',
'user',
'password',
"host",
"port",
"ca_cert",
"cert_key",
"cert_cert",
"timeout",
"user",
"password",
# 'grpc_options' Etcd3Client() option currently not supported by lookup module (maybe in future ?)
)
@@ -166,18 +167,16 @@ def etcd3_client(client_params):
etcd = etcd3.client(**client_params)
etcd.status()
except Exception as exp:
raise AnsibleLookupError(f'Cannot connect to etcd cluster: {exp}')
raise AnsibleLookupError(f"Cannot connect to etcd cluster: {exp}")
return etcd
class LookupModule(LookupBase):
def run(self, terms, variables, **kwargs):
self.set_options(var_options=variables, direct=kwargs)
if not HAS_ETCD:
display.error(missing_required_lib('etcd3'))
display.error(missing_required_lib("etcd3"))
return None
# create the etcd3 connection parameters dict to pass to etcd3 class
@@ -187,21 +186,21 @@ class LookupModule(LookupBase):
# must be mangled a bit to fit in this scheme.
# so here we use a regex to extract server and port
match = re.compile(
r'^(https?://)?(?P<host>(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|([-_\d\w\.]+))(:(?P<port>\d{1,5}))?/?$'
).match(self.get_option('endpoints'))
r"^(https?://)?(?P<host>(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|([-_\d\w\.]+))(:(?P<port>\d{1,5}))?/?$"
).match(self.get_option("endpoints"))
if match:
if match.group('host'):
client_params['host'] = match.group('host')
if match.group('port'):
client_params['port'] = match.group('port')
if match.group("host"):
client_params["host"] = match.group("host")
if match.group("port"):
client_params["port"] = match.group("port")
for opt in etcd3_cnx_opts:
if self.get_option(opt):
client_params[opt] = self.get_option(opt)
cnx_log = dict(client_params)
if 'password' in cnx_log:
cnx_log['password'] = '<redacted>'
if "password" in cnx_log:
cnx_log["password"] = "<redacted>"
display.verbose(f"etcd3 connection parameters: {cnx_log}")
# connect to etcd3 server
@@ -210,18 +209,18 @@ class LookupModule(LookupBase):
ret = []
# we can pass many keys to lookup
for term in terms:
if self.get_option('prefix'):
if self.get_option("prefix"):
try:
for val, meta in etcd.get_prefix(term):
if val and meta:
ret.append({'key': to_native(meta.key), 'value': to_native(val)})
ret.append({"key": to_native(meta.key), "value": to_native(val)})
except Exception as exp:
display.warning(f'Caught except during etcd3.get_prefix: {exp}')
display.warning(f"Caught except during etcd3.get_prefix: {exp}")
else:
try:
val, meta = etcd.get(term)
if val and meta:
ret.append({'key': to_native(meta.key), 'value': to_native(val)})
ret.append({"key": to_native(meta.key), "value": to_native(val)})
except Exception as exp:
display.warning(f'Caught except during etcd3.get: {exp}')
display.warning(f"Caught except during etcd3.get: {exp}")
return ret

View File

@@ -133,6 +133,7 @@ import re
HAVE_SELINUX = False
try:
import selinux
HAVE_SELINUX = True
except ImportError:
pass
@@ -157,78 +158,76 @@ def selinux_context(path):
if ret[0] != -1:
# Limit split to 4 because the selevel, the last in the list,
# may contain ':' characters
context = ret[1].split(':', 3)
context = ret[1].split(":", 3)
return context
def file_props(root, path):
''' Returns dictionary with file properties, or return None on failure '''
"""Returns dictionary with file properties, or return None on failure"""
abspath = os.path.join(root, path)
try:
st = os.lstat(abspath)
except OSError as e:
display.warning(f'filetree: Error using stat() on path {abspath} ({e})')
display.warning(f"filetree: Error using stat() on path {abspath} ({e})")
return None
ret = dict(root=root, path=path)
if stat.S_ISLNK(st.st_mode):
ret['state'] = 'link'
ret['src'] = os.readlink(abspath)
ret["state"] = "link"
ret["src"] = os.readlink(abspath)
elif stat.S_ISDIR(st.st_mode):
ret['state'] = 'directory'
ret["state"] = "directory"
elif stat.S_ISREG(st.st_mode):
ret['state'] = 'file'
ret['src'] = abspath
ret["state"] = "file"
ret["src"] = abspath
else:
display.warning(f'filetree: Error file type of {abspath} is not supported')
display.warning(f"filetree: Error file type of {abspath} is not supported")
return None
ret['uid'] = st.st_uid
ret['gid'] = st.st_gid
ret["uid"] = st.st_uid
ret["gid"] = st.st_gid
try:
ret['owner'] = pwd.getpwuid(st.st_uid).pw_name
ret["owner"] = pwd.getpwuid(st.st_uid).pw_name
except KeyError:
ret['owner'] = st.st_uid
ret["owner"] = st.st_uid
try:
ret['group'] = to_text(grp.getgrgid(st.st_gid).gr_name)
ret["group"] = to_text(grp.getgrgid(st.st_gid).gr_name)
except KeyError:
ret['group'] = st.st_gid
ret['mode'] = f'0{stat.S_IMODE(st.st_mode):03o}'
ret['size'] = st.st_size
ret['mtime'] = st.st_mtime
ret['ctime'] = st.st_ctime
ret["group"] = st.st_gid
ret["mode"] = f"0{stat.S_IMODE(st.st_mode):03o}"
ret["size"] = st.st_size
ret["mtime"] = st.st_mtime
ret["ctime"] = st.st_ctime
if HAVE_SELINUX and selinux.is_selinux_enabled() == 1:
context = selinux_context(abspath)
ret['seuser'] = context[0]
ret['serole'] = context[1]
ret['setype'] = context[2]
ret['selevel'] = context[3]
ret["seuser"] = context[0]
ret["serole"] = context[1]
ret["setype"] = context[2]
ret["selevel"] = context[3]
return ret
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
self.set_options(var_options=variables, direct=kwargs)
basedir = self.get_basedir(variables)
# Regular expression for exclude
exclude = self.get_option('exclude')
exclude = self.get_option("exclude")
exclude_pattern = re.compile(exclude) if exclude else None
ret = []
for term in terms:
term_file = os.path.basename(term)
dwimmed_path = self._loader.path_dwim_relative(basedir, 'files', os.path.dirname(term))
dwimmed_path = self._loader.path_dwim_relative(basedir, "files", os.path.dirname(term))
path = os.path.join(dwimmed_path, term_file)
display.debug(f"Walking '{path}'")
for root, dirs, files in os.walk(path, topdown=True):
# Filter files and directories using a regular expression
if exclude_pattern is not None:
dirs[:] = [d for d in dirs if not exclude_pattern.match(d)]
@@ -238,7 +237,7 @@ class LookupModule(LookupBase):
relpath = os.path.relpath(os.path.join(root, entry), path)
# Skip if relpath was already processed (from another root)
if relpath not in [entry['path'] for entry in ret]:
if relpath not in [entry["path"] for entry in ret]:
props = file_props(path, relpath)
if props is not None:
display.debug(f" found '{os.path.join(path, relpath)}'")

View File

@@ -40,7 +40,6 @@ from ansible.utils.listify import listify_lookup_plugin_terms
class LookupModule(LookupBase):
def _check_list_of_one_list(self, term):
# make sure term is not a list of one (list of one..) item
# return the final non list item if so
@@ -53,12 +52,11 @@ class LookupModule(LookupBase):
return term
def _do_flatten(self, terms, variables):
ret = []
for term in terms:
term = self._check_list_of_one_list(term)
if term == 'None' or term == 'null':
if term == "None" or term == "null":
# ignore undefined items
break

View File

@@ -75,18 +75,21 @@ _raw:
try:
import jwt
HAS_JWT = True
except ImportError:
HAS_JWT = False
HAS_PYTHON_JWT = False # vs pyjwt
if HAS_JWT and hasattr(jwt, 'JWT'):
if HAS_JWT and hasattr(jwt, "JWT"):
HAS_PYTHON_JWT = True
from jwt import jwk_from_pem, JWT # type: ignore[attr-defined]
jwt_instance = JWT()
try:
from cryptography.hazmat.primitives import serialization
HAS_CRYPTOGRAPHY = True
except ImportError:
HAS_CRYPTOGRAPHY = False
@@ -105,13 +108,12 @@ display = Display()
class PythonJWT:
@staticmethod
def read_key(path, private_key=None):
try:
if private_key:
return jwk_from_pem(private_key.encode('utf-8'))
with open(path, 'rb') as pem_file:
return jwk_from_pem(private_key.encode("utf-8"))
with open(path, "rb") as pem_file:
return jwk_from_pem(pem_file.read())
except Exception as e:
raise AnsibleError(f"Error while parsing key file: {e}")
@@ -120,12 +122,12 @@ class PythonJWT:
def encode_jwt(app_id, jwk, exp=600):
now = int(time.time())
payload = {
'iat': now,
'exp': now + exp,
'iss': app_id,
"iat": now,
"exp": now + exp,
"iss": app_id,
}
try:
return jwt_instance.encode(payload, jwk, alg='RS256')
return jwt_instance.encode(payload, jwk, alg="RS256")
except Exception as e:
raise AnsibleError(f"Error while encoding jwt: {e}")
@@ -135,9 +137,9 @@ def read_key(path, private_key=None):
return PythonJWT.read_key(path, private_key)
try:
if private_key:
key_bytes = private_key.encode('utf-8')
key_bytes = private_key.encode("utf-8")
else:
with open(path, 'rb') as pem_file:
with open(path, "rb") as pem_file:
key_bytes = pem_file.read()
return serialization.load_pem_private_key(key_bytes, password=None)
except Exception as e:
@@ -149,26 +151,26 @@ def encode_jwt(app_id, private_key_obj, exp=600):
return PythonJWT.encode_jwt(app_id, private_key_obj)
now = int(time.time())
payload = {
'iat': now,
'exp': now + exp,
'iss': app_id,
"iat": now,
"exp": now + exp,
"iss": app_id,
}
try:
return jwt.encode(payload, private_key_obj, algorithm='RS256')
return jwt.encode(payload, private_key_obj, algorithm="RS256")
except Exception as e:
raise AnsibleError(f"Error while encoding jwt: {e}")
def post_request(generated_jwt, installation_id, api_base):
base = api_base.rstrip('/')
base = api_base.rstrip("/")
github_url = f"{base}/app/installations/{installation_id}/access_tokens"
headers = {
"Authorization": f'Bearer {generated_jwt}',
"Authorization": f"Bearer {generated_jwt}",
"Accept": "application/vnd.github.v3+json",
}
try:
response = open_url(github_url, headers=headers, method='POST')
response = open_url(github_url, headers=headers, method="POST")
except HTTPError as e:
try:
error_body = json.loads(e.read().decode())
@@ -182,10 +184,10 @@ def post_request(generated_jwt, installation_id, api_base):
raise AnsibleError(f"Unexpected data returned: {e} -- {error_body}")
response_body = response.read()
try:
json_data = json.loads(response_body.decode('utf-8'))
json_data = json.loads(response_body.decode("utf-8"))
except json.decoder.JSONDecodeError as e:
raise AnsibleError(f"Error while dencoding JSON respone from github: {e}")
return json_data.get('token')
return json_data.get("token")
def get_token(key_path, app_id, installation_id, private_key, github_url, expiry=600):
@@ -197,12 +199,12 @@ def get_token(key_path, app_id, installation_id, private_key, github_url, expiry
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
if not HAS_JWT:
raise AnsibleError('Python jwt library is required. '
'Please install using "pip install pyjwt"')
raise AnsibleError('Python jwt library is required. Please install using "pip install pyjwt"')
if not HAS_PYTHON_JWT and not HAS_CRYPTOGRAPHY:
raise AnsibleError('Python cryptography library is required. '
'Please install using "pip install cryptography"')
raise AnsibleError(
'Python cryptography library is required. Please install using "pip install cryptography"'
)
self.set_options(var_options=variables, direct=kwargs)
@@ -212,12 +214,12 @@ class LookupModule(LookupBase):
raise AnsibleOptionsError("key_path and private_key are mutually exclusive")
t = get_token(
self.get_option('key_path'),
self.get_option('app_id'),
self.get_option('installation_id'),
self.get_option('private_key'),
self.get_option('github_url'),
self.get_option('token_expiry'),
self.get_option("key_path"),
self.get_option("app_id"),
self.get_option("installation_id"),
self.get_option("private_key"),
self.get_option("github_url"),
self.get_option("token_expiry"),
)
return [t]

View File

@@ -79,7 +79,7 @@ class Hiera:
def get(self, hiera_key):
pargs = [self.hiera_bin]
pargs.extend(['-c', self.hiera_cfg])
pargs.extend(["-c", self.hiera_cfg])
pargs.extend(hiera_key)
@@ -92,6 +92,6 @@ class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
self.set_options(var_options=variables, direct=kwargs)
hiera = Hiera(self.get_option('config_file'), self.get_option('executable'))
hiera = Hiera(self.get_option("config_file"), self.get_option("executable"))
ret = [hiera.get(terms)]
return ret

View File

@@ -52,7 +52,6 @@ display = Display()
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
if not HAS_KEYRING:
raise AnsibleError("Can't LOOKUP(keyring): missing required python library 'keyring'")

View File

@@ -51,8 +51,7 @@ class LPassException(AnsibleError):
class LPass:
def __init__(self, path='lpass'):
def __init__(self, path="lpass"):
self._cli_path = path
@property
@@ -70,7 +69,7 @@ class LPass:
rc = p.wait()
if rc != expected_rc:
raise LPassException(err)
return to_text(out, errors='surrogate_or_strict'), to_text(err, errors='surrogate_or_strict')
return to_text(out, errors="surrogate_or_strict"), to_text(err, errors="surrogate_or_strict")
def _build_args(self, command, args=None):
if args is None:
@@ -80,7 +79,7 @@ class LPass:
return args
def get_field(self, key, field):
if field in ['username', 'password', 'url', 'notes', 'id', 'name']:
if field in ["username", "password", "url", "notes", "id", "name"]:
out, err = self._run(self._build_args("show", [f"--{field}", key]))
else:
out, err = self._run(self._build_args("show", [f"--field={field}", key]))
@@ -88,10 +87,9 @@ class LPass:
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
self.set_options(var_options=variables, direct=kwargs)
field = self.get_option('field')
field = self.get_option("field")
lp = LPass()

View File

@@ -70,9 +70,8 @@ except ImportError:
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
'''
"""
terms contain any number of keys to be retrieved.
If terms is None, all keys from the database are returned
with their values, and if term ends in an asterisk, we
@@ -83,13 +82,13 @@ class LookupModule(LookupBase):
vars:
- lmdb_kv_db: "jp.mdb"
'''
"""
if HAVE_LMDB is False:
raise AnsibleError("Can't LOOKUP(lmdb_kv): this module requires lmdb to be installed")
self.set_options(var_options=variables, direct=kwargs)
db = self.get_option('db')
db = self.get_option("db")
try:
env = lmdb.open(str(db), readonly=True)
@@ -107,7 +106,7 @@ class LookupModule(LookupBase):
else:
for term in terms:
with env.begin() as txn:
if term.endswith('*'):
if term.endswith("*"):
cursor = txn.cursor()
prefix = term[:-1] # strip asterisk
cursor.set_range(to_text(term).encode())

View File

@@ -136,9 +136,9 @@ class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
self.set_options(direct=kwargs)
initial_value = self.get_option("initial_value", None)
self._override = self.get_option('override', 'error')
self._pattern_type = self.get_option('pattern_type', 'regex')
self._groups = self.get_option('groups', None)
self._override = self.get_option("override", "error")
self._pattern_type = self.get_option("pattern_type", "regex")
self._groups = self.get_option("groups", None)
ret = []
for term in terms:
@@ -159,7 +159,7 @@ class LookupModule(LookupBase):
return ret
def _is_host_in_allowed_groups(self, host_groups):
if 'all' in self._groups:
if "all" in self._groups:
return True
group_intersection = [host_group_name for host_group_name in host_groups if host_group_name in self._groups]
@@ -191,7 +191,9 @@ class LookupModule(LookupBase):
result = initial_value
for var_name in var_merge_names:
temp_templar = self._templar.copy_with_new_env(available_variables=variables) # tmp. switch renderer to context of current variables
temp_templar = self._templar.copy_with_new_env(
available_variables=variables
) # tmp. switch renderer to context of current variables
var_value = temp_templar.template(variables[var_name]) # Render jinja2 templates
var_type = _verify_and_get_type(var_value)

View File

@@ -299,11 +299,13 @@ class OnePassCLIv1(OnePassCLIBase):
def full_signin(self):
if self.connect_host or self.connect_token:
raise AnsibleLookupError(
"1Password Connect is not available with 1Password CLI version 1. Please use version 2 or later.")
"1Password Connect is not available with 1Password CLI version 1. Please use version 2 or later."
)
if self.service_account_token:
raise AnsibleLookupError(
"1Password CLI version 1 does not support Service Accounts. Please use version 2 or later.")
"1Password CLI version 1 does not support Service Accounts. Please use version 2 or later."
)
required_params = [
"subdomain",
@@ -338,7 +340,7 @@ class OnePassCLIv1(OnePassCLIBase):
return self._run(args)
def signin(self):
self._check_required_params(['master_password'])
self._check_required_params(["master_password"])
args = ["signin", "--raw"]
if self.subdomain:
@@ -351,6 +353,7 @@ class OnePassCLIv2(OnePassCLIBase):
"""
CLIv2 Syntax Reference: https://developer.1password.com/docs/cli/upgrade#step-2-update-your-scripts
"""
supports_version = "2"
def _parse_field(self, data_json, field_name, section_title=None):
@@ -533,9 +536,13 @@ class OnePassCLIv2(OnePassCLIBase):
self._check_required_params(required_params)
args = [
"account", "add", "--raw",
"--address", f"{self.subdomain}.{self.domain}",
"--email", to_bytes(self.username),
"account",
"add",
"--raw",
"--address",
f"{self.subdomain}.{self.domain}",
"--email",
to_bytes(self.username),
"--signin",
]
@@ -574,7 +581,7 @@ class OnePassCLIv2(OnePassCLIBase):
return self._add_parameters_and_run(args, vault=vault, token=token)
def signin(self):
self._check_required_params(['master_password'])
self._check_required_params(["master_password"])
args = ["signin", "--raw"]
if self.subdomain:
@@ -584,8 +591,19 @@ class OnePassCLIv2(OnePassCLIBase):
class OnePass:
def __init__(self, subdomain=None, domain="1password.com", username=None, secret_key=None, master_password=None,
service_account_token=None, account_id=None, connect_host=None, connect_token=None, cli_class=None):
def __init__(
self,
subdomain=None,
domain="1password.com",
username=None,
secret_key=None,
master_password=None,
service_account_token=None,
account_id=None,
connect_host=None,
connect_token=None,
cli_class=None,
):
self.subdomain = subdomain
self.domain = domain
self.username = username
@@ -607,15 +625,33 @@ class OnePass:
def _get_cli_class(self, cli_class=None):
if cli_class is not None:
return cli_class(self.subdomain, self.domain, self.username, self.secret_key, self.master_password, self.service_account_token,
self.account_id, self.connect_host, self.connect_token)
return cli_class(
self.subdomain,
self.domain,
self.username,
self.secret_key,
self.master_password,
self.service_account_token,
self.account_id,
self.connect_host,
self.connect_token,
)
version = OnePassCLIBase.get_current_version()
for cls in OnePassCLIBase.__subclasses__():
if cls.supports_version == version.split(".")[0]:
try:
return cls(self.subdomain, self.domain, self.username, self.secret_key, self.master_password, self.service_account_token,
self.account_id, self.connect_host, self.connect_token)
return cls(
self.subdomain,
self.domain,
self.username,
self.secret_key,
self.master_password,
self.service_account_token,
self.account_id,
self.connect_host,
self.connect_token,
)
except TypeError as e:
raise AnsibleLookupError(e)
@@ -666,7 +702,6 @@ class OnePass:
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
self.set_options(var_options=variables, direct=kwargs)

View File

@@ -59,7 +59,6 @@ from ansible.plugins.lookup import LookupBase
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
self.set_options(var_options=variables, direct=kwargs)

View File

@@ -76,11 +76,7 @@ class LookupModule(LookupBase):
raise AnsibleLookupError(f"No private key found for item {item_id}.")
if ssh_format:
return (
private_key_field.get("ssh_formats", {})
.get("openssh", {})
.get("value", "")
)
return private_key_field.get("ssh_formats", {}).get("openssh", {}).get("value", "")
return private_key_field.get("value", "")
def run(self, terms, variables=None, **kwargs):
@@ -112,7 +108,4 @@ class LookupModule(LookupBase):
)
op.assert_logged_in()
return [
self.get_ssh_key(op.get_raw(term, vault), term, ssh_format=ssh_format)
for term in terms
]
return [self.get_ssh_key(op.get_raw(term, vault), term, ssh_format=ssh_format) for term in terms]

View File

@@ -264,16 +264,16 @@ display = Display()
# http://stackoverflow.com/questions/10103551/passing-data-to-subprocess-check-output
# note: contains special logic for calling 'pass', so not a drop-in replacement for check_output
def check_output2(*popenargs, **kwargs):
if 'stdout' in kwargs:
raise ValueError('stdout argument not allowed, it will be overridden.')
if 'stderr' in kwargs:
raise ValueError('stderr argument not allowed, it will be overridden.')
if 'input' in kwargs:
if 'stdin' in kwargs:
raise ValueError('stdin and input arguments may not both be used.')
b_inputdata = to_bytes(kwargs['input'], errors='surrogate_or_strict')
del kwargs['input']
kwargs['stdin'] = subprocess.PIPE
if "stdout" in kwargs:
raise ValueError("stdout argument not allowed, it will be overridden.")
if "stderr" in kwargs:
raise ValueError("stderr argument not allowed, it will be overridden.")
if "input" in kwargs:
if "stdin" in kwargs:
raise ValueError("stdin and input arguments may not both be used.")
b_inputdata = to_bytes(kwargs["input"], errors="surrogate_or_strict")
del kwargs["input"]
kwargs["stdin"] = subprocess.PIPE
else:
b_inputdata = None
process = subprocess.Popen(*popenargs, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
@@ -284,24 +284,20 @@ def check_output2(*popenargs, **kwargs):
process.wait()
raise
retcode = process.poll()
if retcode == 0 and (b'encryption failed: Unusable public key' in b_out or
b'encryption failed: Unusable public key' in b_err):
if retcode == 0 and (
b"encryption failed: Unusable public key" in b_out or b"encryption failed: Unusable public key" in b_err
):
retcode = 78 # os.EX_CONFIG
if retcode != 0:
cmd = kwargs.get("args")
if cmd is None:
cmd = popenargs[0]
raise subprocess.CalledProcessError(
retcode,
cmd,
to_native(b_out + b_err, errors='surrogate_or_strict')
)
raise subprocess.CalledProcessError(retcode, cmd, to_native(b_out + b_err, errors="surrogate_or_strict"))
return b_out
class LookupModule(LookupBase):
def __init__(self, loader=None, templar=None, **kwargs):
super().__init__(loader, templar, **kwargs)
self.realpass = None
@@ -309,12 +305,11 @@ class LookupModule(LookupBase):
if self.realpass is None:
try:
passoutput = to_text(
check_output2([self.pass_cmd, "--version"], env=self.env),
errors='surrogate_or_strict'
check_output2([self.pass_cmd, "--version"], env=self.env), errors="surrogate_or_strict"
)
self.realpass = 'pass: the standard unix password manager' in passoutput
except (subprocess.CalledProcessError) as e:
raise AnsibleError(f'exit code {e.returncode} while running {e.cmd}. Error output: {e.output}')
self.realpass = "pass: the standard unix password manager" in passoutput
except subprocess.CalledProcessError as e:
raise AnsibleError(f"exit code {e.returncode} while running {e.cmd}. Error output: {e.output}")
return self.realpass
@@ -329,96 +324,96 @@ class LookupModule(LookupBase):
# next parse the optional parameters in keyvalue pairs
try:
for param in params[1:]:
name, value = param.split('=', 1)
name, value = param.split("=", 1)
if name not in self.paramvals:
raise AnsibleAssertionError(f'{name} not in paramvals')
raise AnsibleAssertionError(f"{name} not in paramvals")
self.paramvals[name] = value
except (ValueError, AssertionError) as e:
raise AnsibleError(e)
# check and convert values
try:
for key in ['create', 'returnall', 'overwrite', 'backup', 'nosymbols']:
for key in ["create", "returnall", "overwrite", "backup", "nosymbols"]:
if not isinstance(self.paramvals[key], bool):
self.paramvals[key] = boolean(self.paramvals[key])
except (ValueError, AssertionError) as e:
raise AnsibleError(e)
if self.paramvals['missing'] not in ['error', 'warn', 'create', 'empty']:
if self.paramvals["missing"] not in ["error", "warn", "create", "empty"]:
raise AnsibleError(f"{self.paramvals['missing']} is not a valid option for missing")
if not isinstance(self.paramvals['length'], int):
if self.paramvals['length'].isdigit():
self.paramvals['length'] = int(self.paramvals['length'])
if not isinstance(self.paramvals["length"], int):
if self.paramvals["length"].isdigit():
self.paramvals["length"] = int(self.paramvals["length"])
else:
raise AnsibleError(f"{self.paramvals['length']} is not a correct value for length")
if self.paramvals['create']:
self.paramvals['missing'] = 'create'
if self.paramvals["create"]:
self.paramvals["missing"] = "create"
# Collect pass environment variables from the plugin's parameters.
self.env = os.environ.copy()
self.env['LANGUAGE'] = 'C' # make sure to get errors in English as required by check_output2
self.env["LANGUAGE"] = "C" # make sure to get errors in English as required by check_output2
if self.backend == 'gopass':
self.env['GOPASS_NO_REMINDER'] = "YES"
elif os.path.isdir(self.paramvals['directory']):
if self.backend == "gopass":
self.env["GOPASS_NO_REMINDER"] = "YES"
elif os.path.isdir(self.paramvals["directory"]):
# Set PASSWORD_STORE_DIR
self.env['PASSWORD_STORE_DIR'] = self.paramvals['directory']
self.env["PASSWORD_STORE_DIR"] = self.paramvals["directory"]
elif self.is_real_pass():
raise AnsibleError(f"Passwordstore directory '{self.paramvals['directory']}' does not exist")
# Set PASSWORD_STORE_UMASK if umask is set
if self.paramvals.get('umask') is not None:
if len(self.paramvals['umask']) != 3:
raise AnsibleError('Passwordstore umask must have a length of 3.')
elif int(self.paramvals['umask'][0]) > 3:
raise AnsibleError('Passwordstore umask not allowed (password not user readable).')
if self.paramvals.get("umask") is not None:
if len(self.paramvals["umask"]) != 3:
raise AnsibleError("Passwordstore umask must have a length of 3.")
elif int(self.paramvals["umask"][0]) > 3:
raise AnsibleError("Passwordstore umask not allowed (password not user readable).")
else:
self.env['PASSWORD_STORE_UMASK'] = self.paramvals['umask']
self.env["PASSWORD_STORE_UMASK"] = self.paramvals["umask"]
def check_pass(self):
try:
self.passoutput = to_text(
check_output2([self.pass_cmd, 'show'] +
[self.passname], env=self.env),
errors='surrogate_or_strict'
check_output2([self.pass_cmd, "show"] + [self.passname], env=self.env), errors="surrogate_or_strict"
).splitlines()
self.password = self.passoutput[0]
self.passdict = {}
try:
values = yaml.safe_load('\n'.join(self.passoutput[1:]))
values = yaml.safe_load("\n".join(self.passoutput[1:]))
for key, item in values.items():
self.passdict[key] = item
except (yaml.YAMLError, AttributeError):
for line in self.passoutput[1:]:
if ':' in line:
name, value = line.split(':', 1)
if ":" in line:
name, value = line.split(":", 1)
self.passdict[name.strip()] = value.strip()
if (self.backend == 'gopass' or
os.path.isfile(os.path.join(self.paramvals['directory'], f"{self.passname}.gpg"))
or not self.is_real_pass()):
if (
self.backend == "gopass"
or os.path.isfile(os.path.join(self.paramvals["directory"], f"{self.passname}.gpg"))
or not self.is_real_pass()
):
# When using real pass, only accept password as found if there is a .gpg file for it (might be a tree node otherwise)
return True
except (subprocess.CalledProcessError) as e:
except subprocess.CalledProcessError as e:
# 'not in password store' is the expected error if a password wasn't found
if 'not in the password store' not in e.output:
raise AnsibleError(f'exit code {e.returncode} while running {e.cmd}. Error output: {e.output}')
if "not in the password store" not in e.output:
raise AnsibleError(f"exit code {e.returncode} while running {e.cmd}. Error output: {e.output}")
if self.paramvals['missing'] == 'error':
raise AnsibleError(f'passwordstore: passname {self.passname} not found and missing=error is set')
elif self.paramvals['missing'] == 'warn':
display.warning(f'passwordstore: passname {self.passname} not found')
if self.paramvals["missing"] == "error":
raise AnsibleError(f"passwordstore: passname {self.passname} not found and missing=error is set")
elif self.paramvals["missing"] == "warn":
display.warning(f"passwordstore: passname {self.passname} not found")
return False
def get_newpass(self):
if self.paramvals['nosymbols']:
if self.paramvals["nosymbols"]:
chars = C.DEFAULT_PASSWORD_CHARS[:62]
else:
chars = C.DEFAULT_PASSWORD_CHARS
if self.paramvals['userpass']:
newpass = self.paramvals['userpass']
if self.paramvals["userpass"]:
newpass = self.paramvals["userpass"]
else:
newpass = random_password(length=self.paramvals['length'], chars=chars)
newpass = random_password(length=self.paramvals["length"], chars=chars)
return newpass
def update_password(self):
@@ -429,7 +424,6 @@ class LookupModule(LookupBase):
subkey = self.paramvals["subkey"]
if subkey != "password":
msg_lines = []
subkey_exists = False
subkey_line = f"{subkey}: {newpass}"
@@ -447,27 +441,25 @@ class LookupModule(LookupBase):
msg_lines.insert(2, subkey_line)
if self.paramvals["timestamp"] and self.paramvals["backup"] and oldpass and oldpass != newpass:
msg_lines.append(
f"lookup_pass: old subkey '{subkey}' password was {oldpass} (Updated on {datetime})\n"
)
msg_lines.append(f"lookup_pass: old subkey '{subkey}' password was {oldpass} (Updated on {datetime})\n")
msg = os.linesep.join(msg_lines)
else:
msg = newpass
if self.paramvals['preserve'] or self.paramvals['timestamp']:
msg += '\n'
if self.paramvals['preserve'] and self.passoutput[1:]:
msg += '\n'.join(self.passoutput[1:])
msg += '\n'
if self.paramvals['timestamp'] and self.paramvals['backup']:
if self.paramvals["preserve"] or self.paramvals["timestamp"]:
msg += "\n"
if self.paramvals["preserve"] and self.passoutput[1:]:
msg += "\n".join(self.passoutput[1:])
msg += "\n"
if self.paramvals["timestamp"] and self.paramvals["backup"]:
msg += f"lookup_pass: old password was {self.password} (Updated on {datetime})\n"
try:
check_output2([self.pass_cmd, 'insert', '-f', '-m', self.passname], input=msg, env=self.env)
except (subprocess.CalledProcessError) as e:
raise AnsibleError(f'exit code {e.returncode} while running {e.cmd}. Error output: {e.output}')
check_output2([self.pass_cmd, "insert", "-f", "-m", self.passname], input=msg, env=self.env)
except subprocess.CalledProcessError as e:
raise AnsibleError(f"exit code {e.returncode} while running {e.cmd}. Error output: {e.output}")
return newpass
def generate_password(self):
@@ -482,24 +474,24 @@ class LookupModule(LookupBase):
else:
msg = newpass
if self.paramvals['timestamp']:
if self.paramvals["timestamp"]:
msg += f"\nlookup_pass: First generated by ansible on {datetime}\n"
try:
check_output2([self.pass_cmd, 'insert', '-f', '-m', self.passname], input=msg, env=self.env)
except (subprocess.CalledProcessError) as e:
raise AnsibleError(f'exit code {e.returncode} while running {e.cmd}. Error output: {e.output}')
check_output2([self.pass_cmd, "insert", "-f", "-m", self.passname], input=msg, env=self.env)
except subprocess.CalledProcessError as e:
raise AnsibleError(f"exit code {e.returncode} while running {e.cmd}. Error output: {e.output}")
return newpass
def get_passresult(self):
if self.paramvals['returnall']:
if self.paramvals["returnall"]:
return os.linesep.join(self.passoutput)
if self.paramvals['subkey'] == 'password':
if self.paramvals["subkey"] == "password":
return self.password
else:
if self.paramvals['subkey'] in self.passdict:
return self.passdict[self.paramvals['subkey']]
if self.paramvals["subkey"] in self.passdict:
return self.passdict[self.paramvals["subkey"]]
else:
if self.paramvals["missing_subkey"] == "error":
raise AnsibleError(
@@ -515,10 +507,10 @@ class LookupModule(LookupBase):
@contextmanager
def opt_lock(self, type):
if self.get_option('lock') == type:
tmpdir = os.environ.get('TMPDIR', '/tmp')
user = os.environ.get('USER')
lockfile = os.path.join(tmpdir, f'.{user}.passwordstore.lock')
if self.get_option("lock") == type:
tmpdir = os.environ.get("TMPDIR", "/tmp")
user = os.environ.get("USER")
lockfile = os.path.join(tmpdir, f".{user}.passwordstore.lock")
with FileLock().lock_file(lockfile, tmpdir, self.lock_timeout):
self.locked = type
yield
@@ -527,40 +519,40 @@ class LookupModule(LookupBase):
yield
def setup(self, variables):
self.backend = self.get_option('backend')
self.backend = self.get_option("backend")
self.pass_cmd = self.backend # pass and gopass are commands as well
self.locked = None
timeout = self.get_option('locktimeout')
if not re.match('^[0-9]+[smh]$', timeout):
timeout = self.get_option("locktimeout")
if not re.match("^[0-9]+[smh]$", timeout):
raise AnsibleError(f"{timeout} is not a correct value for locktimeout")
unit_to_seconds = {"s": 1, "m": 60, "h": 3600}
self.lock_timeout = int(timeout[:-1]) * unit_to_seconds[timeout[-1]]
directory = self.get_option('directory')
directory = self.get_option("directory")
if directory is None:
if self.backend == 'gopass':
if self.backend == "gopass":
try:
with open(os.path.expanduser('~/.config/gopass/config.yml')) as f:
directory = yaml.safe_load(f)['path']
with open(os.path.expanduser("~/.config/gopass/config.yml")) as f:
directory = yaml.safe_load(f)["path"]
except (FileNotFoundError, KeyError, yaml.YAMLError):
directory = os.path.expanduser('~/.local/share/gopass/stores/root')
directory = os.path.expanduser("~/.local/share/gopass/stores/root")
else:
directory = os.path.expanduser('~/.password-store')
directory = os.path.expanduser("~/.password-store")
self.paramvals = {
'subkey': self.get_option('subkey'),
'directory': directory,
'create': self.get_option('create'),
'returnall': self.get_option('returnall'),
'overwrite': self.get_option('overwrite'),
'nosymbols': self.get_option('nosymbols'),
'userpass': self.get_option('userpass') or '',
'length': self.get_option('length'),
'backup': self.get_option('backup'),
'missing': self.get_option('missing'),
'umask': self.get_option('umask'),
'timestamp': self.get_option('timestamp'),
'preserve': self.get_option('preserve'),
"subkey": self.get_option("subkey"),
"directory": directory,
"create": self.get_option("create"),
"returnall": self.get_option("returnall"),
"overwrite": self.get_option("overwrite"),
"nosymbols": self.get_option("nosymbols"),
"userpass": self.get_option("userpass") or "",
"length": self.get_option("length"),
"backup": self.get_option("backup"),
"missing": self.get_option("missing"),
"umask": self.get_option("umask"),
"timestamp": self.get_option("timestamp"),
"preserve": self.get_option("preserve"),
"missing_subkey": self.get_option("missing_subkey"),
}
@@ -570,25 +562,27 @@ class LookupModule(LookupBase):
result = []
for term in terms:
self.parse_params(term) # parse the input into paramvals
with self.opt_lock('readwrite'):
if self.check_pass(): # password file exists
if self.paramvals['overwrite']: # if "overwrite", always update password
with self.opt_lock('write'):
self.parse_params(term) # parse the input into paramvals
with self.opt_lock("readwrite"):
if self.check_pass(): # password file exists
if self.paramvals["overwrite"]: # if "overwrite", always update password
with self.opt_lock("write"):
result.append(self.update_password())
elif (
self.paramvals["subkey"] != "password"
and not self.passdict.get(self.paramvals["subkey"])
and self.paramvals["missing"] == "create"
): # target is a subkey, this subkey is not in passdict BUT missing == create
with self.opt_lock('write'):
with self.opt_lock("write"):
result.append(self.update_password())
else:
result.append(self.get_passresult())
else: # password does not exist
if self.paramvals['missing'] == 'create':
with self.opt_lock('write'):
if self.locked == 'write' and self.check_pass(): # lookup password again if under write lock
if self.paramvals["missing"] == "create":
with self.opt_lock("write"):
if (
self.locked == "write" and self.check_pass()
): # lookup password again if under write lock
result.append(self.get_passresult())
else:
result.append(self.generate_password())

View File

@@ -78,18 +78,15 @@ from ansible.plugins.lookup import LookupBase
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
if not HAS_PETNAME:
raise AnsibleError('Python petname library is required. '
'Please install using "pip install petname"')
raise AnsibleError('Python petname library is required. Please install using "pip install petname"')
self.set_options(var_options=variables, direct=kwargs)
words = self.get_option('words')
length = self.get_option('length')
prefix = self.get_option('prefix')
separator = self.get_option('separator')
words = self.get_option("words")
length = self.get_option("length")
prefix = self.get_option("prefix")
separator = self.get_option("separator")
values = petname.Generate(words=words, separator=separator, letters=length)
if prefix:

View File

@@ -179,18 +179,12 @@ class LookupModule(LookupBase):
@staticmethod
def get_random(random_generator, chars, length):
if not chars:
raise AnsibleLookupError(
"Available characters cannot be None, please change constraints"
)
raise AnsibleLookupError("Available characters cannot be None, please change constraints")
return "".join(random_generator.choice(chars) for dummy in range(length))
@staticmethod
def b64encode(string_value, encoding="utf-8"):
return to_text(
base64.b64encode(
to_bytes(string_value, encoding=encoding, errors="surrogate_or_strict")
)
)
return to_text(base64.b64encode(to_bytes(string_value, encoding=encoding, errors="surrogate_or_strict")))
def run(self, terms, variables=None, **kwargs):
number_chars = string.digits

View File

@@ -92,12 +92,8 @@ class LookupModule(LookupBase):
"""The random_words Ansible lookup class."""
def run(self, terms, variables=None, **kwargs):
if not HAS_XKCDPASS:
raise AnsibleLookupError(
"Python xkcdpass library is required. "
'Please install using "pip install xkcdpass"'
)
raise AnsibleLookupError('Python xkcdpass library is required. Please install using "pip install xkcdpass"')
self.set_options(var_options=variables, direct=kwargs)
method = self.get_option("case")
@@ -107,12 +103,8 @@ class LookupModule(LookupBase):
numwords = self.get_option("numwords")
words = xp.locate_wordfile()
wordlist = xp.generate_wordlist(
max_length=max_length, min_length=min_length, wordfile=words
)
wordlist = xp.generate_wordlist(max_length=max_length, min_length=min_length, wordfile=words)
values = xp.generate_xkcdpassword(
wordlist, case=method, delimiter=delimiter, numwords=numwords
)
values = xp.generate_xkcdpassword(wordlist, case=method, delimiter=delimiter, numwords=numwords)
return [values]

View File

@@ -76,6 +76,7 @@ _raw:
HAVE_REDIS = False
try:
import redis
HAVE_REDIS = True
except ImportError:
pass
@@ -86,9 +87,7 @@ from ansible.plugins.lookup import LookupBase
class LookupModule(LookupBase):
def run(self, terms, variables, **kwargs):
if not HAVE_REDIS:
raise AnsibleError("Can't LOOKUP(redis_kv): module redis is not installed")
@@ -96,9 +95,9 @@ class LookupModule(LookupBase):
self.set_options(direct=kwargs)
# setup connection
host = self.get_option('host')
port = self.get_option('port')
socket = self.get_option('socket')
host = self.get_option("host")
port = self.get_option("port")
socket = self.get_option("socket")
if socket is None:
conn = redis.Redis(host=host, port=port)
else:
@@ -113,5 +112,5 @@ class LookupModule(LookupBase):
ret.append(to_text(res))
except Exception as e:
# connection failed or key not found
raise AnsibleError(f'Encountered exception while fetching {term}: {e}')
raise AnsibleError(f"Encountered exception while fetching {term}: {e}")
return ret

View File

@@ -78,19 +78,18 @@ display = Display()
class LookupModule(LookupBase):
@staticmethod
def Client(server_parameters):
return SecretServer(**server_parameters)
def run(self, terms, variables, **kwargs):
if ANOTHER_LIBRARY_IMPORT_ERROR:
raise AnsibleError('revbits_ansible must be installed to use this plugin') from ANOTHER_LIBRARY_IMPORT_ERROR
raise AnsibleError("revbits_ansible must be installed to use this plugin") from ANOTHER_LIBRARY_IMPORT_ERROR
self.set_options(var_options=variables, direct=kwargs)
secret_server = LookupModule.Client(
{
"base_url": self.get_option('base_url'),
"api_key": self.get_option('api_key'),
"base_url": self.get_option("base_url"),
"api_key": self.get_option("api_key"),
}
)
result = []

View File

@@ -46,7 +46,6 @@ from ansible.module_utils.common.text.converters import to_bytes, to_text
class LookupModule(LookupBase):
def read_shelve(self, shelve_filename, key):
"""
Read the value of "key" from a shelve file
@@ -68,19 +67,19 @@ class LookupModule(LookupBase):
try:
for param in params:
name, value = param.split('=')
name, value = param.split("=")
if name not in paramvals:
raise AnsibleAssertionError(f'{name} not in paramvals')
raise AnsibleAssertionError(f"{name} not in paramvals")
paramvals[name] = value
except (ValueError, AssertionError) as e:
# In case "file" or "key" are not present
raise AnsibleError(e)
key = paramvals['key']
key = paramvals["key"]
# Search also in the role/files directory and in the playbook directory
shelvefile = self.find_file_in_search_path(variables, 'files', paramvals['file'])
shelvefile = self.find_file_in_search_path(variables, "files", paramvals["file"])
if shelvefile:
res = self.read_shelve(shelvefile, key)

View File

@@ -260,14 +260,26 @@ from ansible.plugins.lookup import LookupBase
from ansible.utils.display import Display
try:
from delinea.secrets.server import SecretServer, SecretServerError, PasswordGrantAuthorizer, DomainPasswordGrantAuthorizer, AccessTokenAuthorizer
from delinea.secrets.server import (
SecretServer,
SecretServerError,
PasswordGrantAuthorizer,
DomainPasswordGrantAuthorizer,
AccessTokenAuthorizer,
)
HAS_TSS_SDK = True
HAS_DELINEA_SS_SDK = True
HAS_TSS_AUTHORIZER = True
except ImportError:
try:
from thycotic.secrets.server import SecretServer, SecretServerError, PasswordGrantAuthorizer, DomainPasswordGrantAuthorizer, AccessTokenAuthorizer
from thycotic.secrets.server import (
SecretServer,
SecretServerError,
PasswordGrantAuthorizer,
DomainPasswordGrantAuthorizer,
AccessTokenAuthorizer,
)
HAS_TSS_SDK = True
HAS_DELINEA_SS_SDK = False
@@ -312,11 +324,11 @@ class TSSClient(metaclass=abc.ABCMeta): # noqa: B024
obj = self._client.get_secret_by_path(secret_path, fetch_file_attachments)
else:
obj = self._client.get_secret(secret_id, fetch_file_attachments)
for i in obj['items']:
for i in obj["items"]:
if file_download_path and os.path.isdir(file_download_path):
if i['isFile']:
if i["isFile"]:
try:
file_content = i['itemValue'].content
file_content = i["itemValue"].content
with open(os.path.join(file_download_path, f"{obj['id']}_{i['slug']}"), "wb") as f:
f.write(file_content)
except ValueError:
@@ -324,7 +336,7 @@ class TSSClient(metaclass=abc.ABCMeta): # noqa: B024
except AttributeError:
display.warning(f"Could not read file content for {i['slug']}")
finally:
i['itemValue'] = "*** Not Valid For Display ***"
i["itemValue"] = "*** Not Valid For Display ***"
else:
raise AnsibleOptionsError("File download path does not exist")
return obj
@@ -377,9 +389,7 @@ class TSSClientV1(TSSClient):
super().__init__()
authorizer = self._get_authorizer(**server_parameters)
self._client = SecretServer(
server_parameters["base_url"], authorizer, server_parameters["api_path_uri"]
)
self._client = SecretServer(server_parameters["base_url"], authorizer, server_parameters["api_path_uri"])
@staticmethod
def _get_authorizer(**server_parameters):