def configure_haproxy(service_ports): ''' Configure HAProxy based on the current peers in the service cluster using the provided port map: "swift": [ 8080, 8070 ] HAproxy will also be reloaded/started if required service_ports: dict: dict of lists of [ frontend, backend ] ''' cluster_hosts = {} cluster_hosts[os.getenv('JUJU_UNIT_NAME').replace('/', '-')] = \ unit_get('private-address') for r_id in relation_ids('cluster'): for unit in relation_list(r_id): cluster_hosts[unit.replace('/', '-')] = \ relation_get(attribute='private-address', rid=r_id, unit=unit) context = { 'units': cluster_hosts, 'service_ports': service_ports } with open(HAPROXY_CONF, 'w') as f: f.write(render_template(os.path.basename(HAPROXY_CONF), context)) with open(HAPROXY_DEFAULT, 'w') as f: f.write('ENABLED=1') reload('haproxy')
def amqp_changed(relation_id=None, remote_unit=None): if not cluster.eligible_leader('res_rabbitmq_vip'): msg = 'amqp_changed(): Deferring amqp_changed to eligible_leader.' utils.juju_log('INFO', msg) return relation_settings = {} settings = hookenv.relation_get(rid=relation_id, unit=remote_unit) singleset = set([ 'username', 'vhost' ]) if singleset.issubset(settings): if None in [settings['username'], settings['vhost']]: utils.juju_log('INFO', 'amqp_changed(): Relation not ready.') return relation_settings['password'] = configure_amqp(username=settings['username'], vhost=settings['vhost']) else: queues = {} for k, v in settings.iteritems(): amqp = k.split('_')[0] x = '_'.join(k.split('_')[1:]) if amqp not in queues: queues[amqp] = {} queues[amqp][x] = v relation_settings = {} for amqp in queues: if singleset.issubset(queues[amqp]): relation_settings['_'.join([amqp, 'password'])] = configure_amqp(queues[amqp]['username'], queues[amqp]['vhost']) relation_settings['hostname'] = utils.unit_get('private-address') if cluster.is_clustered(): relation_settings['clustered'] = 'true' if utils.is_relation_made('ha'): # active/passive settings relation_settings['vip'] = utils.config_get('vip') if relation_id: relation_settings['rid'] = relation_id utils.relation_set(**relation_settings) # sync new creds to all peers rabbit.synchronize_service_credentials()
def config_get(): """ Obtain the units config via 'config-get' Returns a dict representing current config. private-address and IP of the unit is also tacked on for convienence """ output = execute("config-get --format json")[0] config = json.loads(output) # make sure no config element is blank after config-get for c in config.keys(): if not config[c]: error_out("ERROR: Config option has no paramter: %s" % c) # tack on our private address and ip config["hostname"] = utils.unit_get('private-address') return config
def amqp_changed(relation_id=None, remote_unit=None): if not cluster.eligible_leader('res_rabbitmq_vip'): msg = 'amqp_changed(): Deferring amqp_changed to eligible_leader.' utils.juju_log('INFO', msg) return relation_settings = {} settings = hookenv.relation_get(rid=relation_id, unit=remote_unit) singleset = set(['username', 'vhost']) if singleset.issubset(settings): if None in [settings['username'], settings['vhost']]: utils.juju_log('INFO', 'amqp_changed(): Relation not ready.') return relation_settings['password'] = configure_amqp( username=settings['username'], vhost=settings['vhost']) else: queues = {} for k, v in settings.iteritems(): amqp = k.split('_')[0] x = '_'.join(k.split('_')[1:]) if amqp not in queues: queues[amqp] = {} queues[amqp][x] = v relation_settings = {} for amqp in queues: if singleset.issubset(queues[amqp]): relation_settings['_'.join([amqp, 'password'])] = configure_amqp( queues[amqp]['username'], queues[amqp]['vhost']) relation_settings['hostname'] = utils.unit_get('private-address') if cluster.is_clustered(): relation_settings['clustered'] = 'true' if utils.is_relation_made('ha'): # active/passive settings relation_settings['vip'] = utils.config_get('vip') if relation_id: relation_settings['rid'] = relation_id utils.relation_set(**relation_settings) # sync new creds to all peers rabbit.synchronize_service_credentials()
def sync_to_peers(peer_interface, user, paths=[], verbose=False): base_cmd = [ 'unison', '-auto', '-batch=true', '-confirmbigdel=false', '-fastcheck=true', '-group=false', '-owner=false', '-prefer=newer', '-times=true' ] if not verbose: base_cmd.append('-silent') hosts = [] for r_id in (utils.relation_ids(peer_interface) or []): for unit in utils.relation_list(r_id): settings = utils.relation_get_dict(relation_id=r_id, remote_unit=unit) try: authed_hosts = settings['ssh_authorized_hosts'].split(':') except KeyError: print 'unison sync_to_peers: peer has not authorized *any* '\ 'hosts yet.' return unit_hostname = utils.unit_get('private-address') add_host = None for authed_host in authed_hosts: if unit_hostname == authed_host: add_host = settings['private-address'] if add_host: hosts.append(settings['private-address']) else: print 'unison sync_to_peers: peer (%s) has not authorized '\ '*this* host yet, skipping.' %\ settings['private-address'] for path in paths: # removing trailing slash from directory paths, unison # doesn't like these. if path.endswith('/'): path = path[:(len(path) - 1)] for host in hosts: try: cmd = base_cmd + [path, 'ssh://%s@%s/%s' % (user, host, path)] utils.juju_log( 'INFO', 'Syncing local path %s to %s@%s:%s' % (path, user, host, path)) run_as_user(user, cmd) except: # it may fail for permissions on some files pass
def sync_to_peers(peer_interface, user, paths=[], verbose=False): base_cmd = ['unison', '-auto', '-batch=true', '-confirmbigdel=false', '-fastcheck=true', '-group=false', '-owner=false', '-prefer=newer', '-times=true'] if not verbose: base_cmd.append('-silent') hosts = [] for r_id in (utils.relation_ids(peer_interface) or []): for unit in utils.relation_list(r_id): settings = utils.relation_get_dict(relation_id=r_id, remote_unit=unit) try: authed_hosts = settings['ssh_authorized_hosts'].split(':') except KeyError: print 'unison sync_to_peers: peer has not authorized *any* '\ 'hosts yet.' return unit_hostname = utils.unit_get('private-address') add_host = None for authed_host in authed_hosts: if unit_hostname == authed_host: add_host = settings['private-address'] if add_host: hosts.append(settings['private-address']) else: print 'unison sync_to_peers: peer (%s) has not authorized '\ '*this* host yet, skipping.' %\ settings['private-address'] for path in paths: # removing trailing slash from directory paths, unison # doesn't like these. if path.endswith('/'): path = path[:(len(path) - 1)] for host in hosts: try: cmd = base_cmd + [path, 'ssh://%s@%s/%s' % (user, host, path)] utils.juju_log('INFO', 'Syncing local path %s to %s@%s:%s' % (path, user, host, path)) run_as_user(user, cmd) except: # it may fail for permissions on some files pass
def amqp_changed(relation_id=None, remote_unit=None): if not cluster.eligible_leader('res_rabbitmq_vip'): msg = 'amqp_changed(): Deferring amqp_changed to eligible_leader.' utils.juju_log('INFO', msg) return rabbit_user = utils.relation_get('username', rid=relation_id, unit=remote_unit) vhost = utils.relation_get('vhost', rid=relation_id, unit=remote_unit) if None in [rabbit_user, vhost]: utils.juju_log('INFO', 'amqp_changed(): Relation not ready.') return password_file = os.path.join(RABBIT_DIR, '%s.passwd' % rabbit_user) if os.path.exists(password_file): password = open(password_file).read().strip() else: cmd = ['pwgen', '64', '1'] password = subprocess.check_output(cmd).strip() with open(password_file, 'wb') as out: out.write(password) rabbit.create_vhost(vhost) rabbit.create_user(rabbit_user, password) rabbit.grant_permissions(rabbit_user, vhost) rabbit_hostname = utils.unit_get('private-address') relation_settings = { 'password': password, 'hostname': rabbit_hostname } if cluster.is_clustered(): relation_settings['clustered'] = 'true' relation_settings['vip'] = utils.config_get('vip') if relation_id: relation_settings['rid'] = relation_id utils.relation_set(**relation_settings)
def shared_db_changed(): def configure_db(hostname, database, username): passwd_file = "/var/lib/mysql/mysql-{}.passwd"\ .format(username) if hostname != local_hostname: remote_ip = socket.gethostbyname(hostname) else: remote_ip = '127.0.0.1' if not os.path.exists(passwd_file): password = pwgen() with open(passwd_file, 'w') as pfile: pfile.write(password) else: with open(passwd_file) as pfile: password = pfile.read().strip() if not database_exists(database): create_database(database) if not grant_exists(database, username, remote_ip): create_grant(database, username, remote_ip, password) return password if not cluster.eligible_leader(LEADER_RES): utils.juju_log( 'INFO', 'MySQL service is peered, bailing shared-db relation' ' as this service unit is not the leader') return settings = relation_get() local_hostname = utils.unit_get('private-address') singleset = set(['database', 'username', 'hostname']) if singleset.issubset(settings): # Process a single database configuration password = configure_db(settings['hostname'], settings['database'], settings['username']) if not cluster.is_clustered(): utils.relation_set(db_host=local_hostname, password=password) else: utils.relation_set(db_host=utils.config_get("vip"), password=password) else: # Process multiple database setup requests. # from incoming relation data: # nova_database=xxx nova_username=xxx nova_hostname=xxx # quantum_database=xxx quantum_username=xxx quantum_hostname=xxx # create #{ # "nova": { # "username": xxx, # "database": xxx, # "hostname": xxx # }, # "quantum": { # "username": xxx, # "database": xxx, # "hostname": xxx # } #} # databases = {} for k, v in settings.iteritems(): db = k.split('_')[0] x = '_'.join(k.split('_')[1:]) if db not in databases: databases[db] = {} databases[db][x] = v return_data = {} for db in databases: if singleset.issubset(databases[db]): return_data['_'.join([db, 'password'])] = \ configure_db(databases[db]['hostname'], databases[db]['database'], databases[db]['username']) if len(return_data) > 0: utils.relation_set(**return_data) if not cluster.is_clustered(): utils.relation_set(db_host=local_hostname) else: utils.relation_set(db_host=utils.config_get("vip"))
def shared_db_changed(): if not cluster.eligible_leader(LEADER_RES): utils.juju_log('INFO', 'MySQL service is peered, bailing shared-db relation' ' as this service unit is not the leader') return if utils.config_get('prefer-ipv6'): local_hostname = get_ipv6_addr(exc_list=[utils.config_get('vip')])[0] else: local_hostname = utils.unit_get('private-address') settings = relation_get() singleset = set([ 'database', 'username', 'hostname']) db_helper = get_db_helper() if singleset.issubset(settings): # Process a single database configuration hostname = settings['hostname'] database = settings['database'] username = settings['username'] # Hostname can be json-encoded list of hostnames try: hostname = json.loads(hostname) except ValueError: hostname = [hostname] for host in hostname: password = db_helper.configure_db(host, database, username) allowed_units = db_helper.get_allowed_units(database, username) allowed_units = unit_sorted(allowed_units) allowed_units = ' '.join(allowed_units) if cluster.is_clustered(): db_host = utils.config_get("vip") else: db_host = local_hostname utils.relation_set(db_host=db_host, password=password, allowed_units=allowed_units) else: # Process multiple database setup requests. # from incoming relation data: # nova_database=xxx nova_username=xxx nova_hostname=xxx # quantum_database=xxx quantum_username=xxx quantum_hostname=xxx # create # { # "nova": { # "username": xxx, # "database": xxx, # "hostname": xxx # }, # "quantum": { # "username": xxx, # "database": xxx, # "hostname": xxx # } # } # databases = {} for k, v in settings.iteritems(): db = k.split('_')[0] x = '_'.join(k.split('_')[1:]) if db not in databases: databases[db] = {} databases[db][x] = v return_data = {} for db in databases: if singleset.issubset(databases[db]): database = databases[db]['database'] hostname = databases[db]['hostname'] username = databases[db]['username'] try: # Can be json-encoded list of hostnames hostname = json.loads(hostname) except ValueError: # Otherwise expected to be single hostname hostname = [hostname] for host in hostname: password = db_helper.configure_db(host, database, username) a_units = db_helper.get_allowed_units(database, username) a_units = ' '.join(unit_sorted(a_units)) return_data['%s_allowed_units' % (db)] = a_units return_data['%s_password' % (db)] = password if len(return_data) > 0: utils.relation_set(**return_data) if not cluster.is_clustered(): utils.relation_set(db_host=local_hostname) else: utils.relation_set(db_host=utils.config_get("vip"))
def shared_db_changed(): def configure_db(hostname, database, username): passwd_file = "/var/lib/mysql/mysql-{}.passwd"\ .format(username) if hostname != local_hostname: remote_ip = socket.gethostbyname(hostname) else: remote_ip = '127.0.0.1' if not os.path.exists(passwd_file): password = pwgen() with open(passwd_file, 'w') as pfile: pfile.write(password) else: with open(passwd_file) as pfile: password = pfile.read().strip() if not database_exists(database): create_database(database) if not grant_exists(database, username, remote_ip): create_grant(database, username, remote_ip, password) return password if not cluster.eligible_leader(LEADER_RES): utils.juju_log('INFO', 'MySQL service is peered, bailing shared-db relation' ' as this service unit is not the leader') return settings = relation_get() local_hostname = utils.unit_get('private-address') singleset = set([ 'database', 'username', 'hostname' ]) if singleset.issubset(settings): # Process a single database configuration password = configure_db(settings['hostname'], settings['database'], settings['username']) if not cluster.is_clustered(): utils.relation_set(db_host=local_hostname, password=password) else: utils.relation_set(db_host=utils.config_get("vip"), password=password) else: # Process multiple database setup requests. # from incoming relation data: # nova_database=xxx nova_username=xxx nova_hostname=xxx # quantum_database=xxx quantum_username=xxx quantum_hostname=xxx # create #{ # "nova": { # "username": xxx, # "database": xxx, # "hostname": xxx # }, # "quantum": { # "username": xxx, # "database": xxx, # "hostname": xxx # } #} # databases = {} for k, v in settings.iteritems(): db = k.split('_')[0] x = '_'.join(k.split('_')[1:]) if db not in databases: databases[db] = {} databases[db][x] = v return_data = {} for db in databases: if singleset.issubset(databases[db]): return_data['_'.join([db, 'password'])] = \ configure_db(databases[db]['hostname'], databases[db]['database'], databases[db]['username']) if len(return_data) > 0: utils.relation_set(**return_data) if not cluster.is_clustered(): utils.relation_set(db_host=local_hostname) else: utils.relation_set(db_host=utils.config_get("vip"))
def shared_db_changed(): if not cluster.eligible_leader(LEADER_RES): utils.juju_log( 'INFO', 'MySQL service is peered, bailing shared-db relation' ' as this service unit is not the leader') return if utils.config_get('prefer-ipv6'): local_hostname = get_ipv6_addr(exc_list=[utils.config_get('vip')])[0] else: local_hostname = utils.unit_get('private-address') settings = relation_get() singleset = set(['database', 'username', 'hostname']) db_helper = get_db_helper() if singleset.issubset(settings): # Process a single database configuration hostname = settings['hostname'] database = settings['database'] username = settings['username'] # Hostname can be json-encoded list of hostnames try: hostname = json.loads(hostname) except ValueError: hostname = [hostname] for host in hostname: password = db_helper.configure_db(host, database, username) allowed_units = db_helper.get_allowed_units(database, username) allowed_units = unit_sorted(allowed_units) allowed_units = ' '.join(allowed_units) if cluster.is_clustered(): db_host = utils.config_get("vip") else: db_host = local_hostname utils.relation_set(db_host=db_host, password=password, allowed_units=allowed_units) else: # Process multiple database setup requests. # from incoming relation data: # nova_database=xxx nova_username=xxx nova_hostname=xxx # quantum_database=xxx quantum_username=xxx quantum_hostname=xxx # create # { # "nova": { # "username": xxx, # "database": xxx, # "hostname": xxx # }, # "quantum": { # "username": xxx, # "database": xxx, # "hostname": xxx # } # } # databases = {} for k, v in settings.iteritems(): db = k.split('_')[0] x = '_'.join(k.split('_')[1:]) if db not in databases: databases[db] = {} databases[db][x] = v return_data = {} for db in databases: if singleset.issubset(databases[db]): database = databases[db]['database'] hostname = databases[db]['hostname'] username = databases[db]['username'] try: # Can be json-encoded list of hostnames hostname = json.loads(hostname) except ValueError: # Otherwise expected to be single hostname hostname = [hostname] for host in hostname: password = db_helper.configure_db(host, database, username) a_units = db_helper.get_allowed_units(database, username) a_units = ' '.join(unit_sorted(a_units)) return_data['%s_allowed_units' % (db)] = a_units return_data['%s_password' % (db)] = password if len(return_data) > 0: utils.relation_set(**return_data) if not cluster.is_clustered(): utils.relation_set(db_host=local_hostname) else: utils.relation_set(db_host=utils.config_get("vip"))
def shared_db_changed(): def get_allowed_units(database, username): allowed_units = set() for relid in hookenv.relation_ids('shared-db'): for unit in hookenv.related_units(relid): attr = "%s_%s" % (database, 'hostname') hosts = hookenv.relation_get(attribute=attr, unit=unit, rid=relid) if not hosts: hosts = [hookenv.relation_get(attribute='private-address', unit=unit, rid=relid)] else: # hostname can be json-encoded list of hostnames try: hosts = json.loads(hosts) except ValueError: pass if not isinstance(hosts, list): hosts = [hosts] if hosts: for host in hosts: utils.juju_log('INFO', "Checking host '%s' grant" % (host)) if grant_exists(database, username, host): if unit not in allowed_units: allowed_units.add(unit) else: utils.juju_log('INFO', "No hosts found for grant check") return allowed_units def configure_db(hostname, database, username): passwd_file = "/var/lib/mysql/mysql-{}.passwd".format(username) if hostname != local_hostname: try: remote_ip = socket.gethostbyname(hostname) except Exception: # socket.gethostbyname doesn't support ipv6 remote_ip = hostname else: remote_ip = '127.0.0.1' if not os.path.exists(passwd_file): password = pwgen() with open(passwd_file, 'w') as pfile: pfile.write(password) os.chmod(pfile.name, 0600) else: with open(passwd_file) as pfile: password = pfile.read().strip() if not database_exists(database): create_database(database) if not grant_exists(database, username, remote_ip): create_grant(database, username, remote_ip, password) return password if not cluster.eligible_leader(LEADER_RES): utils.juju_log('INFO', 'MySQL service is peered, bailing shared-db relation' ' as this service unit is not the leader') return if utils.config_get('prefer-ipv6'): local_hostname = get_ipv6_addr(exc_list=[utils.config_get('vip')])[0] else: local_hostname = utils.unit_get('private-address') settings = relation_get() singleset = set([ 'database', 'username', 'hostname']) if singleset.issubset(settings): # Process a single database configuration hostname = settings['hostname'] database = settings['database'] username = settings['username'] # Hostname can be json-encoded list of hostnames try: hostname = json.loads(hostname) except ValueError: pass if isinstance(hostname, list): for host in hostname: password = configure_db(host, database, username) else: password = configure_db(hostname, database, username) allowed_units = " ".join(unit_sorted(get_allowed_units(database, username))) if not cluster.is_clustered(): utils.relation_set(db_host=local_hostname, password=password, allowed_units=allowed_units) else: utils.relation_set(db_host=utils.config_get("vip"), password=password, allowed_units=allowed_units) else: # Process multiple database setup requests. # from incoming relation data: # nova_database=xxx nova_username=xxx nova_hostname=xxx # quantum_database=xxx quantum_username=xxx quantum_hostname=xxx # create # { # "nova": { # "username": xxx, # "database": xxx, # "hostname": xxx # }, # "quantum": { # "username": xxx, # "database": xxx, # "hostname": xxx # } # } # databases = {} for k, v in settings.iteritems(): db = k.split('_')[0] x = '_'.join(k.split('_')[1:]) if db not in databases: databases[db] = {} databases[db][x] = v return_data = {} for db in databases: if singleset.issubset(databases[db]): database = databases[db]['database'] hostname = databases[db]['hostname'] username = databases[db]['username'] try: hostname = json.loads(hostname) except ValueError: hostname = hostname if isinstance(hostname, list): for host in hostname: password = configure_db(host, database, username) else: password = configure_db(hostname, database, username) return_data['_'.join([db, 'password'])] = password allowed_units = unit_sorted(get_allowed_units(database, username)) return_data['_'.join([db, 'allowed_units'])] = \ " ".join(allowed_units) if len(return_data) > 0: utils.relation_set(**return_data) if not cluster.is_clustered(): utils.relation_set(db_host=local_hostname) else: utils.relation_set(db_host=utils.config_get("vip"))