def leader_init_db_if_ready(use_current_context=False): """ Initialise the keystone db if it is ready and mark it as initialised. NOTE: this must be idempotent. """ if not is_elected_leader(CLUSTER_RES): log("Not leader - skipping db init", level=DEBUG) return if is_db_initialised(): log("Database already initialised - skipping db init", level=DEBUG) update_all_identity_relation_units(check_db_ready=False) return # Bugs 1353135 & 1187508. Dbs can appear to be ready before the # units acl entry has been added. So, if the db supports passing # a list of permitted units then check if we're in the list. if not is_db_ready(use_current_context=use_current_context): log('Allowed_units list provided and this unit not present', level=INFO) return migrate_database() # Ensure any existing service entries are updated in the # new database backend. Also avoid duplicate db ready check. update_all_identity_relation_units(check_db_ready=False) update_all_domain_backends()
def update_all_identity_relation_units(check_db_ready=True): if is_unit_paused_set(): return if check_db_ready and not is_db_ready(): log('Allowed_units list provided and this unit not present', level=INFO) return if not is_db_initialised(): log( "Database not yet initialised - deferring identity-relation " "updates", level=INFO) return log('Firing identity_changed hook for all related services.') for rid in relation_ids('identity-service'): for unit in related_units(rid): identity_changed(relation_id=rid, remote_unit=unit) log('Firing admin_relation_changed hook for all related services.') for rid in relation_ids('identity-admin'): admin_relation_changed(rid) log('Firing identity_credentials_changed hook for all related services.') for rid in relation_ids('identity-credentials'): for unit in related_units(rid): identity_credentials_changed(relation_id=rid, remote_unit=unit)
def update_all_identity_relation_units(check_db_ready=True): CONFIGS.write_all() if is_unit_paused_set(): return if check_db_ready and not is_db_ready(): log('Allowed_units list provided and this unit not present', level=INFO) return if not is_db_initialised(): log("Database not yet initialised - deferring identity-relation " "updates", level=INFO) return if is_elected_leader(CLUSTER_RES): ensure_initial_admin(config) log('Firing identity_changed hook for all related services.') for rid in relation_ids('identity-service'): for unit in related_units(rid): identity_changed(relation_id=rid, remote_unit=unit) log('Firing admin_relation_changed hook for all related services.') for rid in relation_ids('identity-admin'): admin_relation_changed(rid) log('Firing identity_credentials_changed hook for all related services.') for rid in relation_ids('identity-credentials'): for unit in related_units(rid): identity_credentials_changed(relation_id=rid, remote_unit=unit)
def update_all_identity_relation_units(check_db_ready=True): if is_unit_paused_set(): return if check_db_ready and not is_db_ready(): log('Allowed_units list provided and this unit not present', level=INFO) return if not is_db_initialised(): log("Database not yet initialised - deferring identity-relation " "updates", level=INFO) return if not is_expected_scale(): log("Keystone charm and it's dependencies not yet at expected scale " "- deferring identity-relation updates", level=INFO) return log('Firing identity_changed hook for all related services.') for rid in relation_ids('identity-service'): for unit in related_units(rid): identity_changed(relation_id=rid, remote_unit=unit) log('Firing admin_relation_changed hook for all related services.') for rid in relation_ids('identity-admin'): admin_relation_changed(rid) log('Firing identity_credentials_changed hook for all related services.') for rid in relation_ids('identity-credentials'): for unit in related_units(rid): identity_credentials_changed(relation_id=rid, remote_unit=unit)
def identity_credentials_changed(relation_id=None, remote_unit=None): """Update the identity credentials relation on change Calls add_credentials_to_keystone :param relation_id: Relation id of the relation :param remote_unit: Related unit on the relation """ if is_elected_leader(CLUSTER_RES): if expect_ha() and not is_clustered(): log("Expected to be HA but no hacluster relation yet", level=INFO) return if not is_db_ready(): log("identity-credentials-relation-changed hook fired before db " "ready - deferring until db ready", level=WARNING) return if not is_db_initialised(): log("Database not yet initialised - deferring " "identity-credentials-relation updates", level=INFO) return unit_ready, _ = check_api_application_ready() if not unit_ready: log( ("Keystone charm unit not ready - deferring identity-relation " "updates"), level=INFO) return # Create the tenant user add_credentials_to_keystone(relation_id, remote_unit) else: log('Deferring identity_credentials_changed() to service leader.')
def domain_backend_changed(relation_id=None, unit=None): if get_api_version() < 3: log('Domain specific backend identity configuration only supported ' 'with Keystone v3 API, skipping domain creation and ' 'restart.') return domain_name = relation_get(attribute='domain-name', unit=unit, rid=relation_id) if domain_name: # NOTE(jamespage): Only create domain data from lead # unit when clustered and database # is configured and created. if is_leader() and is_db_ready() and is_db_initialised(): create_or_show_domain(domain_name) # NOTE(jamespage): Deployment may have multiple domains, # with different identity backends so # ensure that a domain specific nonce # is checked for restarts of keystone restart_nonce = relation_get(attribute='restart-nonce', unit=unit, rid=relation_id) domain_nonce_key = 'domain-restart-nonce-{}'.format(domain_name) db = unitdata.kv() if restart_nonce != db.get(domain_nonce_key): if not is_unit_paused_set(): service_restart(keystone_service()) db.set(domain_nonce_key, restart_nonce) db.flush()
def leader_init_db_if_ready(use_current_context=False): """ Initialise the keystone db if it is ready and mark it as initialised. NOTE: this must be idempotent. """ if not is_elected_leader(CLUSTER_RES): log("Not leader - skipping db init", level=DEBUG) return if is_db_initialised(): log("Database already initialised - skipping db init", level=DEBUG) update_all_identity_relation_units() return # Bugs 1353135 & 1187508. Dbs can appear to be ready before the # units acl entry has been added. So, if the db supports passing # a list of permitted units then check if we're in the list. if not is_db_ready(use_current_context=use_current_context): log('Allowed_units list provided and this unit not present', level=INFO) return migrate_database() bootstrap_keystone(configs=CONFIGS) ensure_initial_admin(config) if CompareOpenStackReleases(os_release('keystone')) >= 'liberty': CONFIGS.write(POLICY_JSON) # Ensure any existing service entries are updated in the # new database backend. update_all_identity_relation_units() update_all_domain_backends()
def domain_backend_changed(relation_id=None, unit=None): if get_api_version() < 3: log('Domain specific backend identity configuration only supported ' 'with Keystone v3 API, skipping domain creation and ' 'restart.') return domain_name = relation_get(attribute='domain-name', unit=unit, rid=relation_id) if domain_name: # NOTE(jamespage): Only create domain data from lead # unit when clustered and database # is configured and created. if is_leader() and is_db_ready() and is_db_initialised(): create_or_show_domain(domain_name) # NOTE(jamespage): Deployment may have multiple domains, # with different identity backends so # ensure that a domain specific nonce # is checked for restarts of keystone restart_nonce = relation_get(attribute='restart-nonce', unit=unit, rid=relation_id) domain_nonce_key = 'domain-restart-nonce-{}'.format(domain_name) db = unitdata.kv() if restart_nonce != db.get(domain_nonce_key): restart_keystone() db.set(domain_nonce_key, restart_nonce) db.flush()
def update_all_identity_relation_units(check_db_ready=True): CONFIGS.write_all() if check_db_ready and not is_db_ready(): log('Allowed_units list provided and this unit not present', level=INFO) return if not is_db_initialised(): log( "Database not yet initialised - deferring identity-relation " "updates", level=INFO) return if is_elected_leader(CLUSTER_RES): ensure_initial_admin(config) log('Firing identity_changed hook for all related services.') for rid in relation_ids('identity-service'): for unit in related_units(rid): identity_changed(relation_id=rid, remote_unit=unit) log('Firing admin_relation_changed hook for all related services.') for rid in relation_ids('identity-admin'): admin_relation_changed(rid) log('Firing identity_credentials_changed hook for all related services.') for rid in relation_ids('identity-credentials'): for unit in related_units(rid): identity_credentials_changed(relation_id=rid, remote_unit=unit)
def leader_init_db_if_ready(use_current_context=False): """ Initialise the keystone db if it is ready and mark it as initialised. NOTE: this must be idempotent. """ if not is_elected_leader(CLUSTER_RES): log("Not leader - skipping db init", level=DEBUG) return if is_db_initialised(): log("Database already initialised - skipping db init", level=DEBUG) update_all_identity_relation_units(check_db_ready=False) return # Bugs 1353135 & 1187508. Dbs can appear to be ready before the # units acl entry has been added. So, if the db supports passing # a list of permitted units then check if we're in the list. if not is_db_ready(use_current_context=use_current_context): log('Allowed_units list provided and this unit not present', level=INFO) return migrate_database() # Ensure any existing service entries are updated in the # new database backend. Also avoid duplicate db ready check. update_all_identity_relation_units(check_db_ready=False)
def identity_credentials_changed(relation_id=None, remote_unit=None): """Update the identity credentials relation on change Calls add_credentials_to_keystone :param relation_id: Relation id of the relation :param remote_unit: Related unit on the relation """ if is_elected_leader(CLUSTER_RES): if expect_ha() and not is_clustered(): log("Expected to be HA but no hacluster relation yet", level=INFO) return if not is_db_ready(): log("identity-credentials-relation-changed hook fired before db " "ready - deferring until db ready", level=WARNING) return if not is_db_initialised(): log("Database not yet initialised - deferring " "identity-credentials-relation updates", level=INFO) return # Create the tenant user add_credentials_to_keystone(relation_id, remote_unit) else: log('Deferring identity_credentials_changed() to service leader.')
def identity_credentials_changed(relation_id=None, remote_unit=None): """Update the identity credentials relation on change Calls add_credentials_to_keystone :param relation_id: Relation id of the relation :param remote_unit: Related unit on the relation """ if is_elected_leader(CLUSTER_RES): if not is_db_ready(): log( "identity-credentials-relation-changed hook fired before db " "ready - deferring until db ready", level=WARNING) return if not is_db_initialised(): log( "Database not yet initialised - deferring " "identity-credentials-relation updates", level=INFO) return # Create the tenant user add_credentials_to_keystone(relation_id, remote_unit) else: log('Deferring identity_credentials_changed() to service leader.')
def identity_changed(relation_id=None, remote_unit=None): notifications_checksums = {} notifications_endpoints = {} if is_elected_leader(CLUSTER_RES): if not is_db_ready(): log( "identity-service-relation-changed hook fired before db " "ready - deferring until db ready", level=WARNING) return if not is_db_initialised(): log( "Database not yet initialised - deferring identity-relation " "updates", level=INFO) return if expect_ha() and not is_clustered(): log("Expected to be HA but no hacluster relation yet", level=INFO) return add_service_to_keystone(relation_id, remote_unit) if is_service_present('neutron', 'network'): delete_service_entry('quantum', 'network') settings = relation_get(rid=relation_id, unit=remote_unit) # If endpoint has changed, notify to units related over the # identity-notifications interface. We base the decision to notify on # whether admin_url, public_url or internal_url have changed from # previous notify. service = settings.get('service') if service: key = '%s-endpoint-changed' % service notifications_endpoints[key] = endpoints_dict(settings) notifications_checksums[key] = endpoints_checksum(settings) else: # Some services don't set their name in the 'service' key in the # relation, for those their name is calculated from the prefix of # keys. See `assemble_endpoints()` for details. single = { 'service', 'region', 'public_url', 'admin_url', 'internal_url' } endpoints = assemble_endpoints(settings) for ep in endpoints.keys(): if single.issubset(endpoints[ep]): key = '%s-endpoint-changed' % ep log('endpoint: %s' % ep) notifications_endpoints[key] = (endpoints_dict( endpoints[ep])) notifications_checksums[key] = (endpoints_checksum( endpoints[ep])) else: log('Deferring identity_changed() to service leader.') if notifications_endpoints or notifications_checksums: send_notifications(notifications_checksums, notifications_endpoints)
def ha_changed(): CONFIGS.write_all() clustered = relation_get('clustered') if clustered: log('Cluster configured, notifying other services and updating ' 'keystone endpoint configuration') if (is_db_initialised() and is_elected_leader(CLUSTER_RES) and not is_unit_paused_set()): ensure_initial_admin(config) update_all_identity_relation_units()
def config_changed_postupgrade(): save_script_rc() release = os_release('keystone') if run_in_apache(release=release): # Need to ensure mod_wsgi is installed and apache2 is reloaded # immediatly as charm querys its local keystone before restart # decorator can fire apt_install(filter_installed_packages(determine_packages())) # when deployed from source, init scripts aren't installed service_pause('keystone') disable_unused_apache_sites() if WSGI_KEYSTONE_API_CONF in CONFIGS.templates: CONFIGS.write(WSGI_KEYSTONE_API_CONF) if not is_unit_paused_set(): restart_pid_check('apache2') stop_manager_instance() if enable_memcache(release=release): # If charm or OpenStack have been upgraded then the list of required # packages may have changed so ensure they are installed. apt_install(filter_installed_packages(determine_packages())) if is_leader() and fernet_enabled(): key_setup() key_leader_set() configure_https() open_port(config('service-port')) update_nrpe_config() CONFIGS.write_all() if snap_install_requested() and not is_unit_paused_set(): service_restart('snap.keystone.*') stop_manager_instance() if (is_db_initialised() and is_elected_leader(CLUSTER_RES) and not is_unit_paused_set()): ensure_initial_admin(config) if CompareOpenStackReleases( os_release('keystone')) >= 'liberty': CONFIGS.write(POLICY_JSON) update_all_identity_relation_units() update_all_domain_backends() update_all_fid_backends() for r_id in relation_ids('ha'): ha_joined(relation_id=r_id) notify_middleware_with_release_version() inform_peers_if_ready(check_api_unit_ready)
def identity_changed(relation_id=None, remote_unit=None): CONFIGS.write_all() notifications = {} if is_elected_leader(CLUSTER_RES): if not is_db_ready(): log( "identity-service-relation-changed hook fired before db " "ready - deferring until db ready", level=WARNING) return if not is_db_initialised(): log( "Database not yet initialised - deferring identity-relation " "updates", level=INFO) return if expect_ha() and not is_clustered(): log("Expected to be HA but no hacluster relation yet", level=INFO) return add_service_to_keystone(relation_id, remote_unit) if is_service_present('neutron', 'network'): delete_service_entry('quantum', 'network') settings = relation_get(rid=relation_id, unit=remote_unit) service = settings.get('service', None) if service: # If service is known and endpoint has changed, notify service if # it is related with notifications interface. csum = hashlib.sha256() # We base the decision to notify on whether these parameters have # changed (if csum is unchanged from previous notify, relation will # not fire). csum.update(settings.get('public_url', None)) csum.update(settings.get('admin_url', None)) csum.update(settings.get('internal_url', None)) notifications['%s-endpoint-changed' % (service)] = csum.hexdigest() else: # Each unit needs to set the db information otherwise if the unit # with the info dies the settings die with it Bug# 1355848 for rel_id in relation_ids('identity-service'): peerdb_settings = peer_retrieve_by_prefix(rel_id) # Ensure the null'd settings are unset in the relation. peerdb_settings = filter_null(peerdb_settings) if 'service_password' in peerdb_settings: relation_set(relation_id=rel_id, **peerdb_settings) log('Deferring identity_changed() to service leader.') if notifications: send_notifications(notifications)
def config_changed_postupgrade(): save_script_rc() release = os_release('keystone') if run_in_apache(release=release): # Need to ensure mod_wsgi is installed and apache2 is reloaded # immediatly as charm querys its local keystone before restart # decorator can fire apt_install(filter_installed_packages(determine_packages())) # when deployed from source, init scripts aren't installed service_pause('keystone') disable_unused_apache_sites() if WSGI_KEYSTONE_API_CONF in CONFIGS.templates: CONFIGS.write(WSGI_KEYSTONE_API_CONF) if not is_unit_paused_set(): restart_pid_check('apache2') stop_manager_instance() if enable_memcache(release=release): # If charm or OpenStack have been upgraded then the list of required # packages may have changed so ensure they are installed. apt_install(filter_installed_packages(determine_packages())) if is_leader() and fernet_enabled(): key_setup() key_leader_set() configure_https() open_port(config('service-port')) update_nrpe_config() CONFIGS.write_all() if snap_install_requested() and not is_unit_paused_set(): service_restart('snap.keystone.*') stop_manager_instance() if (is_db_initialised() and is_elected_leader(CLUSTER_RES) and not is_unit_paused_set()): ensure_initial_admin(config) if CompareOpenStackReleases( os_release('keystone')) >= 'liberty': CONFIGS.write(POLICY_JSON) update_all_identity_relation_units() update_all_domain_backends() update_all_fid_backends() for r_id in relation_ids('ha'): ha_joined(relation_id=r_id) notify_middleware_with_release_version()
def ha_changed(): CONFIGS.write_all() clustered = relation_get('clustered') if clustered: log('Cluster configured, notifying other services and updating ' 'keystone endpoint configuration') if (is_db_initialised() and is_elected_leader(CLUSTER_RES) and not is_unit_paused_set()): ensure_initial_admin(config) update_all_identity_relation_units() update_all_domain_backends() update_all_fid_backends()
def identity_changed(relation_id=None, remote_unit=None): CONFIGS.write_all() notifications = {} if is_elected_leader(CLUSTER_RES): if not is_db_ready(): log("identity-service-relation-changed hook fired before db " "ready - deferring until db ready", level=WARNING) return if not is_db_initialised(): log("Database not yet initialised - deferring identity-relation " "updates", level=INFO) return if expect_ha() and not is_clustered(): log("Expected to be HA but no hacluster relation yet", level=INFO) return add_service_to_keystone(relation_id, remote_unit) if is_service_present('neutron', 'network'): delete_service_entry('quantum', 'network') settings = relation_get(rid=relation_id, unit=remote_unit) service = settings.get('service', None) if service: # If service is known and endpoint has changed, notify service if # it is related with notifications interface. csum = hashlib.sha256() # We base the decision to notify on whether these parameters have # changed (if csum is unchanged from previous notify, relation will # not fire). csum.update(settings.get('public_url', None)) csum.update(settings.get('admin_url', None)) csum.update(settings.get('internal_url', None)) notifications['%s-endpoint-changed' % (service)] = csum.hexdigest() else: # Each unit needs to set the db information otherwise if the unit # with the info dies the settings die with it Bug# 1355848 for rel_id in relation_ids('identity-service'): peerdb_settings = peer_retrieve_by_prefix(rel_id) # Ensure the null'd settings are unset in the relation. peerdb_settings = filter_null(peerdb_settings) if 'service_password' in peerdb_settings: relation_set(relation_id=rel_id, **peerdb_settings) log('Deferring identity_changed() to service leader.') if notifications: send_notifications(notifications)
def certs_changed(relation_id=None, unit=None): # update_all_identity_relation_units calls the keystone API # so configs need to be written and services restarted # before @restart_on_change(restart_map(), stopstart=True) def write_certs_and_config(): process_certificates('keystone', relation_id, unit) configure_https() write_certs_and_config() # If enabling https the identity endpoints need updating. if (is_db_initialised() and is_elected_leader(CLUSTER_RES) and not is_unit_paused_set()): ensure_initial_admin(config) update_all_identity_relation_units() update_all_domain_backends()
def ha_changed(): CONFIGS.write_all() clustered = relation_get('clustered') if clustered: log('Cluster configured, notifying other services and updating ' 'keystone endpoint configuration') for rid in relation_ids('certificates'): if related_units(rid): for unit in related_units(rid): certs_changed(rid, unit) if (is_db_initialised() and is_elected_leader(CLUSTER_RES) and not is_unit_paused_set()): ensure_initial_admin(config) update_all_identity_relation_units() update_all_domain_backends() update_all_fid_backends() inform_peers_if_ready(check_api_unit_ready)
def trustee_credentials_changed(relation_id=None, remote_unit=None): if is_elected_leader(CLUSTER_RES): if expect_ha() and not is_clustered(): log("Expected to be HA but no hacluster relation yet", level=INFO) return if not is_db_ready(): log("trustee-credentials-relation-changed hook fired before db " "ready - deferring until db ready", level=WARNING) return if not is_db_initialised(): log("Database not yet initialised - deferring " "trustee-credentials-relation updates", level=INFO) return # Create the tenant user add_trustee_credentials_to_keystone(relation_id, remote_unit) else: log('Deferring add_trustee_credentials_to_keystone() to service leader.')
def certs_changed(relation_id=None, unit=None): # update_all_identity_relation_units calls the keystone API # so configs need to be written and services restarted # before @restart_on_change(restart_map(), stopstart=True) def write_certs_and_config(): if process_certificates('keystone', relation_id, unit): configure_https() return True return False if not write_certs_and_config(): log('no certificates for us on the relation yet, deferring.', level=INFO) return # If enabling https the identity endpoints need updating. if (is_db_initialised() and is_elected_leader(CLUSTER_RES) and not is_unit_paused_set()): ensure_initial_admin(config) update_all_identity_relation_units() update_all_domain_backends()
def certs_changed(relation_id=None, unit=None): # update_all_identity_relation_units calls the keystone API # so configs need to be written and services restarted # before @restart_on_change(restart_map(), stopstart=True) def write_certs_and_config(): if process_certificates('keystone', relation_id, unit): configure_https() return True return False if not write_certs_and_config(): log('no certificates for us on the relation yet, deferring.', level=INFO) return # If enabling https the identity endpoints need updating. if (is_db_initialised() and is_elected_leader(CLUSTER_RES) and not is_unit_paused_set()): ensure_initial_admin(config) update_all_identity_relation_units() update_all_domain_backends() update_all_fid_backends() inform_peers_if_ready(check_api_unit_ready)