def cmd_deploy(args, config): label = args.label[0] commit = args.commit[0] gondor_dirname = ".gondor" try: project_root = utils.find_nearest(os.getcwd(), gondor_dirname) except OSError: error("unable to find a .gondor directory.\n") tar_path, tarball_path = None, None try: out("Reading configuration... ") local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(project_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") vcs = local_config.get("gondor", "vcs") app_config = { "requirements_file": config_value(local_config, "app", "requirements_file"), "wsgi_entry_point": config_value(local_config, "app", "wsgi_entry_point"), "migrations": config_value(local_config, "app", "migrations"), "staticfiles": config_value(local_config, "app", "staticfiles"), "site_media_url": config_value(local_config, "app", "site_media_url"), } include_files = [x.strip() for x in config_value(local_config, "files", "include", "").split("\n") if x] out("[ok]\n") if vcs == "git": try: repo_root = utils.find_nearest(os.getcwd(), ".git") except OSError: error("unable to find a .git directory.\n") try: git = utils.find_command("git") except utils.BadCommand, e: error(e.args[0]) check, sha = utils.run_proc([git, "rev-parse", commit]) if check != 0: error("could not map '%s' to a SHA\n" % commit) if commit == "HEAD": commit = sha tar_path = os.path.abspath(os.path.join(repo_root, "%s-%s.tar" % (label, sha))) cmd = [git, "archive", "--format=tar", commit, "-o", tar_path] elif vcs == "hg": try: repo_root = utils.find_nearest(os.getcwd(), ".hg") except OSError: error("unable to find a .hg directory.\n") try: hg = utils.find_command("hg") except utils.BadCommand, e: error(e.args[0])
def cmd_list(args, config): gondor_dirname = ".gondor" try: project_root = utils.find_nearest(os.getcwd(), gondor_dirname) except OSError: error("unable to find a .gondor directory.\n") out("Reading configuration... ") local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(project_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") out("[ok]\n") url = "%s/list/" % endpoint params = { "version": __version__, "site_key": site_key, } response = make_api_call(config, url, urllib.urlencode(params)) data = json.loads(response.read()) if data["status"] == "success": out("\n") instances = sorted(data["instances"], key=lambda v: v["label"]) if instances: for instance in instances: out("%s [%s] %s\n" % (instance["label"], instance["kind"], instance["last_deployment"]["sha"][:8])) else: out("No instances found.\n") else: error("%s\n" % data["message"])
def cmd_sqldump(args, config): label = args.label[0] gondor_dirname = ".gondor" repo_root = utils.find_nearest(os.getcwd(), gondor_dirname) local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(repo_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") # request SQL dump and stream the response through uncompression err("Dumping database... ") url = "%s/sqldump/" % endpoint params = { "version": __version__, "site_key": site_key, "label": label, } try: response = make_api_call(config, url, urllib.urlencode(params)) except urllib2.HTTPError, e: out("\nReceived an error [%d: %s]" % (e.code, e.read())) sys.exit(1)
def cmd_manage(args, config): instance_label = args.label[0] operation = args.operation[0] opargs = args.opargs gondor_dirname = ".gondor" try: project_root = utils.find_nearest(os.getcwd(), gondor_dirname) except OSError: error("unable to find a .gondor directory.\n") out("Reading configuration... ") local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(project_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") out("[ok]\n") url = "%s/manage/" % endpoint params = {"version": __version__, "site_key": site_key, "instance_label": instance_label, "operation": operation} handlers = [http.MultipartPostHandler] if not sys.stdin.isatty(): params["stdin"] = sys.stdin pb = ProgressBar(0, 100, 77) out("Pushing stdin to Gondor... \n") handlers.extend([http.UploadProgressHandler(pb, ssl=True), http.UploadProgressHandler(pb, ssl=False)]) params = params.items() for oparg in opargs: params.append(("arg", oparg)) try: response = make_api_call(config, url, params, extra_handlers=handlers) except urllib2.HTTPError, e: out("\nReceived an error [%d: %s]" % (e.code, e.read())) sys.exit(1)
def cmd_delete(args, config): instance_label = args.label[0] gondor_dirname = ".gondor" try: project_root = utils.find_nearest(os.getcwd(), gondor_dirname) except OSError: error("unable to find a .gondor directory.\n") out("Reading configuration... ") local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(project_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") out("[ok]\n") text = "ARE YOU SURE YOU WANT TO DELETE THIS INSTANCE? [Y/N] " out(text) user_input = raw_input() if user_input != "Y": out("Exiting without deleting the instance.\n") sys.exit(0) text = "Deleting... " url = "%s/delete/" % endpoint params = {"version": __version__, "site_key": site_key, "instance_label": instance_label} try: response = make_api_call(config, url, urllib.urlencode(params)) except urllib2.HTTPError, e: out("\nReceived an error [%d: %s]" % (e.code, e.read())) sys.exit(1)
def cmd_list(args, config): gondor_dirname = ".gondor" try: project_root = utils.find_nearest(os.getcwd(), gondor_dirname) except OSError: error("unable to find a .gondor directory.\n") out("Reading configuration... ") local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(project_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") out("[ok]\n") url = "%s/list/" % endpoint params = { "version": __version__, "site_key": site_key, } try: response = make_api_call(config, url, urllib.urlencode(params)) except urllib2.HTTPError, e: out("\nReceived an error [%d: %s]" % (e.code, e.read())) sys.exit(1)
def cmd_create(args, config): gondor_dirname = ".gondor" try: project_root = utils.find_nearest(os.getcwd(), gondor_dirname) except OSError: error("unable to find a .gondor directory.\n") label = args.label[0] kind = args.kind if kind is None: kind = "dev" try: repo_root = utils.find_nearest(os.getcwd(), ".git") except OSError: try: repo_root = utils.find_nearest(os.getcwd(), ".hg") except OSError: error("unable to find a supported version control directory. Looked for .git and .hg.\n") else: vcs = "hg" else: vcs = "git" out("Reading configuration... ") local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(project_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") out("[ok]\n") text = "Creating instance on Gondor... " url = "%s/create/" % endpoint params = { "version": __version__, "site_key": site_key, "label": label, "kind": kind, "project_root": os.path.basename(project_root), } try: response = make_api_call(config, url, urllib.urlencode(params)) except urllib2.HTTPError, e: out("\nReceived an error [%d: %s]" % (e.code, e.read())) sys.exit(1)
def cmd_init(args, config): site_key = args.site_key[0] if len(site_key) < 11: error("The site key given is too short.\n") # ensure os.getcwd() is a Django directory files = [ os.path.join(os.getcwd(), "__init__.py"), os.path.join(os.getcwd(), "manage.py") ] if not all([os.path.exists(f) for f in files]): error("must run gondor init from a Django project directory.\n") gondor_dir = os.path.abspath(os.path.join(os.getcwd(), ".gondor")) try: repo_root = utils.find_nearest(os.getcwd(), ".git") except OSError: try: repo_root = utils.find_nearest(os.getcwd(), ".hg") except OSError: error( "unable to find a supported version control directory. Looked for .git and .hg.\n" ) else: vcs = "hg" else: vcs = "git" if not os.path.exists(gondor_dir): os.mkdir(gondor_dir) # write out a .gondor/config INI file new_config = ConfigParser.RawConfigParser() new_config.add_section("gondor") new_config.set("gondor", "site_key", site_key) new_config.set("gondor", "vcs", vcs) new_config.add_section("app") new_config.set("app", "requirements_file", "requirements/project.txt") new_config.set("app", "wsgi_entry_point", "deploy.wsgi") new_config.set("app", "migrations", "none") with open(os.path.join(gondor_dir, "config"), "wb") as cf: new_config.write(cf)
def cmd_init(args, config): site_key = args.site_key[0] if len(site_key) < 11: error("The site key given is too short.\n") # ensure os.getcwd() is a Django directory files = [ os.path.join(os.getcwd(), "__init__.py"), os.path.join(os.getcwd(), "manage.py") ] if not all([os.path.exists(f) for f in files]): error("must run gondor init from a Django project directory.\n") gondor_dir = os.path.abspath(os.path.join(os.getcwd(), ".gondor")) try: repo_root = utils.find_nearest(os.getcwd(), ".git") except OSError: try: repo_root = utils.find_nearest(os.getcwd(), ".hg") except OSError: error("unable to find a supported version control directory. Looked for .git and .hg.\n") else: vcs = "hg" else: vcs = "git" if not os.path.exists(gondor_dir): os.mkdir(gondor_dir) # write out a .gondor/config INI file new_config = ConfigParser.RawConfigParser() new_config.add_section("gondor") new_config.set("gondor", "site_key", site_key) new_config.set("gondor", "vcs", vcs) new_config.add_section("app") new_config.set("app", "requirements_file", "requirements/project.txt") new_config.set("app", "wsgi_entry_point", "deploy.wsgi") new_config.set("app", "migrations", "none") with open(os.path.join(gondor_dir, "config"), "wb") as cf: new_config.write(cf)
def cmd_create(args, config): gondor_dirname = ".gondor" try: project_root = utils.find_nearest(os.getcwd(), gondor_dirname) except OSError: error("unable to find a .gondor directory.\n") label = args.label[0] kind = args.kind if kind is None: kind = "dev" out("Reading configuration... ") local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(project_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") out("[ok]\n") text = "Creating instance on Gondor... " url = "%s/create/" % endpoint params = { "version": __version__, "site_key": site_key, "label": label, "kind": kind, "project_root": os.path.basename(project_root), } response = make_api_call(config, url, urllib.urlencode(params)) data = json.loads(response.read()) if data["status"] == "error": message = "error" elif data["status"] == "success": message = "ok" else: message = "unknown" out("\r%s[%s] \n" % (text, message)) if data["status"] == "success": out("\nRun: gondor deploy %s HEAD" % label) out("\nVisit: %s\n" % data["url"]) else: error("%s\n" % data["message"])
def cmd_delete(args, config): instance_label = args.label[0] gondor_dirname = ".gondor" try: project_root = utils.find_nearest(os.getcwd(), gondor_dirname) except OSError: error("unable to find a .gondor directory.\n") out("Reading configuration... ") local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(project_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") out("[ok]\n") text = "ARE YOU SURE YOU WANT TO DELETE THIS INSTANCE? [Y/N] " out(text) user_input = raw_input() if user_input != "Y": out("Exiting without deleting the instance.\n") sys.exit(0) text = "Deleting... " url = "%s/delete/" % endpoint params = { "version": __version__, "site_key": site_key, "instance_label": instance_label, } response = make_api_call(config, url, urllib.urlencode(params)) data = json.loads(response.read()) if data["status"] == "error": message = "error" elif data["status"] == "success": message = "ok" else: message = "unknown" out("\r%s[%s] \n" % (text, message)) if data["status"] == "error": error("%s\n" % data["message"])
def cmd_list(args, config): gondor_dirname = ".gondor" try: project_root = utils.find_nearest(os.getcwd(), gondor_dirname) except OSError: error("unable to find a .gondor directory.\n") out("Reading configuration... ") local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(project_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") out("[ok]\n") url = "%s/list/" % endpoint params = { "version": __version__, "site_key": site_key, } response = make_api_call(config, url, urllib.urlencode(params)) data = json.loads(response.read()) if data["status"] == "success": out("\n") instances = sorted(data["instances"], key=lambda v: v["label"]) if instances: for instance in instances: out("%s [%s] %s\n" % ( instance["label"], instance["kind"], instance["last_deployment"]["sha"][:8] )) else: out("No instances found.\n") else: error("%s\n" % data["message"])
def cmd_deploy(args, config): label = args.label[0] commit = args.commit[0] gondor_dirname = ".gondor" try: project_root = utils.find_nearest(os.getcwd(), gondor_dirname) except OSError: error("unable to find a .gondor directory.\n") tar_path, tarball_path = None, None try: out("Reading configuration... ") local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(project_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") vcs = local_config.get("gondor", "vcs") app_config = { "requirements_file": config_value(local_config, "app", "requirements_file"), "wsgi_entry_point": config_value(local_config, "app", "wsgi_entry_point"), "migrations": config_value(local_config, "app", "migrations"), "staticfiles": config_value(local_config, "app", "staticfiles"), } include_files = [ x.strip() for x in config_value(local_config, "files", "include", "").split("\n") if x ] out("[ok]\n") if vcs == "git": try: repo_root = utils.find_nearest(os.getcwd(), ".git") except OSError: error("unable to find a .git directory.\n") check, sha = utils.run_proc(["git", "rev-parse", commit]) if check != 0: error("could not map '%s' to a SHA\n" % commit) if commit == "HEAD": commit = sha tar_path = os.path.abspath(os.path.join(repo_root, "%s-%s.tar" % (label, sha))) cmd = ["git", "archive", "--format=tar", commit, "-o", tar_path] elif vcs == "hg": try: repo_root = utils.find_nearest(os.getcwd(), ".hg") except OSError: error("unable to find a .hg directory.\n") branches_stdout = utils.run_proc(["hg", "branches"])[1] tags_stdout = utils.run_proc(["hg", "tags"])[1] refs = {} for line in branches_stdout.splitlines() + tags_stdout.splitlines(): m = re.search(r"([\w\d\.-]+)\s*([\d]+):([\w]+)$", line) if m: refs[m.group(1)] = m.group(3) try: sha = refs[commit] except KeyError: error("could not map '%s' to a SHA\n" % commit) tar_path = os.path.abspath(os.path.join(repo_root, "%s-%s.tar" % (label, sha))) cmd = ["hg", "archive", "-p", ".", "-t", "tar", "-r", commit, tar_path] else: error("'%s' is not a valid version control system for Gondor\n" % vcs) out("Archiving code from %s... " % commit) check, output = utils.run_proc(cmd, cwd=repo_root) if check != 0: error(output) out("[ok]\n") if include_files: out("Adding untracked files... ") try: tar_fp = tarfile.open(tar_path, "a") for f in include_files: tar_fp.add(os.path.abspath(os.path.join(repo_root, f)), arcname=f) finally: tar_fp.close() out("[ok]\n") tarball_path = os.path.abspath(os.path.join(repo_root, "%s-%s.tar.gz" % (label, sha))) out("Building tarball... ") with open(tar_path, "rb") as tar_fp: try: tarball = gzip.open(tarball_path, mode="wb") tarball.writelines(tar_fp) finally: tarball.close() out("[ok]\n") pb = ProgressBar(0, 100, 77) out("Pushing tarball to Gondor... \n") url = "%s/deploy/" % endpoint with open(tarball_path, "rb") as tarball: params = { "version": __version__, "site_key": site_key, "label": label, "sha": sha, "commit": commit, "tarball": tarball, "project_root": os.path.relpath(project_root, repo_root), "app": json.dumps(app_config), } handlers = [ http.MultipartPostHandler, http.UploadProgressHandler(pb, ssl=True), http.UploadProgressHandler(pb, ssl=False) ] try: response = make_api_call(config, url, params, extra_handlers=handlers) except KeyboardInterrupt: out("\nCanceling uploading... [ok]\n") sys.exit(1) except urllib2.HTTPError, e: out("\nReceived an error [%d: %s]" % (e.code, e.read())) sys.exit(1) else:
def main(): parser = argparse.ArgumentParser(prog="gondor") parser.add_argument("--version", action="version", version="%%(prog)s %s" % __version__) parser.add_argument("--verbose", "-v", action="count", default=1) command_parsers = parser.add_subparsers(dest="command") # cmd: init parser_init = command_parsers.add_parser("init") parser_init.add_argument("--upgrade", action="store_true") parser_init.add_argument("site_key", nargs="?") # cmd: create parser_create = command_parsers.add_parser("create") parser_create.add_argument("--kind") parser_create.add_argument("label", nargs=1) # cmd: deploy parser_deploy = command_parsers.add_parser("deploy") parser_deploy.add_argument("--no-on-deploy", action="store_true") parser_deploy.add_argument("label", nargs=1) parser_deploy.add_argument("commit", nargs=1) # cmd: sqldump parser_sqldump = command_parsers.add_parser("sqldump") parser_sqldump.add_argument("label", nargs=1) # cmd: run parser_run = command_parsers.add_parser("run") parser_run.add_argument("--detached", action="store_true", help="run process in detached (output is sent to logs)" ) parser_run.add_argument("instance_label", nargs=1) parser_run.add_argument("command_", nargs=argparse.REMAINDER) # cmd: delete parser_delete = command_parsers.add_parser("delete") parser_delete.add_argument("label", nargs=1) # cmd: list parser_list = command_parsers.add_parser("list") # cmd: manage # example: gondor manage primary database:reset # example: gondor manage dev database:copy primary parser_manage = command_parsers.add_parser("manage") parser_manage.add_argument("label", nargs=1) parser_manage.add_argument("operation", nargs=1) parser_manage.add_argument("--yes", action="store_true", help="automatically answer yes to prompts" ) parser_manage.add_argument("opargs", nargs="*") # cmd: open # example: gondor open primary parser_open = command_parsers.add_parser("open") parser_open.add_argument("label", nargs=1) # cmd: dashboard # example: gondor dashboard primary parser_dashboard = command_parsers.add_parser("dashboard") parser_dashboard.add_argument("label", nargs="?") # cmd: env # example: gondor env / gondor env primary / gondor env KEY / gondor env primary KEY parser_env = command_parsers.add_parser("env") parser_env.add_argument("--scoped", action="store_true") parser_env.add_argument("bits", nargs="*") # cmd: env:set # example: gondor env:set KEY=value / gondor env primary KEY=value parser_env_set = command_parsers.add_parser("env:set") parser_env_set.add_argument("bits", nargs="*") args = parser.parse_args() # config / env global_config = load_config(args, "global") config = { "auth.username": global_config.get("auth", {}).get("username"), "auth.key": global_config.get("auth", {}).get("key"), } env = {} if args.command in ["sqldump"]: out = err else: out = globals()["out"] if args.command != "init": config_file = "gondor.yml" try: env["project_root"] = utils.find_nearest(os.getcwd(), config_file) except OSError: error("unable to find %s configuration file.\n" % config_file) if args.verbose > 1: out("Reading configuration... ") local_config = load_config(args, "local") if args.verbose > 1: out("[ok]\n") config.update({ "auth.username": local_config.get("auth", {}).get("username", config["auth.username"]), "auth.key": local_config.get("auth", {}).get("key", config["auth.key"]), "gondor.site_key": local_config.get("key"), "gondor.endpoint": local_config.get("endpoint", DEFAULT_ENDPOINT), "gondor.vcs": local_config.get("vcs"), "app": { "requirements_file": local_config.get("requirements_file"), "framework": local_config.get("framework"), "on_deploy": local_config.get("on_deploy", []), "static_urls": list(itertools.chain(*[ [(u, c) for u, c in su.iteritems()] for su in local_config.get("static_urls", []) ])), "wsgi_entry_point": local_config.get("wsgi", {}).get("entry_point"), "gunicorn_worker_class": local_config.get("wsgi", {}).get("gunicorn", {}).get("worker_class"), "settings_module": local_config.get("django", {}).get("settings_module"), "managepy": local_config.get("django", {}).get("managepy"), "local_settings": local_config.get("django", {}).get("local_settings"), "env": local_config.get("env", {}), } }) # allow some values to be overriden from os.environ config["auth.username"] = os.environ.get("GONDOR_AUTH_USERNAME", config["auth.username"]) config["auth.key"] = os.environ.get("GONDOR_AUTH_KEY", config["auth.key"]) config["gondor.site_key"] = os.environ.get("GONDOR_SITE_KEY", config["gondor.site_key"]) try: vcs_dir = {"git": ".git", "hg": ".hg"}[config["gondor.vcs"]] except KeyError: error("'%s' is not a valid version control system for Gondor\n" % config["gondor.vcs"]) try: env["repo_root"] = utils.find_nearest(os.getcwd(), vcs_dir) except OSError: error("unable to find a %s directory.\n" % vcs_dir) if config["auth.username"] is None or config["auth.key"] is None: error( "you must provide a username and API key in %s or set it in " "the environment.\n" % os.path.expanduser("~/.gondor") ) if config["gondor.site_key"] is None: error("no site key found in configuration or environment.\n") { "init": cmd_init, "create": cmd_create, "deploy": cmd_deploy, "sqldump": cmd_sqldump, "run": cmd_run, "delete": cmd_delete, "list": cmd_list, "manage": cmd_manage, "open": cmd_open, "dashboard": cmd_dashboard, "env": cmd_env, "env:set": cmd_env_set, }[args.command](args, env, config) return 0
def cmd_manage(args, config): instance_label = args.label[0] operation = args.operation[0] opargs = args.opargs gondor_dirname = ".gondor" try: project_root = utils.find_nearest(os.getcwd(), gondor_dirname) except OSError: error("unable to find a .gondor directory.\n") out("Reading configuration... ") local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(project_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") out("[ok]\n") url = "%s/manage/" % endpoint params = { "version": __version__, "site_key": site_key, "instance_label": instance_label, "operation": operation, } handlers = [ http.MultipartPostHandler, ] if not sys.stdin.isatty(): params["stdin"] = sys.stdin pb = ProgressBar(0, 100, 77) out("Pushing stdin to Gondor... \n") handlers.extend([ http.UploadProgressHandler(pb, ssl=True), http.UploadProgressHandler(pb, ssl=False) ]) params = params.items() for oparg in opargs: params.append(("arg", oparg)) response = make_api_call(config, url, params, extra_handlers=handlers) if not sys.stdin.isatty(): out("\n") out("Running... ") data = json.loads(response.read()) if data["status"] == "error": out("[error]\n") error("%s\n" % data["message"]) if data["status"] == "success": task_id = data["task"] while True: params = { "version": __version__, "site_key": site_key, "instance_label": instance_label, "task_id": task_id, } url = "%s/task_status/" % endpoint response = make_api_call(config, url, urllib.urlencode(params)) data = json.loads(response.read()) if data["status"] == "error": out("[error]\n") out("\nError: %s\n" % data["message"]) if data["status"] == "success": if data["state"] == "finished": out("[ok]\n") break elif data["state"] == "failed": out("[failed]\n") out("\n%s\n" % data["reason"]) sys.exit(1) elif data["state"] == "locked": out("[locked]\n") out("\nYour task failed due to being locked. This means there is another task already in progress.\n") sys.exit(1) else: time.sleep(2)
def cmd_deploy(args, config): label = args.label[0] commit = args.commit[0] gondor_dirname = ".gondor" try: project_root = utils.find_nearest(os.getcwd(), gondor_dirname) except OSError: error("unable to find a .gondor directory.\n") tarball = None try: out("Reading configuration... ") local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(project_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") vcs = local_config.get("gondor", "vcs") app_config = { "requirements_file": config_value(local_config, "app", "requirements_file"), "wsgi_entry_point": config_value(local_config, "app", "wsgi_entry_point"), "migrations": config_value(local_config, "app", "migrations"), } out("[ok]\n") if vcs == "git": try: repo_root = utils.find_nearest(os.getcwd(), ".git") except OSError: error("unable to find a .git directory.\n") sha = utils.check_output("git rev-parse %s" % commit).strip() if commit == "HEAD": commit = sha tarball = os.path.abspath(os.path.join(repo_root, "%s-%s.tar" % (label, sha))) git_archive_all.archive_git(tarball,'tar',repo_root) cmd = "(cd %s && gzip %s)" % (repo_root, tarball) tarball += '.gz' elif vcs == "hg": try: repo_root = utils.find_nearest(os.getcwd(), ".hg") except OSError: error("unable to find a .hg directory.\n") branches_stdout = utils.check_output("hg branches") tags_stdout = utils.check_output("hg tags") refs = {} for line in branches_stdout.splitlines() + tags_stdout.splitlines(): m = re.search(r"([\w\d\.-]+)\s*([\d]+):([\w]+)$", line) if m: refs[m.group(1)] = m.group(3) try: sha = refs[commit] except KeyError: error("could not map '%s' to a SHA\n" % commit) tarball = os.path.abspath(os.path.join(repo_root, "%s-%s.tar.gz" % (label, sha))) cmd = "(cd %s && hg archive -p . -t tgz -r %s %s)" % (repo_root, commit, tarball) else: error("'%s' is not a valid version control system for Gondor\n" % vcs) out("Building tarball from %s... " % commit) subprocess.call([cmd], shell=True) out("[ok]\n") pb = ProgressBar(0, 100, 77) out("Pushing tarball to Gondor... \n") url = "%s/deploy/" % endpoint params = { "version": __version__, "site_key": site_key, "label": label, "sha": sha, "commit": commit, "tarball": open(tarball, "rb"), "project_root": os.path.relpath(project_root, repo_root), "app": json.dumps(app_config), } handlers = [ http.MultipartPostHandler, http.UploadProgressHandler(pb, ssl=True), http.UploadProgressHandler(pb, ssl=False) ] try: response = make_api_call(config, url, params, extra_handlers=handlers) except KeyboardInterrupt: out("\nCanceling uploading... [ok]\n") sys.exit(1) else: out("\n") data = json.loads(response.read()) finally: if tarball: os.unlink(tarball) if data["status"] == "error": error("%s\n" % data["message"]) if data["status"] == "success": deployment_id = data["deployment"] if "url" in data: instance_url = data["url"] else: instance_url = None # poll status of the deployment out("Deploying... ") while True: params = { "version": __version__, "site_key": site_key, "instance_label": label, "task_id": deployment_id, } url = "%s/task_status/" % endpoint try: response = make_api_call(config, url, urllib.urlencode(params)) except urllib2.URLError: # @@@ add max retries continue data = json.loads(response.read()) if data["status"] == "error": out("[error]\n") error("%s\n" % data["message"]) if data["status"] == "success": if data["state"] == "deployed": out("[ok]\n") if instance_url: out("\nVisit: %s\n" % instance_url) break elif data["state"] == "failed": out("[failed]\n") out("\n%s\n" % data["reason"]) sys.exit(1) elif data["state"] == "locked": out("[locked]\n") out("\nYour deployment failed due to being locked. This means there is another deployment already in progress.\n") sys.exit(1) else: time.sleep(2)
def cmd_sqldump(args, config): label = args.label[0] gondor_dirname = ".gondor" repo_root = utils.find_nearest(os.getcwd(), gondor_dirname) local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(repo_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") # request SQL dump and stream the response through uncompression err("Dumping database... ") url = "%s/sqldump/" % endpoint params = { "version": __version__, "site_key": site_key, "label": label, } response = make_api_call(config, url, urllib.urlencode(params)) data = json.loads(response.read()) if data["status"] == "error": error("%s\n" % data["message"]) if data["status"] == "success": task_id = data["task"] while True: params = { "version": __version__, "site_key": site_key, "instance_label": label, "task_id": task_id, } url = "%s/task_status/" % endpoint try: response = make_api_call(config, url, urllib.urlencode(params)) except urllib2.URLError: # @@@ add max retries continue data = json.loads(response.read()) if data["status"] == "error": err("[error]\n") error("%s\n" % data["message"]) if data["status"] == "success": if data["state"] == "finished": err("[ok]\n") break elif data["state"] == "failed": err("[failed]\n") err("\n%s\n" % data["reason"]) sys.exit(1) elif data["state"] == "locked": err("[locked]\n") err("\nYour database dump failed due to being locked. " "This means there is another database dump already " "in progress.\n") sys.exit(1) else: time.sleep(2) d = zlib.decompressobj(16+zlib.MAX_WBITS) cs = 16 * 1024 response = urllib2.urlopen(data["result"]["public_url"]) while True: chunk = response.read(cs) if not chunk: break out(d.decompress(chunk))
def main(): parser = argparse.ArgumentParser(prog="gondor") parser.add_argument("--version", action="version", version="%%(prog)s %s" % __version__) parser.add_argument("--verbose", "-v", action="count", default=1) command_parsers = parser.add_subparsers(dest="command") # cmd: init parser_init = command_parsers.add_parser("init") parser_init.add_argument("site_key", nargs=1) # cmd: create parser_create = command_parsers.add_parser("create") parser_create.add_argument("--kind") parser_create.add_argument("label", nargs=1) # cmd: deploy parser_deploy = command_parsers.add_parser("deploy") parser_deploy.add_argument("label", nargs=1) parser_deploy.add_argument("commit", nargs=1) # cmd: sqldump parser_sqldump = command_parsers.add_parser("sqldump") parser_sqldump.add_argument("label", nargs=1) # cmd: run parser_run = command_parsers.add_parser("run") parser_run.add_argument("instance_label", nargs=1) parser_run.add_argument("command_", nargs=1) parser_run.add_argument("cmdargs", nargs=argparse.REMAINDER) # cmd: delete parser_delete = command_parsers.add_parser("delete") parser_delete.add_argument("label", nargs=1) # cmd: list parser_list = command_parsers.add_parser("list") # cmd: manage # example: gondor manage primary database:reset # example: gondor manage dev database:copy primary parser_manage = command_parsers.add_parser("manage") parser_manage.add_argument("label", nargs=1) parser_manage.add_argument("operation", nargs=1) parser_manage.add_argument("--yes", action="store_true", help="automatically answer yes to prompts" ) parser_manage.add_argument("opargs", nargs="*") # cmd: open # example: gondor open primary parser_open = command_parsers.add_parser("open") parser_open.add_argument("label", nargs=1) # cmd: dashboard # example: gondor dashboard primary parser_dashboard = command_parsers.add_parser("dashboard") parser_dashboard.add_argument("label", nargs="?") # cmd: env # example: gondor env / gondor env primary / gondor env KEY / gondor env primary KEY parser_env = command_parsers.add_parser("env") parser_env.add_argument("--scoped", action="store_true") parser_env.add_argument("bits", nargs="*") # cmd: env:set # example: gondor env:set KEY=value / gondor env primary KEY=value parser_env_set = command_parsers.add_parser("env:set") parser_env_set.add_argument("bits", nargs="*") args = parser.parse_args() # config / env global_config = ConfigParser.RawConfigParser() global_config.read(os.path.expanduser("~/.gondor")) config = { "auth.username": config_value(global_config, "auth", "username"), "auth.password": config_value(global_config, "auth", "password"), "auth.key": config_value(global_config, "auth", "key"), } env = {} if args.command in ["sqldump"]: out = err else: out = globals()["out"] if args.command != "init": gondor_dirname = ".gondor" try: env["project_root"] = utils.find_nearest(os.getcwd(), gondor_dirname) except OSError: error("unable to find a .gondor directory.\n") if args.verbose > 1: out("Reading configuration... ") def parse_config(name): local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(env["project_root"], gondor_dirname, name)) return local_config local_config = parse_config("config") if args.verbose > 1: out("[ok]\n") config.update({ "auth.username": config_value(local_config, "auth", "username", config["auth.username"]), "auth.password": config_value(local_config, "auth", "password", config["auth.password"]), "auth.key": config_value(local_config, "auth", "key", config["auth.key"]), "gondor.site_key": config_value(local_config, "gondor", "site_key", False), "gondor.endpoint": config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT), "gondor.vcs": local_config.get("gondor", "vcs"), "app": { "requirements_file": config_value(local_config, "app", "requirements_file"), "wsgi_entry_point": config_value(local_config, "app", "wsgi_entry_point"), "migrations": config_value(local_config, "app", "migrations"), "staticfiles": config_value(local_config, "app", "staticfiles"), "compressor": config_value(local_config, "app", "compressor"), "site_media_url": config_value(local_config, "app", "site_media_url"), "settings_module": config_value(local_config, "app", "settings_module"), "managepy": config_value(local_config, "app", "managepy"), "local_settings": config_value(local_config, "app", "local_settings"), } }) if not config["gondor.site_key"]: if args.verbose > 1: out("Loading separate site_key... ") try: site_key_config = parse_config("site_key") config["gondor.site_key"] = site_key_config.get("gondor", "site_key") except ConfigParser.NoSectionError: if args.verbose > 1: out("[failed]\n") error("Unable to read gondor.site_key from .gondor/config or .gondor/site_key\n"); if args.verbose > 1: out("[ok]\n") try: vcs_dir = {"git": ".git", "hg": ".hg"}[config["gondor.vcs"]] except KeyError: error("'%s' is not a valid version control system for Gondor\n" % config["gondor.vcs"]) try: env["repo_root"] = utils.find_nearest(os.getcwd(), vcs_dir) except OSError: error("unable to find a %s directory.\n" % vcs_dir) if (config["auth.username"] is None and (config["auth.password"] is None or config["auth.key"] is None)): message = "you must set your credentials in %s" % os.path.expanduser("~/.gondor") if "project_root" in env: message += " or %s" % os.path.join(env["project_root"], ".gondor", "config") message += "\n" error(message) { "init": cmd_init, "create": cmd_create, "deploy": cmd_deploy, "sqldump": cmd_sqldump, "run": cmd_run, "delete": cmd_delete, "list": cmd_list, "manage": cmd_manage, "open": cmd_open, "dashboard": cmd_dashboard, "env": cmd_env, "env:set": cmd_env_set, }[args.command](args, env, config)
def main(): parser = argparse.ArgumentParser(prog="gondor") parser.add_argument("--version", action="version", version="%%(prog)s %s" % __version__) command_parsers = parser.add_subparsers(dest="command") # cmd: init parser_init = command_parsers.add_parser("init") parser_init.add_argument("site_key", nargs=1) # cmd: create parser_create = command_parsers.add_parser("create") parser_create.add_argument("--kind") parser_create.add_argument("label", nargs=1) # cmd: deploy parser_deploy = command_parsers.add_parser("deploy") parser_deploy.add_argument("label", nargs=1) parser_deploy.add_argument("commit", nargs=1) # cmd: sqldump parser_sqldump = command_parsers.add_parser("sqldump") parser_sqldump.add_argument("label", nargs=1) # cmd: run parser_run = command_parsers.add_parser("run") parser_run.add_argument("instance_label", nargs=1) parser_run.add_argument("command_", nargs=1) parser_run.add_argument("cmdargs", nargs="*") # cmd: delete parser_delete = command_parsers.add_parser("delete") parser_delete.add_argument("label", nargs=1) # cmd: list parser_list = command_parsers.add_parser("list") # cmd: manage # example: gondor manage primary database:reset # example: gondor manage dev database:copy primary parser_manage = command_parsers.add_parser("manage") parser_manage.add_argument("label", nargs=1) parser_manage.add_argument("operation", nargs=1) parser_manage.add_argument("opargs", nargs="*") args = parser.parse_args() # config / env global_config = ConfigParser.RawConfigParser() global_config.read(os.path.expanduser("~/.gondor")) config = { "auth.username": config_value(global_config, "auth", "username"), "auth.password": config_value(global_config, "auth", "password"), "auth.key": config_value(global_config, "auth", "key"), } env = {} if args.command != "init": gondor_dirname = ".gondor" try: env["project_root"] = utils.find_nearest(os.getcwd(), gondor_dirname) except OSError: error("unable to find a .gondor directory.\n") out("Reading configuration... ") local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(env["project_root"], gondor_dirname, "config")) out("[ok]\n") config.update({ "auth.username": config_value(local_config, "auth", "username", config["auth.username"]), "auth.password": config_value(local_config, "auth", "password", config["auth.password"]), "auth.key": config_value(local_config, "auth", "key", config["auth.key"]), "gondor.site_key": local_config.get("gondor", "site_key"), "gondor.endpoint": config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT), "gondor.vcs": local_config.get("gondor", "vcs"), "app": { "requirements_file": config_value(local_config, "app", "requirements_file"), "wsgi_entry_point": config_value(local_config, "app", "wsgi_entry_point"), "migrations": config_value(local_config, "app", "migrations"), "staticfiles": config_value(local_config, "app", "staticfiles"), "site_media_url": config_value(local_config, "app", "site_media_url"), }, "files.include": [ x.strip() for x in config_value(local_config, "files", "include", "").split("\n") if x ] }) try: vcs_dir = {"git": ".git", "hg": ".hg"}[config["gondor.vcs"]] except KeyError: error("'%s' is not a valid version control system for Gondor\n" % config["gondor.vcs"]) try: env["repo_root"] = utils.find_nearest(os.getcwd(), vcs_dir) except OSError: error("unable to find a %s directory.\n" % vcs_dir) if (config["auth.username"] is None and (config["auth.password"] is None or config["auth.key"] is None)): message = "you must set your credentials in %s" % os.path.expanduser("~/.gondor") if "project_root" in env: message += " or %s" % os.path.join(env["project_root"], ".gondor", "config") message += "\n" error(message) { "init": cmd_init, "create": cmd_create, "deploy": cmd_deploy, "sqldump": cmd_sqldump, "run": cmd_run, "delete": cmd_delete, "list": cmd_list, "manage": cmd_manage, }[args.command](args, env, config)
def cmd_init(args, config): site_key = args.site_key[0] if len(site_key) < 11: error("The site key given is too short.\n") # ensure os.getcwd() is a Django directory files = [ os.path.join(os.getcwd(), "__init__.py"), os.path.join(os.getcwd(), "manage.py") ] if not all([os.path.exists(f) for f in files]): error("must run gondor init from a Django project directory.\n") gondor_dir = os.path.abspath(os.path.join(os.getcwd(), ".gondor")) try: repo_root = utils.find_nearest(os.getcwd(), ".git") except OSError: try: repo_root = utils.find_nearest(os.getcwd(), ".hg") except OSError: error("unable to find a supported version control directory. Looked for .git and .hg.\n") else: vcs = "hg" else: vcs = "git" if not os.path.exists(gondor_dir): if repo_root == os.getcwd(): out("WARNING: we've detected your repo root (directory containing .%s) is the same\n" % vcs) out("directory as your project root. This is certainly allowed, but many of our\n") out("users have problems with this setup because the parent directory is *not* the\n") out("same on Gondor as it is locally. See https://gondor.io/support/project-layout/\n") out("for more information on the suggested layout.\n\n") os.mkdir(gondor_dir) config_file = """[gondor] site_key = %(site_key)s vcs = %(vcs)s [app] ; this path is relative to your project root (the directory .gondor is in) requirements_file = requirements/project.txt ; this is a Python path and the default value maps to deploy/wsgi.py on disk wsgi_entry_point = deploy.wsgi ; can be either nashvegas, south or none migrations = none ; whether or not to run collectstatic (or build_static if collectstatic is not ; available) staticfiles = off """ % { "site_key": site_key, "vcs": vcs } out("Writing configuration (.gondor/config)... ") with open(os.path.join(gondor_dir, "config"), "wb") as cf: cf.write(config_file) out("[ok]\n") out("\nYou are now ready to deploy your project to Gondor. You might want to first\n") out("check .gondor/config (in this directory) for correct values for your\n") out("application. Once you are ready, run:\n\n") out(" gondor deploy primary %s\n" % {"git": "master", "hg": "default"}[vcs]) else: out("Detecting existing .gondor/config. Not overriding.\n")
def cmd_manage(args, config): instance_label = args.label[0] operation = args.operation[0] opargs = args.opargs gondor_dirname = ".gondor" try: project_root = utils.find_nearest(os.getcwd(), gondor_dirname) except OSError: error("unable to find a .gondor directory.\n") out("Reading configuration... ") local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(project_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") out("[ok]\n") url = "%s/manage/" % endpoint params = { "version": __version__, "site_key": site_key, "instance_label": instance_label, "operation": operation, } handlers = [ http.MultipartPostHandler, ] if not sys.stdin.isatty(): params["stdin"] = sys.stdin pb = ProgressBar(0, 100, 77) out("Pushing stdin to Gondor... \n") handlers.extend([ http.UploadProgressHandler(pb, ssl=True), http.UploadProgressHandler(pb, ssl=False) ]) params = params.items() for oparg in opargs: params.append(("arg", oparg)) response = make_api_call(config, url, params, extra_handlers=handlers) if not sys.stdin.isatty(): out("\n") out("Running... ") data = json.loads(response.read()) if data["status"] == "error": out("[error]\n") error("%s\n" % data["message"]) if data["status"] == "success": task_id = data["task"] while True: params = { "version": __version__, "site_key": site_key, "instance_label": instance_label, "task_id": task_id, } url = "%s/task_status/" % endpoint response = make_api_call(config, url, urllib.urlencode(params)) data = json.loads(response.read()) if data["status"] == "error": out("[error]\n") out("\nError: %s\n" % data["message"]) if data["status"] == "success": if data["state"] == "finished": out("[ok]\n") break elif data["state"] == "failed": out("[failed]\n") out("\n%s\n" % data["reason"]) sys.exit(1) elif data["state"] == "locked": out("[locked]\n") out("\nYour task failed due to being locked. This means there is another task already in progress.\n" ) sys.exit(1) else: time.sleep(2)
def cmd_sqldump(args, config): label = args.label[0] gondor_dirname = ".gondor" repo_root = utils.find_nearest(os.getcwd(), gondor_dirname) local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(repo_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") # request SQL dump and stream the response through uncompression err("Dumping database... ") url = "%s/sqldump/" % endpoint params = { "version": __version__, "site_key": site_key, "label": label, } response = make_api_call(config, url, urllib.urlencode(params)) data = json.loads(response.read()) if data["status"] == "error": error("%s\n" % data["message"]) if data["status"] == "success": task_id = data["task"] while True: params = { "version": __version__, "site_key": site_key, "instance_label": label, "task_id": task_id, } url = "%s/task_status/" % endpoint try: response = make_api_call(config, url, urllib.urlencode(params)) except urllib2.URLError: # @@@ add max retries continue data = json.loads(response.read()) if data["status"] == "error": err("[error]\n") error("%s\n" % data["message"]) if data["status"] == "success": if data["state"] == "finished": err("[ok]\n") break elif data["state"] == "failed": err("[failed]\n") err("\n%s\n" % data["reason"]) sys.exit(1) elif data["state"] == "locked": err("[locked]\n") err("\nYour database dump failed due to being locked. " "This means there is another database dump already " "in progress.\n") sys.exit(1) else: time.sleep(2) d = zlib.decompressobj(16 + zlib.MAX_WBITS) cs = 16 * 1024 response = urllib2.urlopen(data["result"]["public_url"]) while True: chunk = response.read(cs) if not chunk: break out(d.decompress(chunk))
def cmd_init(args, env, config): config_file = "gondor.yml" ctx = dict(config_file=config_file) if args.upgrade: gondor_dir = utils.find_nearest(os.getcwd(), ".gondor") legacy_config = ConfigParser.RawConfigParser() legacy_config.read(os.path.abspath(os.path.join(gondor_dir, ".gondor", "config"))) ctx.update({ "site_key": config_value(legacy_config, "gondor", "site_key"), "vcs": config_value(legacy_config, "gondor", "vcs"), "requirements_file": config_value(legacy_config, "app", "requirements_file"), "wsgi_entry_point": config_value(legacy_config, "app", "wsgi_entry_point"), "framework": "django", "gunicorn_worker_class": "eventlet", }) on_deploy, static_urls = [], [] migrations = config_value(legacy_config, "app", "migrations") if migrations: migrations = migrations.strip().lower() if migrations == "none": on_deploy.append(" - manage.py syncdb --noinput") if migrations == "nashvegas": on_deploy.append(" - manage.py upgradedb --execute") if migrations == "south": on_deploy.append(" - manage.py syncdb --noinput") on_deploy.append(" - manage.py migrate --noinput") staticfiles = config_value(legacy_config, "app", "staticfiles") if staticfiles: staticfiles = staticfiles.strip().lower() if staticfiles == "on": on_deploy.append(" - manage.py collectstatic --noinput") compressor = config_value(legacy_config, "app", "compressor") if compressor: compressor = compressor.strip().lower() if compressor == "on": on_deploy.append(" - manage.py compress") site_media_url = config_value(legacy_config, "app", "site_media_url") managepy = config_value(legacy_config, "app", "managepy") if not managepy: managepy = "manage.py" if site_media_url: static_urls.extend([" - %s:" % site_media_url, " root: site_media/"]) extra_config_file_data = """ django: # The location of your manage.py. Gondor uses this as an entry point for # management commands. This path is relative to your project root (the # directory %(config_file)s lives in.) managepy: %(managepy)s """ % { "managepy": managepy, "config_file": config_file, } else: site_key = args.site_key if len(site_key) < 11: error("The site key given is too short.\n") ctx["wsgi_entry_point"] = "wsgi:application" ctx["requirements_file"] = "requirements.txt" on_deploy = [] static_urls = [" - /site_media:", " root: site_media/"] try: utils.find_nearest(os.getcwd(), ".git") except OSError: try: utils.find_nearest(os.getcwd(), ".hg") except OSError: error("unable to find a supported version control directory. Looked for .git and .hg.\n") else: vcs = "hg" else: vcs = "git" extra_config_file_data = "" ctx.update({ "site_key": site_key, "vcs": vcs, "framework": "wsgi", "requirements_file": "requirements.txt", "wsgi_entry_point": "wsgi:application", "gunicorn_worker_class": "sync", }) if not on_deploy: ctx["on_deploy"] = "# on_deploy:\n# - manage.py syncdb --noinput\n# - manage.py collectstatic --noinput" else: ctx["on_deploy"] = "\n".join(["on_deploy:"] + on_deploy) ctx["static_urls"] = "\n".join(["static_urls:"] + static_urls) if not os.path.exists(config_file): config_file_data = """# The key associated to your site. key: %(site_key)s # Version control system used locally for your project. vcs: %(vcs)s # Framework to use on Gondor. framework: %(framework)s # This path is relative to your project root (the directory %(config_file)s lives in.) requirements_file: %(requirements_file)s # Commands to be executed during deployment. These can handle migrations or # moving static files into place. Accepts same parameters as gondor run. %(on_deploy)s # URLs which should be served by Gondor mapping to a filesystem location # relative to your writable storage area. %(static_urls)s wsgi: # The WSGI entry point of your application in two parts separated by a # colon. Example: # # wsgi:application # # wsgi = the Python module which should be importable # application = the callable in the Python module entry_point: %(wsgi_entry_point)s # Options for gunicorn which runs your WSGI project. gunicorn: # The worker class used to run gunicorn (possible values include: # sync, eventlet and gevent) worker_class: %(gunicorn_worker_class)s """ % ctx out("Writing configuration (%s)... " % config_file) with open(config_file, "wb") as cf: cf.write(config_file_data + extra_config_file_data) out("[ok]\n") if args.upgrade: out("\nYour configuration file has been upgraded. New configuration is located\n") out("in %s. Make sure you check this file before continuing then add and\n" % config_file) out("commit it to your VCS.\n") else: out("\nYou are now ready to deploy your project to Gondor. You might want to first\n") out("check %s (in this directory) for correct values for your\n" % config_file) out("application. Once you are ready, run:\n\n") out(" gondor deploy primary %s\n" % {"git": "master", "hg": "default"}[vcs]) else: out("Detected existing %s. Not overriding.\n" % config_file)
def cmd_deploy(args, config): label = args.label[0] commit = args.commit[0] gondor_dirname = ".gondor" try: project_root = utils.find_nearest(os.getcwd(), gondor_dirname) except OSError: error("unable to find a .gondor directory.\n") tarball = None try: out("Reading configuration... ") local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(project_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") vcs = local_config.get("gondor", "vcs") app_config = { "requirements_file": config_value(local_config, "app", "requirements_file"), "wsgi_entry_point": config_value(local_config, "app", "wsgi_entry_point"), "migrations": config_value(local_config, "app", "migrations"), } out("[ok]\n") if vcs == "git": try: repo_root = utils.find_nearest(os.getcwd(), ".git") except OSError: error("unable to find a .git directory.\n") sha = utils.check_output("git rev-parse %s" % commit).strip() if commit == "HEAD": commit = sha tarball = os.path.abspath( os.path.join(repo_root, "%s-%s.tar" % (label, sha))) git_archive_all.archive_git(tarball, 'tar', repo_root) cmd = "(cd %s && gzip %s)" % (repo_root, tarball) tarball += '.gz' elif vcs == "hg": try: repo_root = utils.find_nearest(os.getcwd(), ".hg") except OSError: error("unable to find a .hg directory.\n") branches_stdout = utils.check_output("hg branches") tags_stdout = utils.check_output("hg tags") refs = {} for line in branches_stdout.splitlines() + tags_stdout.splitlines( ): m = re.search(r"([\w\d\.-]+)\s*([\d]+):([\w]+)$", line) if m: refs[m.group(1)] = m.group(3) try: sha = refs[commit] except KeyError: error("could not map '%s' to a SHA\n" % commit) tarball = os.path.abspath( os.path.join(repo_root, "%s-%s.tar.gz" % (label, sha))) cmd = "(cd %s && hg archive -p . -t tgz -r %s %s)" % ( repo_root, commit, tarball) else: error("'%s' is not a valid version control system for Gondor\n" % vcs) out("Building tarball from %s... " % commit) subprocess.call([cmd], shell=True) out("[ok]\n") pb = ProgressBar(0, 100, 77) out("Pushing tarball to Gondor... \n") url = "%s/deploy/" % endpoint params = { "version": __version__, "site_key": site_key, "label": label, "sha": sha, "commit": commit, "tarball": open(tarball, "rb"), "project_root": os.path.relpath(project_root, repo_root), "app": json.dumps(app_config), } handlers = [ http.MultipartPostHandler, http.UploadProgressHandler(pb, ssl=True), http.UploadProgressHandler(pb, ssl=False) ] try: response = make_api_call(config, url, params, extra_handlers=handlers) except KeyboardInterrupt: out("\nCanceling uploading... [ok]\n") sys.exit(1) else: out("\n") data = json.loads(response.read()) finally: if tarball: os.unlink(tarball) if data["status"] == "error": error("%s\n" % data["message"]) if data["status"] == "success": deployment_id = data["deployment"] if "url" in data: instance_url = data["url"] else: instance_url = None # poll status of the deployment out("Deploying... ") while True: params = { "version": __version__, "site_key": site_key, "instance_label": label, "task_id": deployment_id, } url = "%s/task_status/" % endpoint try: response = make_api_call(config, url, urllib.urlencode(params)) except urllib2.URLError: # @@@ add max retries continue data = json.loads(response.read()) if data["status"] == "error": out("[error]\n") error("%s\n" % data["message"]) if data["status"] == "success": if data["state"] == "deployed": out("[ok]\n") if instance_url: out("\nVisit: %s\n" % instance_url) break elif data["state"] == "failed": out("[failed]\n") out("\n%s\n" % data["reason"]) sys.exit(1) elif data["state"] == "locked": out("[locked]\n") out("\nYour deployment failed due to being locked. This means there is another deployment already in progress.\n" ) sys.exit(1) else: time.sleep(2)
def cmd_run(args, config): instance_label = args.instance_label[0] command = args.command_[0] cmdargs = args.cmdargs params = {"cmdargs": cmdargs} gondor_dirname = ".gondor" try: project_root = utils.find_nearest(os.getcwd(), gondor_dirname) except OSError: error("unable to find a .gondor directory.\n") out("Reading configuration... ") local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(project_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") vcs = local_config.get("gondor", "vcs") app_config = { "requirements_file": config_value(local_config, "app", "requirements_file"), "wsgi_entry_point": config_value(local_config, "app", "wsgi_entry_point"), "migrations": config_value(local_config, "app", "migrations"), "staticfiles": config_value(local_config, "app", "staticfiles"), } out("[ok]\n") if vcs == "git": try: repo_root = utils.find_nearest(os.getcwd(), ".git") except OSError: error("unable to find a .git directory.\n") elif vcs == "hg": try: repo_root = utils.find_nearest(os.getcwd(), ".hg") except OSError: error("unable to find a .hg directory.\n") else: error("'%s' is not a valid version control system for Gondor\n" % vcs) if command == "createsuperuser": try: # Get a username while 1: username = raw_input("Username: "******"Error: That username is invalid. Use only letters, digits and underscores.\n") username = None continue break # Get an email while 1: email = raw_input("Email address: ") if not EMAIL_RE.search(email): sys.stderr.write("Error: That email address is invalid.\n") email = None else: break # Get a password while 1: password = getpass.getpass() password2 = getpass.getpass("Password (again): ") if password != password2: sys.stderr.write("Error: Your passwords didn't match.\n") password = None continue if password.strip() == "": sys.stderr.write("Error: Blank passwords aren't allowed.\n") password = None continue break except KeyboardInterrupt: sys.stderr.write("\nOperation cancelled.\n") sys.exit(1) params = { "username": username, "email": email, "password": password, } out("Executing... ") url = "%s/run/" % endpoint params = { "version": __version__, "site_key": site_key, "instance_label": instance_label, "project_root": os.path.relpath(project_root, repo_root), "command": command, "params": json.dumps(params), "app": json.dumps(app_config), } try: response = make_api_call(config, url, urllib.urlencode(params)) except urllib2.HTTPError, e: out("\nReceived an error [%d: %s]" % (e.code, e.read())) sys.exit(1)
def cmd_run(args, config): instance_label = args.instance_label[0] command = args.command_[0] cmdargs = args.cmdargs params = {"cmdargs": cmdargs} gondor_dirname = ".gondor" try: project_root = utils.find_nearest(os.getcwd(), gondor_dirname) except OSError: error("unable to find a .gondor directory.\n") out("Reading configuration... ") local_config = ConfigParser.RawConfigParser() local_config.read(os.path.join(project_root, gondor_dirname, "config")) endpoint = config_value(local_config, "gondor", "endpoint", DEFAULT_ENDPOINT) site_key = local_config.get("gondor", "site_key") vcs = local_config.get("gondor", "vcs") app_config = { "requirements_file": config_value(local_config, "app", "requirements_file"), "wsgi_entry_point": config_value(local_config, "app", "wsgi_entry_point"), "migrations": config_value(local_config, "app", "migrations"), } out("[ok]\n") if vcs == "git": try: repo_root = utils.find_nearest(os.getcwd(), ".git") except OSError: error("unable to find a .git directory.\n") elif vcs == "hg": try: repo_root = utils.find_nearest(os.getcwd(), ".hg") except OSError: error("unable to find a .hg directory.\n") else: error("'%s' is not a valid version control system for Gondor\n" % vcs) if command == "createsuperuser": try: # Get a username while 1: username = raw_input("Username: "******"Error: That username is invalid. Use only letters, digits and underscores.\n" ) username = None continue break # Get an email while 1: email = raw_input("Email address: ") if not EMAIL_RE.search(email): sys.stderr.write("Error: That email address is invalid.\n") email = None else: break # Get a password while 1: password = getpass.getpass() password2 = getpass.getpass("Password (again): ") if password != password2: sys.stderr.write("Error: Your passwords didn't match.\n") password = None continue if password.strip() == "": sys.stderr.write( "Error: Blank passwords aren't allowed.\n") password = None continue break except KeyboardInterrupt: sys.stderr.write("\nOperation cancelled.\n") sys.exit(1) params = { "username": username, "email": email, "password": password, } out("Executing... ") url = "%s/run/" % endpoint params = { "version": __version__, "site_key": site_key, "instance_label": instance_label, "project_root": os.path.relpath(project_root, repo_root), "command": command, "params": json.dumps(params), "app": json.dumps(app_config), } response = make_api_call(config, url, urllib.urlencode(params)) data = json.loads(response.read()) if data["status"] == "error": out("[error]\n") error("%s\n" % data["message"]) if data["status"] == "success": task_id = data["task"] while True: params = { "version": __version__, "site_key": site_key, "instance_label": instance_label, "task_id": task_id, } url = "%s/task_status/" % endpoint response = make_api_call(config, url, urllib.urlencode(params)) data = json.loads(response.read()) if data["status"] == "error": out("[error]\n") out("\nError: %s\n" % data["message"]) if data["status"] == "success": if data["state"] == "executed": out("[ok]\n") out("\n%s" % data["result"]["output"]) break elif data["state"] == "failed": out("[failed]\n") out("\n%s\n" % data["reason"]) sys.exit(1) elif data["state"] == "locked": out("[locked]\n") out("\nYour execution failed due to being locked. This means there is another execution already in progress.\n" ) sys.exit(1) else: time.sleep(2)
def cmd_init(args, env, config): site_key = args.site_key[0] if len(site_key) < 11: error("The site key given is too short.\n") # ensure os.getcwd() is a Django directory files = [ os.path.join(os.getcwd(), "__init__.py"), os.path.join(os.getcwd(), "manage.py") ] if not all([os.path.exists(f) for f in files]): error("must run gondor init from a Django project directory.\n") gondor_dir = os.path.abspath(os.path.join(os.getcwd(), ".gondor")) try: repo_root = utils.find_nearest(os.getcwd(), ".git") except OSError: try: repo_root = utils.find_nearest(os.getcwd(), ".hg") except OSError: error("unable to find a supported version control directory. Looked for .git and .hg.\n") else: vcs = "hg" else: vcs = "git" if not os.path.exists(gondor_dir): if repo_root == os.getcwd(): out("WARNING: we've detected your repo root (directory containing .%s) is the same\n" % vcs) out("directory as your project root. This is certainly allowed, but many of our\n") out("users have problems with this setup because the parent directory is *not* the\n") out("same on Gondor as it is locally. See https://gondor.io/support/project-layout/\n") out("for more information on the suggested layout.\n\n") os.mkdir(gondor_dir) config_file = """[gondor] site_key = %(site_key)s vcs = %(vcs)s [app] ; This path is relative to your project root (the directory .gondor is in) requirements_file = requirements.txt ; The wsgi entry point of your application in two parts separated by a colon. ; wsgi:deploy where wsgi is the Python module which should be importable and ; application which represents the callable in the module. wsgi_entry_point = wsgi:application ; Can be either nashvegas, south or none migrations = none ; Whether or not to run collectstatic during deployment staticfiles = off ; Path to map frontend servers to for your site media (includes both STATIC_URL ; and MEDIA_URL; you must ensure they are under the same path) site_media_url = /site_media """ % { "site_key": site_key, "vcs": vcs } out("Writing configuration (.gondor/config)... ") with open(os.path.join(gondor_dir, "config"), "wb") as cf: cf.write(config_file) out("[ok]\n") out("\nYou are now ready to deploy your project to Gondor. You might want to first\n") out("check .gondor/config (in this directory) for correct values for your\n") out("application. Once you are ready, run:\n\n") out(" gondor deploy primary %s\n" % {"git": "master", "hg": "default"}[vcs]) else: out("Detecting existing .gondor/config. Not overriding.\n")
def cmd_init(args, env, config): site_key = args.site_key[0] if len(site_key) < 11: error("The site key given is too short.\n") gondor_dir = os.path.abspath(os.path.join(os.getcwd(), ".gondor")) try: repo_root = utils.find_nearest(os.getcwd(), ".git") except OSError: try: repo_root = utils.find_nearest(os.getcwd(), ".hg") except OSError: error("unable to find a supported version control directory. Looked for .git and .hg.\n") else: vcs = "hg" else: vcs = "git" if not os.path.exists(gondor_dir): os.mkdir(gondor_dir) config_file = """[gondor] site_key = %(site_key)s vcs = %(vcs)s [app] ; This path is relative to your project root (the directory .gondor is in) requirements_file = requirements.txt ; The wsgi entry point of your application in two parts separated by a colon. ; wsgi:deploy where wsgi is the Python module which should be importable and ; application which represents the callable in the module. wsgi_entry_point = wsgi:application ; Can be either nashvegas, south or none migrations = none ; Whether or not to run collectstatic during deployment staticfiles = off ; Whether or not to run compress (from django_compressor) during deployment compressor = off ; Path to map frontend servers to for your site media (includes both STATIC_URL ; and MEDIA_URL; you must ensure they are under the same path) site_media_url = /site_media ; The location of your manage.py. Gondor uses this as an entry point for ; management commands. This is relative to the directory .gondor lives in. ; managepy = manage.py ; Gondor will use settings_module as DJANGO_SETTINGS_MODULE when it runs your ; code. Commented out by default (means it will not be set). ; settings_module = settings """ % { "site_key": site_key, "vcs": vcs } out("Writing configuration (.gondor/config)... ") with open(os.path.join(gondor_dir, "config"), "wb") as cf: cf.write(config_file) out("[ok]\n") out("\nYou are now ready to deploy your project to Gondor. You might want to first\n") out("check .gondor/config (in this directory) for correct values for your\n") out("application. Once you are ready, run:\n\n") out(" gondor deploy primary %s\n" % {"git": "master", "hg": "default"}[vcs]) else: out("Detecting existing .gondor/config. Not overriding.\n")