def signal_wrapper(*args, **kwargs): """Wrapper to output any SignalExceptions to STDERR.""" try: signal(*args, **kwargs) except SignalException as e: fail(e.error)
def main(): import argparse parser = argparse.ArgumentParser( description="Send signal operation and optionally post files to MAAS" ) parser.add_argument( "--config", metavar="file", help="Specify config file", default=None ) parser.add_argument( "--ckey", metavar="key", help="The consumer key to auth with", default=None, ) parser.add_argument( "--tkey", metavar="key", help="The token key to auth with", default=None, ) parser.add_argument( "--csec", metavar="secret", help="The consumer secret (likely '')", default="", ) parser.add_argument( "--tsec", metavar="secret", help="The token secret to auth with", default=None, ) parser.add_argument( "--apiver", metavar="version", help='The apiver to use ("" can be used)', default=MD_VERSION, ) parser.add_argument( "--url", metavar="url", help="The data source to query", default=None ) parser.add_argument( "--script-name", metavar="script_name", type=str, dest="script_name", help="The name of the Script this signal is about.", ) parser.add_argument( "--script-result-id", metavar="script_result_id", type=int, dest="script_result_id", help="The ScriptResult database id this signal is about.", ) parser.add_argument( "--file", dest="files", help="File to post", action="append", default=[], ) parser.add_argument( "--runtime", metavar="runtime", type=float, dest="runtime", help="How long the script took to run.", ) parser.add_argument( "--exit-status", metavar="exit_status", type=int, dest="exit_status", help="The exit return code of the script this signal is about.", ) parser.add_argument( "--script-version-id", metavar="script_version_id", type=int, dest="script_version_id", help="The Script VersionTextFile database id this signal is about.", ) parser.add_argument( "--power-type", dest="power_type", help="Power type.", choices=POWER_TYPES, default=None, ) parser.add_argument( "--power-parameters", dest="power_params", help="Power parameters.", default=None, ) parser.add_argument("status", help="Status", choices=VALID_STATUS) parser.add_argument( "error", help="Optional error message", nargs="?", default=None ) args = parser.parse_args() creds = { "consumer_key": args.ckey, "token_key": args.tkey, "token_secret": args.tsec, "consumer_secret": args.csec, "metadata_url": args.url, } if args.config: read_config(args.config, creds) url = creds.get("metadata_url") if url is None: fail("URL must be provided either in --url or in config\n") url = "%s/%s/" % (url, args.apiver) files = {} for fpath in args.files: files[os.path.basename(fpath)] = open(fpath, "rb") try: signal( url, creds, args.status, args.error, args.script_name, args.script_result_id, files, args.runtime, args.exit_status, args.script_version_id, args.power_type, args.power_params, ) except SignalException as e: fail(e.error)
def __enter__(self): """Apply the user network configuration.""" if not self.apply_configured_networking: return self output_and_send_scripts( "Applying custom network configuration for {msg_name}", self.scripts, self.send_result, status="APPLYING_NETCONF", ) if not os.path.exists(self.netplan_yaml): # This should never happen, if it does it means the Metadata # server is sending us incomplete data. output_and_send_scripts( "Unable to apply custom network configuration for {msg_name}." "\n\nnetplan.yaml is missing from tar.", self.scripts, self.send_result, error_is_stderr=True, exit_status=1, status="APPLYING_NETCONF", ) raise FileNotFoundError(self.netplan_yaml) # Backup existing netplan config os.makedirs(self.backup_dir, exist_ok=True) for f in os.listdir(NETPLAN_DIR): shutil.move(os.path.join(NETPLAN_DIR, f), self.backup_dir) # Place the customized netplan config in shutil.copy2(self.netplan_yaml, NETPLAN_DIR) self._bring_down_networking() # Apply the configuration. if not run_and_check( ["netplan", "apply", "--debug"], self.scripts, "APPLYING_NETCONF", self.send_result, True, lambda: self._apply_ephemeral_netplan(), ): raise OSError("netplan failed to apply!") # The new network configuration may change what devices are available. # Clear the cache and reload. get_interfaces(clear_cache=True) try: # Confirm we can still communicate with MAAS. if self.send_result: signal( self.url, self.creds, "APPLYING_NETCONF", "User netplan config applied", ) except SignalException: self._apply_ephemeral_netplan() output_and_send_scripts( "Unable to communicate to the MAAS metadata service after " "applying custom network configuration.", self.scripts, self.send_result, error_is_stderr=True, exit_status=1, status="APPLYING_NETCONF", ) raise else: # Network configuration successfully applied. Clear the logs so # only script output is reported _clean_logs(self.scripts) return self