diff --git a/src/composer/cli/__init__.py b/src/composer/cli/__init__.py index 123962b7..fc07121b 100644 --- a/src/composer/cli/__init__.py +++ b/src/composer/cli/__init__.py @@ -26,8 +26,11 @@ from composer.cli.projects import projects_cmd from composer.cli.compose import compose_cmd, compose_cmd_v1 from composer.cli.sources import sources_cmd from composer.cli.status import status_cmd -from composer.cli.upload import upload_cmd -from composer.cli.providers import providers_cmd + + +def upload_cmd_unavailable(opts): + print("This command is not supported. You can upload images as part of the compose command") + return 1 command_map = { "0": { @@ -45,12 +48,14 @@ command_map = { "compose": compose_cmd_v1, "sources": sources_cmd, "status": status_cmd, - "upload": upload_cmd, - "providers": providers_cmd + "upload": upload_cmd_unavailable, + "providers": upload_cmd_unavailable } } + + def main(opts): """ Main program execution diff --git a/src/composer/cli/help.py b/src/composer/cli/help.py index e055118e..10f93402 100644 --- a/src/composer/cli/help.py +++ b/src/composer/cli/help.py @@ -139,45 +139,9 @@ status show Show API server status. """ upload_help = """ -NOTE: upload commands are only available when using an API v1 backend. - -upload info - Details about an upload - -upload start [ |] - Upload a build image to the selected provider. - -upload log - Show the upload log - -upload cancel - Cancel an upload with that is queued or in progress - -upload delete - Delete the upload and remove it from the build - -upload reset - Reset the upload so that it can be tried again -""" - -providers_help = """ -NOTE: providers commands are only available when using an API v1 backend. - -providers list - List the available providers, or list the available profiles - -providers show - show the details of a specific provider's profile - -providers push - Add a new profile, or overwrite an existing one - -providers save - Save the profile's details to a TOML file named .toml - -providers delete - Delete a profile from a provider +NOTE: uploading is only available as part of the compose command +using the osbuild-composer API server. """ epilog = compose_help + blueprints_help + modules_help + projects_help \ - + sources_help + status_help + upload_help + providers_help + + sources_help + status_help + upload_help diff --git a/src/composer/cli/providers.py b/src/composer/cli/providers.py deleted file mode 100644 index 13174985..00000000 --- a/src/composer/cli/providers.py +++ /dev/null @@ -1,322 +0,0 @@ -# -# Copyright (C) 2019 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -import logging -log = logging.getLogger("composer-cli") - -import json -import pytoml as toml -import os - -from composer import http_client as client -from composer.cli.help import providers_help -from composer.cli.utilities import handle_api_result, toml_filename - -def providers_cmd(opts): - """Process providers commands - - :param opts: Cmdline arguments - :type opts: argparse.Namespace - :returns: Value to return from sys.exit() - :rtype: int - - This dispatches the providers commands to a function - """ - cmd_map = { - "list": providers_list, - "info": providers_info, - "show": providers_show, - "push": providers_push, - "save": providers_save, - "delete": providers_delete, - "template": providers_template - } - if opts.args[1] == "help" or opts.args[1] == "--help": - print(providers_help) - return 0 - elif opts.args[1] not in cmd_map: - log.error("Unknown providers command: %s", opts.args[1]) - return 1 - - return cmd_map[opts.args[1]](opts.socket, opts.api_version, opts.args[2:], opts.json, opts.testmode) - -def providers_list(socket_path, api_version, args, show_json=False, testmode=0): - """Return the list of providers - - :param socket_path: Path to the Unix socket to use for API communication - :type socket_path: str - :param api_version: Version of the API to talk to. eg. "0" - :type api_version: str - :param args: List of remaining arguments from the cmdline - :type args: list of str - :param show_json: Set to True to show the JSON output instead of the human readable output - :type show_json: bool - :param testmode: unused in this function - :type testmode: int - - providers list - """ - api_route = client.api_url(api_version, "/upload/providers") - r = client.get_url_json(socket_path, api_route) - results = r["providers"] - if not results: - return 0 - - if show_json: - print(json.dumps(results, indent=4)) - else: - if len(args) == 1: - if args[0] not in results: - log.error("%s is not a valid provider", args[0]) - return 1 - print("\n".join(sorted(results[args[0]]["profiles"].keys()))) - else: - print("\n".join(sorted(results.keys()))) - - return 0 - -def providers_info(socket_path, api_version, args, show_json=False, testmode=0): - """Show information about each provider - - :param socket_path: Path to the Unix socket to use for API communication - :type socket_path: str - :param api_version: Version of the API to talk to. eg. "0" - :type api_version: str - :param args: List of remaining arguments from the cmdline - :type args: list of str - :param show_json: Set to True to show the JSON output instead of the human readable output - :type show_json: bool - :param testmode: unused in this function - :type testmode: int - - providers info - """ - if len(args) == 0: - log.error("info is missing the provider name") - return 1 - - api_route = client.api_url(api_version, "/upload/providers") - r = client.get_url_json(socket_path, api_route) - results = r["providers"] - if not results: - return 0 - - if show_json: - print(json.dumps(results, indent=4)) - else: - if args[0] not in results: - log.error("%s is not a valid provider", args[0]) - return 1 - p = results[args[0]] - print("%s supports these image types: %s" % (p["display"], ", ".join(p["supported_types"]))) - print("Settings:") - for k in p["settings-info"]: - f = p["settings-info"][k] - print(" %-20s: %s is a %s" % (k, f["display"], f["type"])) - - return 0 - -def providers_show(socket_path, api_version, args, show_json=False, testmode=0): - """Return details about a provider - - :param socket_path: Path to the Unix socket to use for API communication - :type socket_path: str - :param api_version: Version of the API to talk to. eg. "0" - :type api_version: str - :param args: List of remaining arguments from the cmdline - :type args: list of str - :param show_json: Set to True to show the JSON output instead of the human readable output - :type show_json: bool - :param testmode: unused in this function - :type testmode: int - - providers show - """ - if len(args) == 0: - log.error("show is missing the provider name") - return 1 - if len(args) == 1: - log.error("show is missing the profile name") - return 1 - - api_route = client.api_url(api_version, "/upload/providers") - r = client.get_url_json(socket_path, api_route) - results = r["providers"] - if not results: - return 0 - - if show_json: - print(json.dumps(results, indent=4)) - else: - if args[0] not in results: - log.error("%s is not a valid provider", args[0]) - return 1 - if args[1] not in results[args[0]]["profiles"]: - log.error("%s is not a valid %s profile", args[1], args[0]) - return 1 - - # Print the details for this profile - # fields are different for each provider, so we just print out the key:values - for k in results[args[0]]["profiles"][args[1]]: - print("%s: %s" % (k, results[args[0]]["profiles"][args[1]][k])) - return 0 - -def providers_push(socket_path, api_version, args, show_json=False, testmode=0): - """Add a new provider profile or overwrite an existing one - - :param socket_path: Path to the Unix socket to use for API communication - :type socket_path: str - :param api_version: Version of the API to talk to. eg. "0" - :type api_version: str - :param args: List of remaining arguments from the cmdline - :type args: list of str - :param show_json: Set to True to show the JSON output instead of the human readable output - :type show_json: bool - :param testmode: unused in this function - :type testmode: int - - providers push - - """ - if len(args) == 0: - log.error("push is missing the profile TOML file") - return 1 - if not os.path.exists(args[0]): - log.error("Missing profile TOML file: %s", args[0]) - return 1 - - api_route = client.api_url(api_version, "/upload/providers/save") - profile = toml.load(args[0]) - result = client.post_url_json(socket_path, api_route, json.dumps(profile)) - return handle_api_result(result, show_json)[0] - -def providers_save(socket_path, api_version, args, show_json=False, testmode=0): - """Save a provider's profile to a TOML file - - :param socket_path: Path to the Unix socket to use for API communication - :type socket_path: str - :param api_version: Version of the API to talk to. eg. "0" - :type api_version: str - :param args: List of remaining arguments from the cmdline - :type args: list of str - :param show_json: Set to True to show the JSON output instead of the human readable output - :type show_json: bool - :param testmode: unused in this function - :type testmode: int - - providers save - - """ - if len(args) == 0: - log.error("save is missing the provider name") - return 1 - if len(args) == 1: - log.error("save is missing the profile name") - return 1 - - api_route = client.api_url(api_version, "/upload/providers") - r = client.get_url_json(socket_path, api_route) - results = r["providers"] - if not results: - return 0 - - if show_json: - print(json.dumps(results, indent=4)) - else: - if args[0] not in results: - log.error("%s is not a valid provider", args[0]) - return 1 - if args[1] not in results[args[0]]["profiles"]: - log.error("%s is not a valid %s profile", args[1], args[0]) - return 1 - - profile = { - "provider": args[0], - "profile": args[1], - "settings": results[args[0]]["profiles"][args[1]] - } - open(toml_filename(args[1]), "w").write(toml.dumps(profile)) - - return 0 - -def providers_delete(socket_path, api_version, args, show_json=False, testmode=0): - """Delete a profile from a provider - - :param socket_path: Path to the Unix socket to use for API communication - :type socket_path: str - :param api_version: Version of the API to talk to. eg. "0" - :type api_version: str - :param args: List of remaining arguments from the cmdline - :type args: list of str - :param show_json: Set to True to show the JSON output instead of the human readable output - :type show_json: bool - :param testmode: unused in this function - :type testmode: int - - providers delete - - """ - if len(args) == 0: - log.error("delete is missing the provider name") - return 1 - if len(args) == 1: - log.error("delete is missing the profile name") - return 1 - - api_route = client.api_url(api_version, "/upload/providers/delete/%s/%s" % (args[0], args[1])) - result = client.delete_url_json(socket_path, api_route) - return handle_api_result(result, show_json)[0] - -def providers_template(socket_path, api_version, args, show_json=False, testmode=0): - """Return a TOML template for setting the provider's fields - - :param socket_path: Path to the Unix socket to use for API communication - :type socket_path: str - :param api_version: Version of the API to talk to. eg. "0" - :type api_version: str - :param args: List of remaining arguments from the cmdline - :type args: list of str - :param show_json: Set to True to show the JSON output instead of the human readable output - :type show_json: bool - :param testmode: unused in this function - :type testmode: int - - providers template - """ - if len(args) == 0: - log.error("template is missing the provider name") - return 1 - - api_route = client.api_url(api_version, "/upload/providers") - r = client.get_url_json(socket_path, api_route) - results = r["providers"] - if not results: - return 0 - - if show_json: - print(json.dumps(results, indent=4)) - return 0 - - if args[0] not in results: - log.error("%s is not a valid provider", args[0]) - return 1 - - template = {"provider": args[0]} - settings = results[args[0]]["settings-info"] - template["settings"] = dict([(k, settings[k]["display"]) for k in settings]) - print(toml.dumps(template)) - - return 0 diff --git a/src/composer/cli/upload.py b/src/composer/cli/upload.py deleted file mode 100644 index ca81abf1..00000000 --- a/src/composer/cli/upload.py +++ /dev/null @@ -1,277 +0,0 @@ -# -# Copyright (C) 2019 Red Hat, Inc. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -import logging -log = logging.getLogger("composer-cli") - -import json -import pytoml as toml -import os - -from composer import http_client as client -from composer.cli.help import upload_help -from composer.cli.utilities import handle_api_result - -def upload_cmd(opts): - """Process upload commands - - :param opts: Cmdline arguments - :type opts: argparse.Namespace - :returns: Value to return from sys.exit() - :rtype: int - - This dispatches the upload commands to a function - """ - cmd_map = { - "list": upload_list, - "info": upload_info, - "start": upload_start, - "log": upload_log, - "cancel": upload_cancel, - "delete": upload_delete, - "reset": upload_reset, - } - if opts.args[1] == "help" or opts.args[1] == "--help": - print(upload_help) - return 0 - elif opts.args[1] not in cmd_map: - log.error("Unknown upload command: %s", opts.args[1]) - return 1 - - return cmd_map[opts.args[1]](opts.socket, opts.api_version, opts.args[2:], opts.json, opts.testmode) - -def upload_list(socket_path, api_version, args, show_json=False, testmode=0): - """Return the composes and their associated upload uuids and status - - :param socket_path: Path to the Unix socket to use for API communication - :type socket_path: str - :param api_version: Version of the API to talk to. eg. "0" - :type api_version: str - :param args: List of remaining arguments from the cmdline - :type args: list of str - :param show_json: Set to True to show the JSON output instead of the human readable output - :type show_json: bool - :param testmode: unused in this function - :type testmode: int - - upload list - """ - api_route = client.api_url(api_version, "/compose/finished") - r = client.get_url_json(socket_path, api_route) - results = r["finished"] - if not results: - return 0 - - if show_json: - print(json.dumps(results, indent=4)) - else: - compose_fmt = "{id} {queue_status} {blueprint} {version} {compose_type}" - upload_fmt = ' {uuid} "{image_name}" {provider_name} {status}' - for c in results: - print(compose_fmt.format(**c)) - print("\n".join(upload_fmt.format(**u) for u in c["uploads"])) - print() - - return 0 - -def upload_info(socket_path, api_version, args, show_json=False, testmode=0): - """Return detailed information about the upload - - :param socket_path: Path to the Unix socket to use for API communication - :type socket_path: str - :param api_version: Version of the API to talk to. eg. "0" - :type api_version: str - :param args: List of remaining arguments from the cmdline - :type args: list of str - :param show_json: Set to True to show the JSON output instead of the human readable output - :type show_json: bool - :param testmode: unused in this function - :type testmode: int - - upload info - - This returns information about the upload, including uuid, name, status, service, and image. - """ - if len(args) == 0: - log.error("info is missing the upload uuid") - return 1 - - api_route = client.api_url(api_version, "/upload/info/%s" % args[0]) - result = client.get_url_json(socket_path, api_route) - (rc, exit_now) = handle_api_result(result, show_json) - if exit_now: - return rc - - image_path = result["upload"]["image_path"] - print("%s %-8s %-15s %-8s %s" % (result["upload"]["uuid"], - result["upload"]["status"], - result["upload"]["image_name"], - result["upload"]["provider_name"], - os.path.basename(image_path) if image_path else "UNFINISHED")) - - return rc - -def upload_start(socket_path, api_version, args, show_json=False, testmode=0): - """Start upload up a build uuid image - - :param socket_path: Path to the Unix socket to use for API communication - :type socket_path: str - :param api_version: Version of the API to talk to. eg. "0" - :type api_version: str - :param args: List of remaining arguments from the cmdline - :type args: list of str - :param show_json: Set to True to show the JSON output instead of the human readable output - :type show_json: bool - :param testmode: unused in this function - :type testmode: int - - upload start [ | ] - """ - if len(args) == 0: - log.error("start is missing the compose build id") - return 1 - if len(args) == 1: - log.error("start is missing the image name") - return 1 - if len(args) == 2: - log.error("start is missing the provider and profile details") - return 1 - - body = {"image_name": args[1]} - if len(args) == 3: - try: - body.update(toml.load(args[2])) - except toml.TomlError as e: - log.error(str(e)) - return 1 - elif len(args) == 4: - body["provider"] = args[2] - body["profile"] = args[3] - else: - log.error("start has incorrect number of arguments") - return 1 - - api_route = client.api_url(api_version, "/compose/uploads/schedule/%s" % args[0]) - result = client.post_url_json(socket_path, api_route, json.dumps(body)) - (rc, exit_now) = handle_api_result(result, show_json) - if exit_now: - return rc - - print("Upload %s added to the queue" % result["upload_id"]) - return rc - -def upload_log(socket_path, api_version, args, show_json=False, testmode=0): - """Return the upload log - - :param socket_path: Path to the Unix socket to use for API communication - :type socket_path: str - :param api_version: Version of the API to talk to. eg. "0" - :type api_version: str - :param args: List of remaining arguments from the cmdline - :type args: list of str - :param show_json: Set to True to show the JSON output instead of the human readable output - :type show_json: bool - :param testmode: unused in this function - :type testmode: int - - upload log - """ - if len(args) == 0: - log.error("log is missing the upload uuid") - return 1 - - api_route = client.api_url(api_version, "/upload/log/%s" % args[0]) - result = client.get_url_json(socket_path, api_route) - (rc, exit_now) = handle_api_result(result, show_json) - if exit_now: - return rc - - print("Upload log for %s:\n" % result["upload_id"]) - print(result["log"]) - - return 0 - -def upload_cancel(socket_path, api_version, args, show_json=False, testmode=0): - """Cancel the queued or running upload - - :param socket_path: Path to the Unix socket to use for API communication - :type socket_path: str - :param api_version: Version of the API to talk to. eg. "0" - :type api_version: str - :param args: List of remaining arguments from the cmdline - :type args: list of str - :param show_json: Set to True to show the JSON output instead of the human readable output - :type show_json: bool - :param testmode: unused in this function - :type testmode: int - - upload cancel - """ - if len(args) == 0: - log.error("cancel is missing the upload uuid") - return 1 - - api_route = client.api_url(api_version, "/upload/cancel/%s" % args[0]) - result = client.delete_url_json(socket_path, api_route) - return handle_api_result(result, show_json)[0] - -def upload_delete(socket_path, api_version, args, show_json=False, testmode=0): - """Delete an upload and remove it from the build - - :param socket_path: Path to the Unix socket to use for API communication - :type socket_path: str - :param api_version: Version of the API to talk to. eg. "0" - :type api_version: str - :param args: List of remaining arguments from the cmdline - :type args: list of str - :param show_json: Set to True to show the JSON output instead of the human readable output - :type show_json: bool - :param testmode: unused in this function - :type testmode: int - - upload delete - """ - if len(args) == 0: - log.error("delete is missing the upload uuid") - return 1 - - api_route = client.api_url(api_version, "/upload/delete/%s" % args[0]) - result = client.delete_url_json(socket_path, api_route) - return handle_api_result(result, show_json)[0] - -def upload_reset(socket_path, api_version, args, show_json=False, testmode=0): - """Reset the upload and execute it again - - :param socket_path: Path to the Unix socket to use for API communication - :type socket_path: str - :param api_version: Version of the API to talk to. eg. "0" - :type api_version: str - :param args: List of remaining arguments from the cmdline - :type args: list of str - :param show_json: Set to True to show the JSON output instead of the human readable output - :type show_json: bool - :param testmode: unused in this function - :type testmode: int - - upload reset - """ - if len(args) == 0: - log.error("reset is missing the upload uuid") - return 1 - - api_route = client.api_url(api_version, "/upload/reset/%s" % args[0]) - result = client.post_url_json(socket_path, api_route, json.dumps({})) - return handle_api_result(result, show_json)[0]