#!/usr/bin/python # # 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 recipe 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. recipes list List the names of the available recipes. show Display the recipe in TOML format. changes Display the changes for each recipe. diff Display the differences between 2 versions of a recipe. Commit hash or NEWEST Commit hash, NEWEST, or WORKSPACE save Save the recipe to a file, .toml delete Delete a recipe from the server depsolve Display the packages needed to install the recipe. push Push a recipe TOML file to the server. freeze Display the frozen recipe's modules and packages. freeze show Display the frozen recipe in TOML format. freeze save Save the frozen recipe to a file, .frozen.toml. tag Tag the most recent recipe commit as a release. undo Undo changes to a recipe by reverting to the selected commit. workspace Push the recipe 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="/var/log/lorax-composer/cli.log", metavar="LOG", help="Path to logfile (/var/log/lorax-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))