#!/usr/bin/python3 # # composer-cli # # Copyright (C) 2018 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 os import sys import argparse from composer import vernum from composer.cli import main VERSION = "{0}-{1}".format(os.path.basename(sys.argv[0]), vernum) # Documentation for the commands epilog = """ compose start Start a compose using the selected blueprint and output type. types List the supported output types. status List the status of all running and finished composes. log [kB] Show the last 1kB of the compose log. cancel Cancel a running compose and delete any intermediate results. delete Delete the listed compose results. info Show detailed information on the compose. metadata Download the metadata use to create the compose to -metadata.tar logs Download the compose logs to -logs.tar results Download all of the compose results; metadata, logs, and image to .tar image Download the output image from the compose. Filename depends on the type. blueprints list List the names of the available blueprints. show Display the blueprint in TOML format. changes Display the changes for each blueprint. diff Display the differences between 2 versions of a blueprint. Commit hash or NEWEST Commit hash, NEWEST, or WORKSPACE save Save the blueprint to a file, .toml delete Delete a blueprint from the server depsolve Display the packages needed to install the blueprint. push Push a blueprint TOML file to the server. freeze Display the frozen blueprint's modules and packages. freeze show Display the frozen blueprint in TOML format. freeze save Save the frozen blueprint to a file, .frozen.toml. tag Tag the most recent blueprint commit as a release. undo Undo changes to a blueprint by reverting to the selected commit. workspace Push the blueprint TOML to the temporary workspace storage. modules list List the available modules. projects list List the available projects. projects info Show details about the listed projects. """ def get_parser(): """ Return the ArgumentParser for composer-cli""" parser = argparse.ArgumentParser(description="Lorax Composer commandline tool", epilog=epilog, formatter_class=argparse.RawDescriptionHelpFormatter, fromfile_prefix_chars="@") parser.add_argument("-j", "--json", action="store_true", default=False, help="Output the raw JSON response instead of the normal output.") parser.add_argument("-s", "--socket", default="/run/weldr/api.socket", metavar="SOCKET", help="Path to the socket file to listen on") parser.add_argument("--log", dest="logfile", default="./composer-cli.log", metavar="LOG", help="Path to logfile (./composer-cli.log)") parser.add_argument("-a", "--api", dest="api_version", default="0", metavar="APIVER", help="API Version to use") parser.add_argument("--test", dest="testmode", default=0, type=int, metavar="TESTMODE", help="Pass test mode to compose. 1=Mock compose with fail. 2=Mock compose with finished.") parser.add_argument("-V", action="store_true", dest="showver", help="show program's version number and exit") # Commands are implemented by parsing the remaining arguments outside of argparse parser.add_argument('args', nargs=argparse.REMAINDER) return parser def setup_logging(logfile): # Setup logging to console and to logfile log.setLevel(logging.DEBUG) sh = logging.StreamHandler() sh.setLevel(logging.INFO) fmt = logging.Formatter("%(asctime)s: %(message)s") sh.setFormatter(fmt) log.addHandler(sh) fh = logging.FileHandler(filename=logfile) fh.setLevel(logging.DEBUG) fmt = logging.Formatter("%(asctime)s %(levelname)s %(name)s: %(message)s") fh.setFormatter(fmt) log.addHandler(fh) if __name__ == '__main__': # parse the arguments opts = get_parser().parse_args() if opts.showver: print(VERSION) sys.exit(0) logpath = os.path.abspath(os.path.dirname(opts.logfile)) if not os.path.isdir(logpath): os.makedirs(logpath) setup_logging(opts.logfile) log.debug("opts=%s", opts) errors = [] # Check to see if the socket exists and can be accessed if not os.path.exists(opts.socket): errors.append("%s does not exist" % opts.socket) elif not os.access(opts.socket, os.R_OK|os.W_OK): errors.append("This user cannot access %s" % opts.socket) # No point in continuing if there are errors if errors: for e in errors: log.error(e) sys.exit(1) sys.exit(main(opts))