def signal_wrapper(*args, **kwargs):
    """Wrapper to output any SignalExceptions to STDERR."""
    try:
        signal(*args, **kwargs)
    except SignalException as e:
        fail(e.error)
Example #2
0
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)
Example #3
0
    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