def _get_svn_user_and_pass(): if not env.has_key('svnuser') or len(env.svnuser) == 0: # prompt user for username prompt('Enter SVN username:'******'svnuser') if not env.has_key('svnpass') or len(env.svnpass) == 0: # prompt user for password env.svnpass = getpass.getpass('Enter SVN password:')
def write_nginx_conf(): ctx = { "allowed_hosts": env.django["allowed_hosts"], "app_root": env.source_root, "media_root": env.django["media_root"], "static_root": env.django["static_root"] } if env.has_key("django_admin_enabled") and env.django_admin_enabled: ctx["django_admin_enabled"] = True ctx["admin_contrib"] = env.django["django_contrib_path"] if exists("/etc/nginx/sites-enabled/default"): sudo("rm -rf /etc/nginx/sites-enabled/default") upload_template(filename="webserver/nginx.template", destination="/etc/nginx/sites-enabled/{0}.conf".format( env.virtualenv_name), use_jinja=True, template_dir=env.deploy_templates_path, use_sudo=True, context=ctx, backup=False)
def write_local_settings(): """Write a local_settings file to our settings folder.""" if not env.has_key("deploy_templates_path"): print "Its not possible to writeoff localsettings because we can't locate our deploy templates" return ctx = { "databases": env.databases, "debug": str(env.django["debug"]), "template_debug": str(env.django["template_debug"]), "media_root": env.django["media_root"], "static_root": env.django["static_root"]} if env.django["allowed_hosts"]: ctx["allowed_hosts"] = env.django["allowed_hosts"].split(" ") upload_template(filename="django/local_settings.template", destination=os.path.join(env.django_settings_path, "local_settings.py"), use_jinja=True, template_dir=env.deploy_templates_path, use_sudo=True, context=ctx, backup=False) if not exists(env.django["media_root"]): sudo("mkdir -p {0}".format(env.django["media_root"])) if not exists(env.django["static_root"]): sudo("mkdir -p {0}".format(env.django["static_root"]))
def write_local_settings(): """Write a local_settings file to our settings folder.""" if not env.has_key("deploy_templates_path"): print "Its not possible to writeoff localsettings because we can't locate our deploy templates" return ctx = { "databases": env.databases, "debug": str(env.django["debug"]), "template_debug": str(env.django["template_debug"]), "media_root": env.django["media_root"], "static_root": env.django["static_root"] } if env.django["allowed_hosts"]: ctx["allowed_hosts"] = env.django["allowed_hosts"].split(" ") upload_template(filename="django/local_settings.template", destination=os.path.join(env.django_settings_path, "local_settings.py"), use_jinja=True, template_dir=env.deploy_templates_path, use_sudo=True, context=ctx, backup=False) if not exists(env.django["media_root"]): sudo("mkdir -p {0}".format(env.django["media_root"])) if not exists(env.django["static_root"]): sudo("mkdir -p {0}".format(env.django["static_root"]))
def get_linux_flavor(): """ Obtain and set the env variable linux_flavor """ # Already ran through this method if env.has_key('linux_flavor'): return env.linux_flavor linux_flavor = None # Try lsb_release if check_command('lsb_release'): distributionId = run('lsb_release -i') if distributionId and distributionId.find(':') != -1: linux_flavor = distributionId.split(':')[1].strip() # Try python if not linux_flavor and check_command('python'): lf = run( "python -c 'import platform; print platform.linux_distribution()[0]'" ) if lf: linux_flavor = lf.split()[0] # Try /etc/issue if not linux_flavor and check_path('/etc/issue') == '1': re = run('cat /etc/issue') issue = re.split() if issue: if issue[0] == 'CentOS' or issue[0] == 'Ubuntu' \ or issue[0] == 'Debian': linux_flavor = issue[0] elif issue[0] == 'Amazon': linux_flavor = ' '.join(issue[:2]) elif issue[2] in ('SUSE', 'openSUSE'): linux_flavor = issue[2] # Try uname -s if not linux_flavor: linux_flavor = run('uname -s') # Sanitize if linux_flavor and type(linux_flavor) == type([]): linux_flavor = linux_flavor[0] # Final check if not linux_flavor or linux_flavor not in SUPPORTED_OS: puts('>>>>>>>>>>') puts( 'Target machine is running an unsupported or unkown Linux flavor: {0}.' .format(linux_flavor)) puts('If you know better, please enter it below.') puts('Must be one of:') puts(' '.join(SUPPORTED_OS)) linux_flavor = prompt('LINUX flavor: ') puts(blue("Remote machine running %s" % linux_flavor)) env.linux_flavor = linux_flavor return linux_flavor
def run_tests(): """Run all tests for the project""" with virtualenv(env.virtualenv_path): if env.has_key("deploy_branch"): checkout(env.app_path, env.deploy_branch) with cd(env.source_root): sudo("./manage.py test")
def decorator(*args, **kwargs): if env.has_key('target_env'): execute(func, *args, **kwargs) else: target = kwargs.pop(target_param) config = config_for_target(target) config['target_env'] = target with settings(**config): execute(func, *args, **kwargs)
def output_loop(*args, **kwargs): ol = fabric.io.OutputLooper(*args, **kwargs) if env.has_key('pretty_host_string'): ol.prefix = "[%s] %s: " % ( env.pretty_host_string, "out" if args[1] == 'recv' else "err" ) else: ol.prefix = "[%s] %s: " % ( env.host_string, "out" if args[1] == 'recv' else "err" ) ol.loop()
def delete_old_versions(keep=None): """Delete old rollback directories, keeping the last "keep" (default 5)".""" require('prev_root', provided_by=env.valid_envs) # the -1 argument ensures one directory per line prev_versions = run('ls -1 ' + env.prev_root).split('\n') if keep == None: if env.has_key('versions_to_keep'): keep = env.versions_to_keep else: keep = 5 versions_to_keep = -1 * int(keep) prev_versions_to_delete = prev_versions[:versions_to_keep] for version_to_delete in prev_versions_to_delete: sudo_or_run('rm -rf ' + os.path.join(env.prev_root, version_to_delete.strip()))
def create_revision(): """ Creates a tar.gz of the project to be transfered to the remote host. This method creates a temporary directory to work with a clean clone of the repository. This avoids by accident deploying something not checked in. """ _init() if env.has_key('archive'): archive = _get_attr('archive') _status("Archive: %s" % archive) return archive # # The following is specific to this project # and would need to be changed if this file is # used for anything else. import tempfile import datetime tempdir = tempfile.mktemp() archive_date = datetime.datetime.utcnow().isoformat('_').replace( '-', '').replace(':', '').split('.')[0] archive = os.path.join(tempdir, "fmath-%s.tar.gz" % archive_date) local("mkdir -p %s" % tempdir) with lcd(tempdir): repo = _get_attr('repo') branch = _get_attr('repo_branch') local("git clone %s repo" % repo) with lcd('repo/clj'): local("git checkout %s" % branch) local('lein deps') local('LEIN_SNAPSHOTS_IN_RELEASE=true lein jar') local('git rev-list --max-count=1 HEAD > REVISION') local( "REV=`cat REVISION | head -1` && echo \"<a href=\\\"https://github.com/ericdwhite/fmath/tree/${REV}\\\">github://ericdwhite/fmath ${REV}</a>\" > template/revision.html" ) local('git branch >> REVISION') local("tar -czf %s `cat FILES`" % archive) _status("Archive: %s" % archive) env.archive = archive return archive
def create_revision(): """ Creates a tar.gz of the project to be transfered to the remote host. This method creates a temporary directory to work with a clean clone of the repository. This avoids by accident deploying something not checked in. """ _init() if env.has_key("archive"): archive = _get_attr("archive") _status("Archive: %s" % archive) return archive # # The following is specific to this project # and would need to be changed if this file is # used for anything else. import tempfile import datetime tempdir = tempfile.mktemp() archive_date = datetime.datetime.utcnow().isoformat("_").replace("-", "").replace(":", "").split(".")[0] archive = os.path.join(tempdir, "fmath-%s.tar.gz" % archive_date) local("mkdir -p %s" % tempdir) with lcd(tempdir): repo = _get_attr("repo") branch = _get_attr("repo_branch") local("git clone %s repo" % repo) with lcd("repo/clj"): local("git checkout %s" % branch) local("lein deps") local("LEIN_SNAPSHOTS_IN_RELEASE=true lein jar") local("git rev-list --max-count=1 HEAD > REVISION") local( 'REV=`cat REVISION | head -1` && echo "<a href=\\"https://github.com/ericdwhite/fmath/tree/${REV}\\">github://ericdwhite/fmath ${REV}</a>" > template/revision.html' ) local("git branch >> REVISION") local("tar -czf %s `cat FILES`" % archive) _status("Archive: %s" % archive) env.archive = archive return archive
def write_nginx_conf(): ctx = { "allowed_hosts": env.django["allowed_hosts"], "app_root": env.source_root, "media_root": env.django["media_root"], "static_root": env.django["static_root"] } if env.has_key("django_admin_enabled") and env.django_admin_enabled: ctx["django_admin_enabled"] = True ctx["admin_contrib"] = env.django["django_contrib_path"] if exists("/etc/nginx/sites-enabled/default"): sudo("rm -rf /etc/nginx/sites-enabled/default") upload_template(filename="webserver/nginx.template", destination="/etc/nginx/sites-enabled/{0}.conf".format(env.virtualenv_name), use_jinja=True, template_dir=env.deploy_templates_path, use_sudo=True, context=ctx, backup=False)
def _checkout_or_update_cvs(revision): if files.exists(env.vcs_root): with cd(env.vcs_root): sudo_or_run('CVS_RSH="ssh" cvs update -d -P') else: if env.has_key('cvs_user'): user_spec = env.cvs_user + "@" else: user_spec = "" with cd(env.project_root): cvs_options = '-d:%s:%s%s:%s' % (env.cvs_connection_type, user_spec, env.repository, env.repo_path) command_options = '-d %s' % env.vcs_root if revision is not None: command_options += ' -r ' + revision sudo_or_run('%s cvs %s checkout %s %s' % (env.cvs_rsh, cvs_options, command_options, env.cvs_project))
def clone_repository(): if not exists(os.path.join(env.app_root, "requirements.txt")): clone(env.git_url, env.app_root, use_sudo=True) if env.has_key("deploy_branch"): checkout(env.app_root, env.deploy_branch, use_sudo=True)
def _init(): if not env.has_key('inited'): _status("Initializing.") _merge_paths() env.inited = True
def _init(): if not env.has_key("inited"): _status("Initializing.") _merge_paths() env.inited = True
def connect(user, host, port): """ Create and return a new SSHClient instance connected to given host. """ from state import env, output # # Initialization # # Init client client = ssh.SSHClient() # Load known host keys (e.g. ~/.ssh/known_hosts) unless user says not to. if not env.disable_known_hosts: client.load_system_host_keys() # Unless user specified not to, accept/add new, unknown host keys if not env.reject_unknown_hosts: client.set_missing_host_key_policy(ssh.AutoAddPolicy()) # Use client provided private key instance if it exists if env.has_key('pkey'): pkey = env.pkey env.key_filename = None else: pkey = None # # Connection attempt loop # # Initialize loop variables connected = False password = get_password() tries = 0 # Loop until successful connect (keep prompting for new password) while not connected: # Attempt connection try: tries += 1 client.connect( hostname=host, port=int(port), username=user, pkey=pkey, password=password, key_filename=key_filenames(), timeout=env.timeout, allow_agent=not env.no_agent, look_for_keys=not env.no_keys ) connected = True # set a keepalive if desired if env.keepalive: client.get_transport().set_keepalive(env.keepalive) return client # BadHostKeyException corresponds to key mismatch, i.e. what on the # command line results in the big banner error about man-in-the-middle # attacks. except ssh.BadHostKeyException, e: raise NetworkError("Host key for %s did not match pre-existing key! Server's key was changed recently, or possible man-in-the-middle attack." % host, e) # Prompt for new password to try on auth failure except ( ssh.AuthenticationException, ssh.PasswordRequiredException, ssh.SSHException ), e: msg = str(e) # For whatever reason, empty password + no ssh key or agent # results in an SSHException instead of an # AuthenticationException. Since it's difficult to do # otherwise, we must assume empty password + SSHException == # auth exception. Conversely: if we get SSHException and there # *was* a password -- it is probably something non auth # related, and should be sent upwards. # # This also holds true for rejected/unknown host keys: we have to # guess based on other heuristics. if e.__class__ is ssh.SSHException \ and (password or msg.startswith('Unknown server')): raise NetworkError(msg, e) # Otherwise, assume an auth exception, and prompt for new/better # password. # The 'ssh' library doesn't handle prompting for locked private # keys (i.e. keys with a passphrase and not loaded into an agent) # so we have to detect this and tweak our prompt slightly. # (Otherwise, however, the logic flow is the same, because # ssh's connect() method overrides the password argument to be # either the login password OR the private key passphrase. Meh.) # # NOTE: This will come up if you normally use a # passphrase-protected private key with ssh-agent, and enter an # incorrect remote username, because ssh.connect: # * Tries the agent first, which will fail as you gave the wrong # username, so obviously any loaded keys aren't gonna work for a # nonexistent remote account; # * Then tries the on-disk key file, which is passphrased; # * Realizes there's no password to try unlocking that key with, # because you didn't enter a password, because you're using # ssh-agent; # * In this condition (trying a key file, password is None) # ssh raises PasswordRequiredException. text = None if e.__class__ is ssh.PasswordRequiredException: # NOTE: we can't easily say WHICH key's passphrase is needed, # because ssh doesn't provide us with that info, and # env.key_filename may be a list of keys, so we can't know # which one raised the exception. Best not to try. prompt = "[%s] Passphrase for private key" text = prompt % env.host_string password = prompt_for_password(text) # Update env.password, env.passwords if empty set_password(password)