def heroku_deploy(): if not heroku_remote_exists(): # check if heroku toolbelt is available heroku_bin = local('which heroku', capture=True) if not heroku_bin: install_heroku_toolbelt() # log in to heroku selected_account = heroku_select_account() local('heroku login --account %s' % selected_account) # select or create an app app_name = heroku_select_or_create_app(selected_account) # add redis ? add_redis = prompt(_white("Type 'y' to add Redis To Go to your Heroku application " "(to use an external service, update your settings file): ")) or None if add_redis.lower() == 'y': heroku_add_redis(app=app_name, account=selected_account) check_git() # add git remote local('git remote add heroku heroku.com:%s.git' % app_name) print(_green("You are ready to commit any changes and deploy to heroku by typing: %s" % _white("git push heroku <name_of_branch>"))) return None print(_green("Looks like there is already a heroku remote set up. Huzzah!"))
def destory_config(conf): import os for vm in conf: sendWarning("Removing stale Keys for: " + _white(vm["name"])) dest = "provisioner/conf/keys/" + vm["name"] + ".pem" os.remove(dest) cfg = "provisioner/conf/cache/cheflab-hosts.cfg" sendWarning("Removing stale hosts file : " + _white(cfg)) os.remove(cfg)
def deploy(): if not exists('/home/%s' % env.user): sudo('mkdir /home/%s' % env.user) sudo('chown %s:%s /home/%s' % (env.user, env.user, env.user)) puppet_properties = {} properties = get_puppet_properties() puppet_properties.update((k, v) for k, v in properties.iteritems() if v) puppet_properties['couchdb_hostname'] = env.host ''' if the desired couchdb database path DNE, create it ''' if 'database_dir' in puppet_properties: if not exists(puppet_properties['database_dir']): sudo('mkdir -p %s' % puppet_properties['database_dir']) ''' ensure puppet is installed before running module ''' install_puppet() ''' ensure puppet repo is up-to-date on host then apply couch module ''' update_puppet_repo() apply_couch_module(puppet_properties) # update_hosts() ''' adding a small sleep to ensure couchdb is running before setting up dbs and replicating ''' run('sleep 10') couchdb_flush() couchdb_replicate(properties['couchdb_masterless_mode'], properties['slave_mode']) ''' new relic setup - ask operator if s/he wants to set up new relic monitoring ''' newrelic = bool( prompt(_white( 'Set up New Relic monitoring %s ' % _green('[y/N]:')))) or False if newrelic: newrelic_key = None while not newrelic_key: newrelic_key = prompt( _white( 'Enter your New Relic license key -- required: ')) or None if newrelic and newrelic_key: newrelic_setup(newrelic, newrelic_key) ''' if this is the first time it has run, amend rc.local with appropriate commands ''' if not exists('/etc/puppet/.couchdb.deployed'): amend_rc_local(properties['couchdb_masterless_mode']) ''' add a blank hidden file to let us know this deploy has already run ''' sudo('touch /etc/puppet/.couchdb.deployed')
def heroku_select_or_create_app(account_name): account_applications = local('heroku apps --account %s' % account_name, capture=True) app = prompt(_white("Type the name of the application you wish to use, or press " "Enter to create a new one:\n\t%s%s\nSelection: " % (_yellow('* '), _yellow('\n\t* '.join(account_applications.split('\n')))))) or None if app: if app in account_applications: return app app = prompt(_white("Type the name of the app you would like to create: ")) local('heroku apps:create %s --account %s' % (app, account_name)) return app
def heroku_select_account(): # select heroku account accounts = local('heroku accounts', capture=True) or None if accounts: return prompt(_white("Type the name of the Heroku account you would like to use:\n\t%s%s\n" % (_yellow('* '), _yellow('\n\t* '.join(accounts.split('\n')))))) else: add_account = prompt(_white("No heroku toolbelt account was found. Would you like to add one? [n] ")) or None if add_account: account_name = prompt(_white("Type the name of the account you would like to add")) local('heroku accounts:add %s' % account_name) return account_name
def get_keys(conf): from shutil import copy for vm in conf: sendInfo("Getting Keys for: " + _white(vm["name"])) src = "boxes/machines/" + vm["name"] + "/virtualbox/private_key" dest = "provisioner/conf/keys/" + vm["name"] + ".pem" copy(src, dest)
def heroku_add_redis(app=None, account=None): redis_host = None redis_port = 6379 redis_password = None redis_db = 0 if not account: account = heroku_select_account() if not app: app = heroku_select_or_create_app(account) redis_exists = local('heroku addons --app %s --account %s' % (app, account), capture=True) if not 'redistogo' in redis_exists: local('heroku addons:add --app %s --account %s redistogo:nano' % (app, account)) open_redis_details = prompt(_white("Would you like to open the addon's details in your browser now? [n] ")) or False if open_redis_details: prompted = prompt(_yellow("Once the redis details open, you will be prompted to enter some details. " "You can type 'q' at any time to cancel updating your application's Redis details." "Press Enter to open the Redis details page.")) if prompted != 'q': local('heroku addons:open --app %s --account %s redistogo:nano' % (app, account)) prompted = prompt(_white("From the 'General' section, paste the name of the redis instance (like 'angelfish-9357')")) or None if prompted and prompted != 'q': host, redis_port = prompted.strip().split('-') redis_host = '%s.redistogo.com' % host prompted = prompt(_white("From the security section, paste the Redis password: "******"Which environment is this for?\n\t1. Staging\n\t2. Production\nSelection: ")) profile = 'staging' if '2' in is_staging: profile = 'prod' settings_file = [i for i in os.listdir('./') if re.search('settings', i) and not re.search(r'.*\.pyc$', i)][0] settings_path = os.path.join('./', settings_file) f = open(settings_path, 'r') settings_lines = [ i.replace('<%s.redis_host>' % profile, redis_host) .replace('<%s.redis_port>' % profile, str(redis_port)) .replace('<%s.redis_password>' % profile, redis_password) for i in f.readlines()] f = open('%s' % settings_path, 'w') for line in settings_lines: f.write(line) f.close()
def get_puppet_properties(): properties = {} print(_white('Enter setup information. Defaults in %s. ' % _green('green'))) prompt( _white( 'To keep default, simply press enter when prompted. \nAll optional unless noted. Press enter to continue.' )) properties['bind'] = prompt( _white('CouchDB bind address %s ' % _green('[0.0.0.0]:'))) or '0.0.0.0' properties['database_dir'] = prompt( _white('CouchDB database dir %s ' % _green('[/usr/local/var/lib/couchdb]:'))) or None ''' admin user info ''' properties['admin_user'] = prompt( _white('CouchDB admin user %s ' % _green('[None]:'))) or None if properties['admin_user']: properties['admin_password'] = None while not properties['admin_password']: properties['admin_password'] = prompt( _white( 'CouchDb admin password %s ' % _green('[None] :'))) or None ''' masterless/slave setup ''' properties['couchdb_masterless_mode'] = bool( prompt( _yellow('Run as part of a masterless cluster %s ' % _green('[y/N]:')))) or False if not properties['couchdb_masterless_mode']: properties['slave_mode'] = bool( prompt( _yellow('Run as a slave to another master %s ' % _green('[y/N]:')))) or False else: properties['slave_mode'] = False if properties['couchdb_masterless_mode'] or properties['slave_mode']: properties['couchdb_master_hostname'] = None properties['couchdb_master_ip'] = None while not properties['couchdb_master_hostname']: properties['couchdb_master_hostname'] = prompt( _white( 'Hostname of CouchDB master server -- required: ')) or None while not properties['couchdb_master_ip']: properties['couchdb_master_ip'] = prompt( _white('IP Address of CouchDB master server -- required: ') ) or None return properties
def generate_hostsfile(conf): import os.path cheflabfile = "provisioner/conf/cache/cheflab-hosts.cfg" sendInfo("Generating hosts file") s = [] if os.path.isfile(cheflabfile): with open(cheflabfile) as f: for line in f: s.append(line.strip().split("\t")) for vm, index in zip(conf, s): fqdn = vm["name"] + ".cheflab.dev" if fqdn == index[1]: pass else: sendInfo("Adding host entry for: " + _white(fqdn)) write_file(cheflabfile, vm["ip"], fqdn, vm["name"]) else: for vm in conf: fqdn = vm["name"] + ".cheflab.dev" sendInfo("Adding host entry for: " + _white(fqdn)) write_file(cheflabfile, vm["ip"], fqdn, vm["name"])
def import_container(container_name=None): """ import a container by name. If no container name is specified, import all containers :param container_name: (optional) the container to import """ import_containers = [x for x in CONTAINERS if x['name'] != 'base'] if container_name: import_containers = [x for x in import_containers if x['name'] == container_name] for c in import_containers: container = Container(env.environment, c) print(_white("==> Importing %s container from S3" % container.name)) local('sudo curl %s | sudo docker import - %s/%s' % (container.s3_path, env.environment.lower(), container.name))
def create_virtualenv_local(virtual_env_path=env.local_virtual_env_path): """ * create a local virtualenv environment. Usage: create_virtual_local:path_to_env create_virtual_local Options: path_toenv: Optional. Will default to one directory up from fabfile named 'env'. Effectively the path ['../']. """ if not os.path.isdir(virtual_env_path): with settings(warn_only=True): result = local("virtualenv --no-site-packages --distribute %s" % virtual_env_path) if result.failed and not confirm(_white("Installing virtualenv failed. Continue anyway?"), default=False): abort(_red("Aborting local staging.")) print(_green("Virtualenv installed and detected."))
def config(): ENVIRONMENT = os.environ.get("COUCHENV", "development") if ENVIRONMENT in ['prod', 'production']: config_file_path = './config/production.json' elif ENVIRONMENT in ['test', 'staging']: config_file_path = './config/staging.json' elif ENVIRONMENT in ['dev', 'development']: config_file_path = './config/dev.json' elif ENVIORNMENT in ['local']: config_file_path = './config/local.json' else: abort( _red( 'No COUCHENV or config file defined. Either define COUCHENV=[prod|test|dev] or call fab config:/path/to/config/file spinup:[ID]' )) opts = {} with open(config_file_path) as data_file: ''' load in template data from data file ''' opts = json.load(data_file) opts['environment'] = ENVIRONMENT.upper() ''' ensure required properties are present in config file ''' if all(k in opts for k in ('user', 'ssh_keyfile', 'project_name', 'aws_access_key_id', 'aws_secret_access_key', 'aws_ami', 'aws_keypair_name', 'aws_ec2_region', 'aws_instance_type', 'aws_security_group')): return opts else: print( _red( 'One or more required fields are missing. Ensure that the following properties are included in your config file:\n' )) print( _white( '%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s' % ('user', 'ssh_keyfile', 'project_name', 'aws_access_key_id', 'aws_secret_access_key', 'aws_ami', 'aws_keypair_name', 'aws_ec2_region', 'aws_instance_type', 'aws_security_group'))) abort('Aborting.')
def create_virtualenv_local(virtual_env_path=env.local_virtual_env_path): """ * create a local virtualenv environment. Usage: create_virtual_local:path_to_env create_virtual_local Options: path_toenv: Optional. Will default to one directory up from fabfile named 'env'. Effectively the path ['../']. """ if not os.path.isdir(virtual_env_path): with settings(warn_only=True): result = local("virtualenv --no-site-packages --distribute %s" % virtual_env_path) if result.failed and not confirm( _white("Installing virtualenv failed. Continue anyway?"), default=False): abort(_red("Aborting local staging.")) print(_green("Virtualenv installed and detected."))
def install_heroku_toolbelt(): is_installed = False install = prompt(_white("Heroku Toolbelt is not installed. Would you like to install it? [n] ")) or None if install: if re.search('darwin', sys.platform): # install with brew if available brew = local('which brew', capture=True) if brew: local('brew install heroku-toolbelt') is_installed = True else: abort(_red("Attempted to install heroku-toolbelt with brew, but brew was not found. " "Please install homebrew and try again, or install the heroku-toolbelt manually " "from https://toolbelt.heroku.com")) elif re.search('linux', sys.platform): # install with wget if ubuntu is_ubuntu = local('uname -v', capture=True) if re.search('ubuntu', is_ubuntu.lower()): sudo('wget -qO- https://toolbelt.heroku.com/install-ubuntu.sh | sh') is_installed = True if is_installed: print(_green("Heroku Toolbelt successfully installed"))
def spinup(suffix): ''' if no suffix was defined for the new instance, generate one at random ''' if not suffix: suffix = b2a_hex(os.urandom(4)) ''' get environment options and create an ec2 connection ''' opts = config() env.user = opts['user'] host_name = '%s-CouchDB-%s' % (opts['environment'], suffix) ec2 = EC2(opts['aws_ec2_region'], opts['aws_access_key_id'], opts['aws_secret_access_key']) print(_green("Started...")) print(_yellow("...Creating EC2 instance...")) ''' check if user has defined specific placement zone ''' desired_availability_zone = None if 'aws_ec2_availability_zone' in opts: desired_availability_zone = opts['aws_ec2_availability_zone'] ''' clone the defined ami to a new instance ''' reservation = ec2.conn.run_instances( opts['aws_ami'], placement=desired_availability_zone, key_name=opts['aws_keypair_name'], instance_type=opts['aws_instance_type'], security_groups=opts['aws_security_group']) instance = reservation.instances[0] ''' update progress ''' while instance.state != 'running': print(_yellow("Instance state: %s" % instance.state)) sleep(1) instance.update() ''' tag the new instance ''' ec2.conn.create_tags([instance.id], {'Name': '%s' % host_name}) if opts['project_name']: ec2.conn.create_tags([instance.id], {'Project': opts['project_name']}) ''' update progress ''' print(_yellow("Launched: %s, %s" % (instance.dns_name, host_name))) print(_green("Instance state: %s" % instance.state)) print(_green("Public dns: %s" % instance.public_dns_name)) ''' if you want to add the new instance to a load balancer, you can do that. ''' add_to_lb = prompt( _white( "Add new EC2 instance to an ELB %s" % _green('[y/N]: '))) or None if add_to_lb: add_to_lb = prompt( _white( "Adding this to the ELB will automatically enable the availability zone for your EC2 instance if not already enabled for this ELB. Proceed %s " % _green('[y/N]: '))) if add_to_lb: load_balancer_name = None if 'aws_elb_load_balancer' not in opts: while not load_balancer_name: load_balancer_name = prompt( _white('Load Balancer Name --required: ')) or None else: load_balancer_name = opts['aws_elb_load_balancer'] ''' if no desired_availability_zone was defined in the config, set it now to the instance's placement group ''' if not desired_availability_zone: desired_availability_zone = instance.placement add_to_load_balancer(ec2, load_balancer_name, instance.id, desired_availability_zone) ''' update local ssh config so new instance is ssh-ready ''' local('echo "\nHost %s" >> ~/.ssh/config' % host_name) local('echo "HostName %s" >> ~/.ssh/config' % instance.dns_name) local('echo "User %s" >> ~/.ssh/config' % env.user) ''' run couchdb deploy ''' print(_yellow("Deploying CouchDB Puppet Module...")) env.host_string = instance.dns_name deploy()