def get_ceph_nodes(): hosts = [] for r_id in utils.relation_ids('ceph'): for unit in utils.relation_list(r_id): hosts.append(utils.relation_get('private-address', unit=unit, rid=r_id)) return hosts
def is_clustered(): for r_id in (relation_ids('ha') or []): for unit in (relation_list(r_id) or []): clustered = relation_get('clustered', rid=r_id, unit=unit) if clustered: return True return False
def get_ceph_nodes(): hosts = [] for r_id in utils.relation_ids('ceph'): for unit in utils.relation_list(r_id): hosts.append( utils.relation_get('private-address', unit=unit, rid=r_id)) return hosts
def ssh_authorized_peers(peer_interface, user, group=None, ensure_local_user=False): """ Main setup function, should be called from both peer -changed and -joined hooks with the same parameters. """ if ensure_local_user: ensure_user(user, group) priv_key, pub_key = get_keypair(user) hook = os.path.basename(sys.argv[0]) if hook == '%s-relation-joined' % peer_interface: utils.relation_set(ssh_pub_key=pub_key) print 'joined' elif hook == '%s-relation-changed' % peer_interface: hosts = [] keys = [] for r_id in utils.relation_ids(peer_interface): for unit in utils.relation_list(r_id): settings = utils.relation_get_dict(relation_id=r_id, remote_unit=unit) if 'ssh_pub_key' in settings: keys.append(settings['ssh_pub_key']) hosts.append(settings['private-address']) else: utils.juju_log('INFO', 'ssh_authorized_peers(): ssh_pub_key '\ 'missing for unit %s, skipping.' % unit) write_authorized_keys(user, keys) write_known_hosts(user, hosts) authed_hosts = ':'.join(hosts) utils.relation_set(ssh_authorized_hosts=authed_hosts)
def is_clustered(): for r_id in relation_ids("ha") or []: for unit in relation_list(r_id) or []: clustered = relation_get("clustered", rid=r_id, unit=unit) if clustered: return True return False
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 get_ca_cert(): ca_cert = None juju_log('INFO', "Inspecting identity-service relations for CA SSL certificate.") for r_id in relation_ids('identity-service'): for unit in relation_list(r_id): if not ca_cert: ca_cert = relation_get('ca_cert', rid=r_id, unit=unit) return ca_cert
def cluster_with(): vers = rabbit_version() if vers >= '3.0.1-1': cluster_cmd = 'join_cluster' cmd = [ RABBITMQ_CTL, 'set_policy HA \'^(?!amq\.).*\' ' '\'{"ha-mode": "all"}\'' ] subprocess.check_call(cmd) else: cluster_cmd = 'cluster' out = subprocess.check_output([RABBITMQ_CTL, 'cluster_status']) current_host = subprocess.check_output(['hostname']).strip() # check all peers and try to cluster with them available_nodes = [] first_hostname = utils.relation_get('host') available_nodes.append(first_hostname) for r_id in (utils.relation_ids('cluster') or []): for unit in (utils.relation_list(r_id) or []): address = utils.relation_get('private_address', rid=r_id, unit=unit) if address is not None: node = get_hostname(address, fqdn=False) if current_host != node: available_nodes.append(node) # iterate over all the nodes, join to the first available for node in available_nodes: utils.juju_log('INFO', 'Clustering with remote rabbit host (%s).' % node) for line in out.split('\n'): if re.search(node, line): utils.juju_log('INFO', 'Host already clustered with %s.' % node) return try: cmd = [RABBITMQ_CTL, 'stop_app'] subprocess.check_call(cmd) cmd = [RABBITMQ_CTL, cluster_cmd, 'rabbit@%s' % node] subprocess.check_call(cmd) cmd = [RABBITMQ_CTL, 'start_app'] subprocess.check_call(cmd) utils.juju_log('INFO', 'Host clustered with %s.' % node) return except: # continue to the next node pass # error, no nodes available for clustering utils.juju_log('ERROR', 'No nodes available for clustering') sys.exit(1)
def ha_changed(): if not cluster.is_clustered(): return vip = utils.config_get('vip') utils.juju_log('INFO', 'ha_changed(): We are now HA clustered. ' 'Advertising our VIP (%s) to all AMQP clients.' % vip) # need to re-authenticate all clients since node-name changed. for rid in utils.relation_ids('amqp'): for unit in utils.relation_list(rid): amqp_changed(relation_id=rid, remote_unit=unit)
def ha_changed(): if not cluster.is_clustered(): return vip = utils.config_get('vip') utils.juju_log( 'INFO', 'ha_changed(): We are now HA clustered. ' 'Advertising our VIP (%s) to all AMQP clients.' % vip) # need to re-authenticate all clients since node-name changed. for rid in utils.relation_ids('amqp'): for unit in utils.relation_list(rid): amqp_changed(relation_id=rid, remote_unit=unit)
def get_ceph_nodes(): hosts = [] for r_id in utils.relation_ids('ceph'): for unit in utils.relation_list(r_id): ceph_addr = \ utils.relation_get('ceph-public-address', rid=r_id, unit=unit) or \ utils.relation_get('private-address', rid=r_id, unit=unit) hosts.append(ceph_addr) return hosts
def cluster_with(): vers = rabbit_version() if vers >= '3.0.1-1': cluster_cmd = 'join_cluster' cmd = [RABBITMQ_CTL, 'set_policy HA \'^(?!amq\.).*\' ' '\'{"ha-mode": "all"}\''] subprocess.check_call(cmd) else: cluster_cmd = 'cluster' out = subprocess.check_output([RABBITMQ_CTL, 'cluster_status']) current_host = subprocess.check_output(['hostname']).strip() # check all peers and try to cluster with them available_nodes = [] first_hostname = utils.relation_get('host') available_nodes.append(first_hostname) for r_id in (utils.relation_ids('cluster') or []): for unit in (utils.relation_list(r_id) or []): address = utils.relation_get('private_address', rid=r_id, unit=unit) if address is not None: node = get_hostname(address, fqdn=False) if current_host != node: available_nodes.append(node) # iterate over all the nodes, join to the first available for node in available_nodes: utils.juju_log('INFO', 'Clustering with remote rabbit host (%s).' % node) for line in out.split('\n'): if re.search(node, line): utils.juju_log('INFO', 'Host already clustered with %s.' % node) return try: cmd = [RABBITMQ_CTL, 'stop_app'] subprocess.check_call(cmd) cmd = [RABBITMQ_CTL, cluster_cmd, 'rabbit@%s' % node] subprocess.check_call(cmd) cmd = [RABBITMQ_CTL, 'start_app'] subprocess.check_call(cmd) utils.juju_log('INFO', 'Host clustered with %s.' % node) return except: # continue to the next node pass # error, no nodes available for clustering utils.juju_log('ERROR', 'No nodes available for clustering') sys.exit(1)
def get_ceph_nodes(): hosts = [] for r_id in utils.relation_ids('ceph'): for unit in utils.relation_list(r_id): ceph_addr = \ utils.relation_get('ceph-public-address', rid=r_id, unit=unit) or \ utils.relation_get('private-address', rid=r_id, unit=unit) # We host is an ipv6 address we need to wrap it in [] ceph_addr = format_ipv6_addr(ceph_addr) or ceph_addr hosts.append(ceph_addr) return hosts
def config_changed(): unison.ensure_user(user=SSH_USER, group='keystone') execute("chmod -R g+wrx /var/lib/keystone/") # Determine whether or not we should do an upgrade, based on the # the version offered in keyston-release. available = get_os_codename_install_source(config['openstack-origin']) installed = get_os_codename_package('keystone') if (available and get_os_version_codename(available) > \ get_os_version_codename(installed)): # TODO: fixup this call to work like utils.install() do_openstack_upgrade(config['openstack-origin'], ' '.join(packages)) # Ensure keystone group permissions execute("chmod -R g+wrx /var/lib/keystone/") env_vars = {'OPENSTACK_SERVICE_KEYSTONE': 'keystone', 'OPENSTACK_PORT_ADMIN': cluster.determine_api_port( config['admin-port']), 'OPENSTACK_PORT_PUBLIC': cluster.determine_api_port( config['service-port'])} save_script_rc(**env_vars) set_admin_token(config['admin-token']) if cluster.eligible_leader(CLUSTER_RES): utils.juju_log('INFO', 'Cluster leader - ensuring endpoint configuration' ' is up to date') ensure_initial_admin(config) update_config_block('logger_root', level=config['log-level'], file='/etc/keystone/logging.conf') if get_os_version_package('keystone') >= '2013.1': # PKI introduced in Grizzly configure_pki_tokens(config) if config_dirty(): utils.restart('keystone') if cluster.eligible_leader(CLUSTER_RES): utils.juju_log('INFO', 'Firing identity_changed hook' ' for all related services.') # HTTPS may have been set - so fire all identity relations # again for r_id in utils.relation_ids('identity-service'): for unit in utils.relation_list(r_id): identity_changed(relation_id=r_id, remote_unit=unit)
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 get_cert(): cert = config_get('ssl_cert') key = config_get('ssl_key') if not (cert and key): juju_log('INFO', "Inspecting identity-service relations for SSL certificate.") cert = key = None for r_id in relation_ids('identity-service'): for unit in relation_list(r_id): if not cert: cert = relation_get('ssl_cert', rid=r_id, unit=unit) if not key: key = relation_get('ssl_key', rid=r_id, unit=unit) return (cert, key)
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 https(): ''' Determines whether enough data has been provided in configuration or relation data to configure HTTPS . returns: boolean ''' if config_get('use-https') == "yes": return True if config_get('ssl_cert') and config_get('ssl_key'): return True for r_id in relation_ids('identity-service'): for unit in relation_list(r_id): if (relation_get('https_keystone', rid=r_id, unit=unit) and relation_get('ssl_cert', rid=r_id, unit=unit) and relation_get('ssl_key', rid=r_id, unit=unit) and relation_get('ca_cert', rid=r_id, unit=unit)): return True return False
def https(): """ Determines whether enough data has been provided in configuration or relation data to configure HTTPS . returns: boolean """ if config_get("use-https") == "yes": return True if config_get("ssl_cert") and config_get("ssl_key"): return True for r_id in relation_ids("identity-service"): for unit in relation_list(r_id): if ( relation_get("https_keystone", rid=r_id, unit=unit) and relation_get("ssl_cert", rid=r_id, unit=unit) and relation_get("ssl_key", rid=r_id, unit=unit) and relation_get("ca_cert", rid=r_id, unit=unit) ): return True return False
def db_changed(): relation_data = utils.relation_get_dict() if ('password' not in relation_data or 'db_host' not in relation_data): utils.juju_log('INFO', "db_host or password not set. Peer not ready, exit 0") return update_config_block('sql', connection="mysql://%s:%s@%s/%s" % (config["database-user"], relation_data["password"], relation_data["db_host"], config["database"])) if cluster.eligible_leader(CLUSTER_RES): utils.juju_log('INFO', 'Cluster leader, performing db-sync') execute("keystone-manage db_sync", echo=True) if config_dirty(): utils.restart('keystone') time.sleep(5) if cluster.eligible_leader(CLUSTER_RES): ensure_initial_admin(config) # If the backend database has been switched to something new and there # are existing identity-service relations,, service entries need to be # recreated in the new database. Re-executing identity-service-changed # will do this. for rid in utils.relation_ids('identity-service'): for unit in utils.relation_list(rid=rid): utils.juju_log('INFO', "Re-exec'ing identity-service-changed" " for: %s - %s" % (rid, unit)) identity_changed(relation_id=rid, remote_unit=unit)
def peer_units(): peers = [] for r_id in (relation_ids('cluster') or []): for unit in (relation_list(r_id) or []): peers.append(unit) return peers
def do_openstack_upgrade(install_src, packages): '''Upgrade packages from a given install src.''' config = config_get() old_vers = get_os_codename_package('keystone') new_vers = get_os_codename_install_source(install_src) utils.juju_log('INFO', "Beginning Keystone upgrade: %s -> %s" % \ (old_vers, new_vers)) # Backup previous config. utils.juju_log('INFO', "Backing up contents of /etc/keystone.") stamp = time.strftime('%Y%m%d%H%M') cmd = 'tar -pcf /var/lib/juju/keystone-backup-%s.tar /etc/keystone' % stamp execute(cmd, die=True, echo=True) configure_installation_source(install_src) execute('apt-get update', die=True, echo=True) os.environ['DEBIAN_FRONTEND'] = 'noninteractive' cmd = 'apt-get --option Dpkg::Options::=--force-confnew -y '\ 'install %s' % packages execute(cmd, echo=True, die=True) # we have new, fresh config files that need updating. # set the admin token, which is still stored in config. set_admin_token(config['admin-token']) # set the sql connection string if a shared-db relation is found. ids = utils.relation_ids('shared-db') if ids: for rid in ids: for unit in utils.relation_list(rid): utils.juju_log('INFO', 'Configuring new keystone.conf for ' 'database access on existing database' ' relation to %s' % unit) relation_data = utils.relation_get_dict(relation_id=rid, remote_unit=unit) update_config_block('sql', connection="mysql://%s:%s@%s/%s" % (config["database-user"], relation_data["password"], relation_data["private-address"], config["database"])) utils.stop('keystone') if (cluster.eligible_leader(CLUSTER_RES)): utils.juju_log('INFO', 'Running database migrations for %s' % new_vers) execute('keystone-manage db_sync', echo=True, die=True) else: utils.juju_log('INFO', 'Not cluster leader; snoozing whilst' ' leader upgrades DB') time.sleep(10) utils.start('keystone') time.sleep(5) utils.juju_log('INFO', 'Completed Keystone upgrade: ' '%s -> %s' % (old_vers, new_vers))
def peer_units(): peers = [] for r_id in relation_ids("cluster") or []: for unit in relation_list(r_id) or []: peers.append(unit) return peers