def add_standard_cmdline_options(parser, uses_pw_file=True, running_deployment=True, default_log_level="INFO"): """These are the command line options used by """ log_setup.add_log_option(parser, default=default_log_level) parser.add_option("--deployment-home", "-d", dest="deployment_home", default=None, help="Location of deployed application - can figure this out automatically unless installing from source") if uses_pw_file: if running_deployment: parser.add_option("-p", "--master-password-file", default=None, help="File containing master password (if not specified, will prompt from console if needed). If --suppress-master-password-file is not set, and the master password file is not already at <deployment_home>/config/master.pw, a master password file will be generated at that location. Permissions will be set to 0600.") parser.add_option("--generate-random-passwords", "-g", default=False, action="store_true", help="If passwords are needed for individual components to be installed, generate random passwords rather than prompting for them") parser.add_option("--suppress-master-password-file", default=False, action="store_true", help="If specified, do not create a file containing the master password at <deployment_home>/config/master.pw.") else: parser.add_option("-p", "--master-password-file", default=None, help="File containing master password. If not specified, will look for file at <deployment_home>/config/master.pw. If that file is not present, prompt from console if needed)") ## parser.add_option("--generate-password-file", "-g", ## dest="generate_password_file", ## default=False, action="store_true", ## help="If specified, generate a password file and exit") parser.add_option("-s", "--subproc", action="store_true", dest="subproc", default=False, help="Run in subprocess mode, getting master password from standard input") if running_deployment: parser.add_option("--mgt-backends", dest="mgt_backends", default=None, help="If specified, a list of management backend plugin(s)") parser.add_option("--force-stop-on-error", dest="force_stop_on_error", default=False, action="store_true", help="If specified, force stop any running daemons if the install fails. Default is to leave things running (helpful for debugging).") parser.add_option("-n", "--dry-run", action="store_true", default=False, help="If specified, just do a dry run and exit")
def process_args(self, argv): usage = "usage: %prog [options] deployment_home" parser = OptionParser(usage=usage) add_log_option(parser) parser.add_option("--application-archive", "-a", dest="application_archive", action="store", default=None, help="If specified, override the application_archive property in config choices file with this value") parser.add_option("-s", "--subproc", action="store_true", dest="subproc", default=False, help="Run in subprocess mode, getting master password from standard input") parser.add_option("-x", "--python", default=None, help="Use the specified python executable as basis for Python virtual environments", dest="python_exe") parser.add_option("-p", "--master-password-file", default=None, help="File containing master password (if not specified, will prompt from console if needed)") (self.options, args) = parser.parse_args(args=argv) if len(args) != 1: parser.error("Expecting exactly one argument, the deployment's home directory") self.deployment_home = os.path.abspath(os.path.expanduser(args[0])) if not os.path.exists(self.deployment_home): parser.error("Deployment home %s not found" % self.deployment_home) self.config_dir = os.path.join(self.deployment_home, "config") if not os.path.exists(self.config_dir): parser.error("Configuration directory %s does not exist" % self.config_dir) log_directory_file = os.path.join(self.config_dir, "log_directory.txt") if not os.path.exists(log_directory_file): parser.error("Log directory pointer file %s does not exit" % log_directory_file) with open(log_directory_file, "r") as f: self.log_directory = f.read().rstrip() parse_log_options(self.options, self.log_directory) if self.options.python_exe: if not os.path.exists(self.options.python_exe): parser.error("Python executable %s does not exist" % self.options.python_exe) if self.options.master_password_file: if not os.path.exists(self.options.master_password_file): parser.error("Master password file %s not found" % self.options.master_password_file) self.engage_home = os.path.join(self.deployment_home, "engage") if not os.path.isdir(self.engage_home): parser.error("Engage home %s does not exist" % self.engage_home) self.engage_bin_dir = os.path.join(self.engage_home, "bin") if not os.path.isdir(self.engage_bin_dir): parser.error("Engage binary directory %s does not exist" % self.engage_bin_dir) if self.options.application_archive: self.application_archive = os.path.abspath(os.path.expanduser(self.options.application_archive)) if not os.path.exists(self.application_archive): parser.error("Application archive file %s does not exist" % self.application_archive) if os.path.exists(os.path.join(self.config_dir, "pw_repository")): if self.options.master_password_file: with open(self.options.master_password_file, "rb") as f: self.master_pw = f.read().rstrip() elif self.options.subproc: self.master_pw = sys.stdin.read().rstrip() else: while True: self.master_pw = getpass.getpass("Master password:"******"Re-enter Master password:"******"Passwords do not match, try again."
def main(argv): usage = "usage: %prog [options] deployment_home" parser = OptionParser(usage=usage) add_log_option(parser) parser.add_option("-d", "--logdir", action="store", type="string", help="master log directory for deployment (defaults to <deployment_home>/log)", dest="logdir", default=None) parser.add_option("-c", "--create-dist-archive", action="store_true", help="create a distribution archive", dest="create_dist_archive", default=False) parser.add_option("-x", "--python", default=None, help="Use the specified python executable as basis for Python virtual environments", dest="python_exe") parser.add_option("--never-download", default=False, action="store_true", help="If specified, never try to download packages during bootstrap. If a package is required, exit with an error.", dest="never_download") parser.add_option("--include-test-data", default=False, action="store_true", help="If specified, copy test data into the deployment home. Otherwise, tests requiring data will be skipped.") (options, args) = parser.parse_args(args=argv) if len(args) != 1: parser.error("Expecting exactly one argument, the deployment's home directory") logger = setup_logger("Bootstrap", __name__) if options.python_exe: options.python_exe = os.path.abspath(os.path.expanduser(options.python_exe)) if not os.path.exists(options.python_exe): parser.error("Python executable %s does not exist" % options.python_exe) if not os.access(options.python_exe, os.X_OK): parser.error("Python executable file %s is not an executable" % options.python_exe) test_data_src = os.path.join(base_src_dir, "test_data") if options.include_test_data and not os.path.isdir(test_data_src): parser.error("--include-test-data specified, but test data directory %s does not exist" % test_data_src) deployment_home = os.path.abspath(os.path.expanduser(args[0])) if os.path.exists(deployment_home): sentry_file = os.path.join(deployment_home, "config/installed_resources.json") if os.path.exists(sentry_file): raise Exception("Deployment home directory %s exists and contains the file %s. Cannot overwrite an existing install." % (deployment_home, sentry_file)) else: os.makedirs(deployment_home) if options.logdir: log_dir = os.path.abspath(os.path.expanduser(options.logdir)) else: log_dir = os.path.join(deployment_home, "log") if not os.path.exists(log_dir): os.makedirs(log_dir) parse_log_options(options, log_dir) logger.info("Running bootstrap under Python executable %s" % sys.executable) # the engage home is just a python virtual environment engage_home = os.path.join(deployment_home, "engage") sw_packages_src_loc = os.path.join(base_src_dir, "sw_packages") sw_packages_dst_loc = os.path.join(engage_home, "sw_packages") create_virtualenv(engage_home, logger, sw_packages_src_loc, base_python_exe=options.python_exe, never_download=options.never_download) logger.info("Created python virtualenv for engage") # copy this bootstrap script and the upgrade script bootstrap_py_dst = os.path.join(engage_home, "bootstrap.py") shutil.copyfile(os.path.join(base_src_dir, "bootstrap.py"), bootstrap_py_dst) os.chmod(bootstrap_py_dst, 0755) upgrade_py_src = os.path.join(base_src_dir, "upgrade.py") upgrade_py_dst = os.path.join(engage_home, "upgrade.py") shutil.copyfile(upgrade_py_src, upgrade_py_dst) os.chmod(upgrade_py_dst, 0755) # we also copy the python_pkg directory to the distribution home for use in creating # future distributions python_pkg_dst_dir = os.path.join(engage_home, "python_pkg") copy_tree(python_pkg_dir, python_pkg_dst_dir, logger) # we need to run the setup.py script for the python_pkg engage_bin_dir = os.path.join(engage_home, "bin") engage_python_exe = os.path.join(engage_bin_dir, "python") assert os.path.exists(engage_python_exe), "Python executable at %s missing" % engage_python_exe setup_py_file = os.path.join(python_pkg_dir, "setup.py") assert os.path.exists(setup_py_file), "Missing %s" % setup_py_file cmd = "%s %s install" % (engage_python_exe, setup_py_file) rc = system(cmd, logger, cwd=python_pkg_dir) if rc != 0: raise Exception("Install of engage python packages failed: '%s' failed, rc was %d" % (cmd, rc)) logger.info("Installed python packages") platform = get_platform() # copy the configurator binary config_exe_src_loc = os.path.join(base_src_dir, "bin/configurator-%s" % platform) assert os.path.exists(config_exe_src_loc), "Configurator executable missing at %s" % config_exe_src_loc config_exe_dst_loc = os.path.join(engage_bin_dir, "configurator-%s" % platform) logger.action("cp %s %s" % (config_exe_src_loc, config_exe_dst_loc)) shutil.copyfile(config_exe_src_loc, config_exe_dst_loc) os.chmod(config_exe_dst_loc, 0755) symlink_loc = os.path.join(engage_bin_dir, "configurator") logger.action("ln -s %s %s" % (config_exe_dst_loc, symlink_loc)) os.symlink(config_exe_dst_loc, symlink_loc) # copy the metadata files metadata_files_src_loc = os.path.join(base_src_dir, "metadata") metadata_files_dst_loc = os.path.join(engage_home, "metadata") copy_tree(metadata_files_src_loc, metadata_files_dst_loc, logger) # copy the sw_packages directory copy_tree(sw_packages_src_loc, sw_packages_dst_loc, logger) if not is_package_installed(engage_bin_dir, "Crypto.Cipher.AES", logger): if get_platform()=="linux64" and (not options.never_download): run_apt_install("python-crypto", logger) else: # Pycrypto may be preinstalled on the machine. # If so, we don't install our local copy, as installation # can be expensive (involves a g++ compile). run_install(engage_bin_dir, sw_packages_src_loc, ["pycrypto-2.3-%s.tar.gz" % platform, "pycrypto-2.3.tar.gz"], logger, "pycrypto", never_download=options.never_download) bootstrap_packages = [# JF 2012-05-11: Don't install provision and its # dependencies - moving down to DJM level. #(["paramiko-1.7.6.zip"], "paramiko"), #(["apache-libcloud-0.6.2.tar.bz2"], None), #(["argparse-1.2.1.tar.gz"], "argparse"), #(["provision-0.9.3-dev.tar.gz"], None), (["nose-1.0.0.tar.gz"], "nose"), (["engage_utils-1.0.tar.gz"], "git+git://github.com/genforma/engage-utils.git")] # run install for all of the bootstrap packages for (package_file_list, alternate) in bootstrap_packages: run_install(engage_bin_dir, sw_packages_src_loc, package_file_list, logger, alternate, never_download=options.never_download) # create a virtualenv for the deployed apps deployed_virtualenv = os.path.join(deployment_home, "python") create_virtualenv(deployed_virtualenv, logger, sw_packages_src_loc, base_python_exe=options.python_exe, never_download=options.never_download) logger.info("Created a virtualenv for deployed apps") deployed_config_dir = os.path.join(deployment_home, "config") os.makedirs(deployed_config_dir) # don't use "with" as this should be python 2.5 compatible f = open(os.path.join(deployed_config_dir, "log_directory.txt"), "wb") try: f.write(log_dir) finally: f.close() # copy the test data if requested if options.include_test_data: test_data_dest = os.path.join(engage_home, "test_data") copy_tree(test_data_src, test_data_dest, logger) if options.create_dist_archive: logger.info("Creating a distribution") import engage.engine.create_distribution engage.engine.create_distribution.create_distribution_from_deployment_home(deployment_home, include_test_data=options.include_test_data) logger.info("Engage environment bootstrapped successfully") return 0