diff --git a/cf_remote/commands.py b/cf_remote/commands.py index 2f4945d..e859b7f 100644 --- a/cf_remote/commands.py +++ b/cf_remote/commands.py @@ -279,7 +279,9 @@ def install( return errors -def _iterate_over_packages(tags=None, version=None, edition=None, download=False, output_dir=None): +def _iterate_over_packages( + tags=None, version=None, edition=None, download=False, output_dir=None +): releases = Releases(edition) print("Available releases: {}".format(releases)) @@ -298,17 +300,25 @@ def _iterate_over_packages(tags=None, version=None, edition=None, download=False else: for artifact in artifacts: if download: - package_path= download_package(artifact.url, checksum=artifact.checksum) - if output_dir : - output_dir = os.path.normpath(output_dir) + package_path = download_package( + artifact.url, checksum=artifact.checksum + ) + if output_dir: + output_dir = os.path.abspath(os.path.expanduser(output_dir)) parent = os.path.dirname(output_dir) if not os.path.exists(parent): - user_error("'{}' doesn't exist. Make sure this path is correct and exists.".format(parent)) + user_error( + "'{}' doesn't exist. Make sure this path is correct and exists.".format( + parent + ) + ) mkdir(output_dir) filename = os.path.basename(artifact.url) output_path = os.path.join(output_dir, filename) + assert artifact.checksum copy_file(package_path, output_path) + print("Copied to '{}' (Checksum OK).".format(output_path)) else: print(artifact.url) return 0 @@ -574,8 +584,12 @@ def destroy(group_name=None): def list_platforms(): print() - print("Platform images are queried based on the platform name, version and architecture.") - print("The form of platform specified is: [-][-]. e.g. debian, debian-12 or debian-12-x64") + print( + "Platform images are queried based on the platform name, version and architecture." + ) + print( + "The form of platform specified is: [-][-]. e.g. debian, debian-12 or debian-12-x64" + ) print("Ubuntu version can be just major (20) or major+minor (20-04)") print("Architecture can either be x64 or arm64") print() @@ -748,7 +762,7 @@ def show(ansible_inventory): del group["meta"] if "region" in meta and "provider" in meta: extra = " in {}, {}".format(meta["region"], meta["provider"]) - if "date" in meta : + if "date" in meta: added = "saved" if "saved" in meta and meta["saved"] else "spawned" extra += ", {} {}".format(added, meta["date"]) print( @@ -899,20 +913,21 @@ def deploy(hubs, masterfiles): os.system("tar -czf %s -C %s masterfiles" % (tarball, above)) return deploy_tarball(hubs, tarball) -def agent(hosts, bootstrap=None) : + +def agent(hosts, bootstrap=None): command = "cf-agent" - if bootstrap : + if bootstrap: command += " --bootstrap {}".format(bootstrap) for host in hosts: data = get_info(host) - if not data["agent_version"] : + if not data["agent_version"]: user_error("CFEngine not installed on {}".format(host)) output = run_command(host, command, sudo=True) - if output : + if output: print(output) return 0 diff --git a/cf_remote/main.py b/cf_remote/main.py index 0515645..07e1879 100644 --- a/cf_remote/main.py +++ b/cf_remote/main.py @@ -138,11 +138,7 @@ def _get_arg_parser(): ) sp.add_argument("tags", metavar="TAG", nargs="*") - sp.add_argument("--output-dir", - "-o", - help="Where to download", - type=str - ) + sp.add_argument("--output-dir", "-o", help="Where to download", type=str) sp = subp.add_parser( "run", help="Run the command given as arguments on the given hosts" @@ -270,7 +266,11 @@ def _get_arg_parser(): ) sp = subp.add_parser("agent", help="Run cf-agent") sp.add_argument( - "--hosts", "-H", help="Which hosts to run cf-agent from", type=str, required=True + "--hosts", + "-H", + help="Which hosts to run cf-agent from", + type=str, + required=True, ) sp.add_argument("--bootstrap", "-B", help="Which hub to bootstrap to", type=str) @@ -292,8 +292,10 @@ def run_command_with_args(command, args): else: trust_keys = None - if not args.bootstrap : - log.warning("You did not specify --bootstrap in the install command, so CFEngine has been installed, but not started.\nTo fix this, run:\ncf-remote agent --hosts HOSTS --bootstrap BOOTSTRAP") + if not args.bootstrap: + log.warning( + "You did not specify --bootstrap in the install command, so CFEngine has been installed, but not started.\nTo fix this, run:\ncf-remote agent --hosts HOSTS --bootstrap BOOTSTRAP" + ) return commands.install( args.hub, @@ -325,7 +327,10 @@ def run_command_with_args(command, args): ) elif command == "download": return commands.download( - tags=args.tags, version=args.version, edition=args.edition, output_dir=args.output_dir + tags=args.tags, + version=args.version, + edition=args.edition, + output_dir=args.output_dir, ) elif command == "run": return commands.run(hosts=args.hosts, raw=args.raw, command=args.remote_command) diff --git a/cf_remote/packages.py b/cf_remote/packages.py index 1cb493d..88d8439 100644 --- a/cf_remote/packages.py +++ b/cf_remote/packages.py @@ -105,7 +105,6 @@ def add_tags_from_filename(self, filename): self.add_tag("opensuse-leap15") self.add_tag("opensuse-leap") - # We don't build for Fedora, so we need to map the distro to the correct packages if "el9" in self.tags: self.add_tag("fedora40") diff --git a/cf_remote/paths.py b/cf_remote/paths.py index e12efdb..c37b5a2 100644 --- a/cf_remote/paths.py +++ b/cf_remote/paths.py @@ -15,7 +15,11 @@ def cfengine_dir(subdir=None): parent = os.path.dirname(override_dir) if not os.path.exists(parent): - user_error("'{}' doesn't exist. Make sure this path is correct and exists.".format(parent)) + user_error( + "'{}' doesn't exist. Make sure this path is correct and exists.".format( + parent + ) + ) return path_append(override_dir, subdir) diff --git a/cf_remote/remote.py b/cf_remote/remote.py index bc33293..e5843c4 100644 --- a/cf_remote/remote.py +++ b/cf_remote/remote.py @@ -93,14 +93,13 @@ def print_info(data): output["CFEngine"] = agent_version policy_server = data.get("policy_server") - if policy_server : + if policy_server: output["Policy server"] = policy_server - else : + else: output["Policy server"] = "None (not bootstrapped yet)" else: output["CFEngine"] = "Not installed" - binaries = [] if "bin" in data: for key in data["bin"]: @@ -330,8 +329,15 @@ def uninstall_cfengine(host, data, *, connection=None, purge=False): host, "rm -rf /var/cfengine /opt/cfengine", connection=connection, sudo=True ) if purge: - run_command(host, "rm -rf /var/log/CFEngine-Install*", connection=connection, sudo=True) - run_command(host, "rm -rf /etc/systemd/system/cf-php-fpm.service", connection=connection, sudo=True) + run_command( + host, "rm -rf /var/log/CFEngine-Install*", connection=connection, sudo=True + ) + run_command( + host, + "rm -rf /etc/systemd/system/cf-php-fpm.service", + connection=connection, + sudo=True, + ) @auto_connect diff --git a/cf_remote/ssh.py b/cf_remote/ssh.py index 977821c..8b9a047 100644 --- a/cf_remote/ssh.py +++ b/cf_remote/ssh.py @@ -49,17 +49,25 @@ def __init__(self, host, user, connect_kwargs=None): # Create an SSH Control Master process (man:ssh_config(5)) so that # commands run on this host can reuse the same SSH connection. self._control_path = os.path.join(paths.cf_remote_dir(), "%C") - control_master_args = ["ssh", "-M", "-N", - "-oControlPath=%s" % self._control_path, - ] + control_master_args = [ + "ssh", + "-M", + "-N", + "-oControlPath=%s" % self._control_path, + ] control_master_args.extend(aramid.DEFAULT_SSH_ARGS) control_master_args.append("%s@%s" % (user, host)) - self._ssh_control_master = subprocess.Popen(control_master_args) # stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + self._ssh_control_master = subprocess.Popen( + control_master_args + ) # stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) def __del__(self): # If we have an SSH Control Master running, signal it to terminate. - if self._ssh_control_master is not None and self._ssh_control_master.poll() is None: + if ( + self._ssh_control_master is not None + and self._ssh_control_master.poll() is None + ): self._ssh_control_master.send_signal(signal.SIGTERM) def run(self, command, hide=False): diff --git a/cf_remote/utils.py b/cf_remote/utils.py index ef763c2..eb94a1c 100644 --- a/cf_remote/utils.py +++ b/cf_remote/utils.py @@ -72,7 +72,7 @@ def read_file(path): def save_file(path, data): - try : + try: if "/" in path: mkdir("/".join(path.split("/")[0:-1])) with open(path, "w") as f: @@ -205,19 +205,19 @@ def print_progress_dot(*args): print(".", end="") sys.stdout.flush() # STDOUT is line-buffered - -def copy_file(input_path, output_path) : + +def copy_file(input_path, output_path): filename = os.path.basename(input_path) output_dir = os.path.dirname(output_path) - tmp_filename = '.{}.tmp'.format(filename) + tmp_filename = ".{}.tmp".format(filename) tmp_output_path = os.path.join(output_dir, tmp_filename) - shutil.copyfile(input_path, tmp_output_path) + shutil.copyfile(input_path, tmp_output_path) os.rename(tmp_output_path, output_path) -def is_different_checksum(checksum, content) : +def is_different_checksum(checksum, content): assert type(content) == bytes digest = hashlib.sha256(content).digest().hex() diff --git a/cf_remote/web.py b/cf_remote/web.py index dc9ef09..3f7ae3c 100644 --- a/cf_remote/web.py +++ b/cf_remote/web.py @@ -5,12 +5,19 @@ import urllib.request import json from collections import OrderedDict -from cf_remote.utils import is_different_checksum, user_error, write_json, mkdir, parse_json +from cf_remote.utils import ( + is_different_checksum, + user_error, + write_json, + mkdir, + parse_json, +) from cf_remote import log from cf_remote.paths import cf_remote_dir, cf_remote_packages_dir SHA256_RE = re.compile(r"^[0-9a-f]{64}$") + def get_json(url): with urllib.request.urlopen(url) as r: assert r.status >= 200 and r.status < 300 @@ -27,9 +34,10 @@ def get_json(url): def download_package(url, path=None, checksum=None): - if checksum and not SHA256_RE.match(checksum): - user_error("Invalid checksum or unsupported checksum algorithm: '%s'" % checksum) + user_error( + "Invalid checksum or unsupported checksum algorithm: '%s'" % checksum + ) if not path: filename = os.path.basename(url) @@ -50,14 +58,22 @@ def download_package(url, path=None, checksum=None): f.seek(0) content = f.read() if checksum and is_different_checksum(checksum, content): - user_error("Downloaded file '{}' does not match expected checksum '{}'. Please delete the file.".format(filename, checksum)) + user_error( + "Downloaded file '{}' does not match expected checksum '{}'. Please delete the file.".format( + filename, checksum + ) + ) else: print("Downloading package: '{}'".format(path)) answer = urllib.request.urlopen(url).read() if checksum and is_different_checksum(checksum, answer): - user_error("Downloaded file '{}' does not match expected checksum '{}'".format(filename, checksum)) + user_error( + "Downloaded file '{}' does not match expected checksum '{}'. Please delete the file.".format( + filename, checksum + ) + ) f.write(answer) f.flush()