Refactoring to use openstack charm helpers
This commit is contained in:
parent
b22142ee63
commit
7ce1bb2dd7
@ -1 +1 @@
|
|||||||
keystone-hooks
|
keystone_hooks.py
|
@ -1 +1 @@
|
|||||||
keystone-hooks
|
keystone_hooks.py
|
@ -1 +1 @@
|
|||||||
keystone-hooks
|
keystone_hooks.py
|
@ -1 +1 @@
|
|||||||
keystone-hooks
|
keystone_hooks.py
|
@ -1 +1 @@
|
|||||||
keystone-hooks
|
keystone_hooks.py
|
@ -1 +1 @@
|
|||||||
keystone-hooks
|
keystone_hooks.py
|
@ -1 +1 @@
|
|||||||
keystone-hooks
|
keystone_hooks.py
|
@ -1 +1 @@
|
|||||||
keystone-hooks
|
keystone_hooks.py
|
@ -1 +1 @@
|
|||||||
keystone-hooks
|
keystone_hooks.py
|
@ -1,19 +1,53 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
import sys
|
import os
|
||||||
import time
|
import time
|
||||||
import urlparse
|
import urlparse
|
||||||
|
|
||||||
from base64 import b64encode
|
from base64 import b64encode
|
||||||
|
|
||||||
from utils import *
|
from keystone_utils import (
|
||||||
|
config_get,
|
||||||
|
execute,
|
||||||
|
update_config_block,
|
||||||
|
set_admin_token,
|
||||||
|
ensure_initial_admin,
|
||||||
|
relation_get_dict,
|
||||||
|
create_service_entry,
|
||||||
|
create_endpoint_template,
|
||||||
|
create_role,
|
||||||
|
get_admin_token,
|
||||||
|
get_service_password,
|
||||||
|
create_user,
|
||||||
|
grant_role,
|
||||||
|
get_ca,
|
||||||
|
synchronize_service_credentials,
|
||||||
|
do_openstack_upgrade,
|
||||||
|
configure_pki_tokens,
|
||||||
|
SSH_USER,
|
||||||
|
SSL_DIR,
|
||||||
|
CLUSTER_RES
|
||||||
|
)
|
||||||
|
|
||||||
from lib.openstack_common import *
|
from lib.openstack_common import (
|
||||||
|
configure_installation_source,
|
||||||
|
get_os_codename_install_source,
|
||||||
|
get_os_codename_package,
|
||||||
|
get_os_version_codename,
|
||||||
|
get_os_version_package,
|
||||||
|
save_script_rc
|
||||||
|
)
|
||||||
import lib.unison as unison
|
import lib.unison as unison
|
||||||
|
import lib.utils as utils
|
||||||
|
import lib.cluster_utils as cluster
|
||||||
|
import lib.haproxy_utils as haproxy
|
||||||
|
|
||||||
config = config_get()
|
config = config_get()
|
||||||
|
|
||||||
packages = "keystone python-mysqldb pwgen haproxy python-jinja2 openssl unison"
|
packages = [
|
||||||
|
"keystone", "python-mysqldb", "pwgen",
|
||||||
|
"haproxy", "python-jinja2", "openssl", "unison"
|
||||||
|
]
|
||||||
service = "keystone"
|
service = "keystone"
|
||||||
|
|
||||||
# used to verify joined services are valid openstack components.
|
# used to verify joined services are valid openstack components.
|
||||||
@ -62,13 +96,15 @@ valid_services = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def install_hook():
|
def install_hook():
|
||||||
if config["openstack-origin"] != "distro":
|
if config["openstack-origin"] != "distro":
|
||||||
configure_installation_source(config["openstack-origin"])
|
configure_installation_source(config["openstack-origin"])
|
||||||
execute("apt-get update", die=True)
|
utils.install(packages)
|
||||||
execute("apt-get -y install %s" % packages, die=True, echo=True)
|
update_config_block('DEFAULT',
|
||||||
update_config_block('DEFAULT', public_port=config["service-port"])
|
public_port=cluster.determine_api_port(config["service-port"]))
|
||||||
update_config_block('DEFAULT', admin_port=config["admin-port"])
|
update_config_block('DEFAULT',
|
||||||
|
admin_port=cluster.determine_api_port(config["admin-port"]))
|
||||||
set_admin_token(config['admin-token'])
|
set_admin_token(config['admin-token'])
|
||||||
|
|
||||||
# set all backends to use sql+sqlite, if they are not already by default
|
# set all backends to use sql+sqlite, if they are not already by default
|
||||||
@ -83,9 +119,9 @@ def install_hook():
|
|||||||
update_config_block('ec2',
|
update_config_block('ec2',
|
||||||
driver='keystone.contrib.ec2.backends.sql.Ec2')
|
driver='keystone.contrib.ec2.backends.sql.Ec2')
|
||||||
|
|
||||||
execute("service keystone stop", echo=True)
|
utils.stop('keystone')
|
||||||
execute("keystone-manage db_sync")
|
execute("keystone-manage db_sync")
|
||||||
execute("service keystone start", echo=True)
|
utils.start('keystone')
|
||||||
|
|
||||||
# ensure /var/lib/keystone is g+wrx for peer relations that
|
# ensure /var/lib/keystone is g+wrx for peer relations that
|
||||||
# may be syncing data there via SSH_USER.
|
# may be syncing data there via SSH_USER.
|
||||||
@ -96,17 +132,21 @@ def install_hook():
|
|||||||
|
|
||||||
|
|
||||||
def db_joined():
|
def db_joined():
|
||||||
relation_data = { "database": config["database"],
|
relation_data = {
|
||||||
"username": config["database-user"],
|
"database": config["database"],
|
||||||
"hostname": config["hostname"] }
|
"username": config["database-user"],
|
||||||
relation_set(relation_data)
|
"hostname": config["hostname"]
|
||||||
|
}
|
||||||
|
utils.relation_set(**relation_data)
|
||||||
|
|
||||||
|
|
||||||
def db_changed():
|
def db_changed():
|
||||||
relation_data = relation_get_dict()
|
relation_data = relation_get_dict()
|
||||||
if ('password' not in relation_data or
|
if ('password' not in relation_data or
|
||||||
'db_host' not in relation_data):
|
'db_host' not in relation_data):
|
||||||
juju_log("db_host or password not set. Peer not ready, exit 0")
|
utils.juju_log('INFO',
|
||||||
exit(0)
|
"db_host or password not set. Peer not ready, exit 0")
|
||||||
|
return
|
||||||
|
|
||||||
update_config_block('sql', connection="mysql://%s:%s@%s/%s" %
|
update_config_block('sql', connection="mysql://%s:%s@%s/%s" %
|
||||||
(config["database-user"],
|
(config["database-user"],
|
||||||
@ -114,15 +154,13 @@ def db_changed():
|
|||||||
relation_data["db_host"],
|
relation_data["db_host"],
|
||||||
config["database"]))
|
config["database"]))
|
||||||
|
|
||||||
execute("service keystone stop", echo=True)
|
utils.stop('keystone')
|
||||||
|
if cluster.eligible_leader(CLUSTER_RES):
|
||||||
|
utils.juju_log('INFO',
|
||||||
|
'Cluster leader, performing db-sync')
|
||||||
|
execute("keystone-manage db_sync", echo=True)
|
||||||
|
utils.start('keystone')
|
||||||
|
|
||||||
if not eligible_leader():
|
|
||||||
juju_log('Deferring DB initialization to service leader.')
|
|
||||||
execute("service keystone start")
|
|
||||||
return
|
|
||||||
|
|
||||||
execute("keystone-manage db_sync", echo=True)
|
|
||||||
execute("service keystone start")
|
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
ensure_initial_admin(config)
|
ensure_initial_admin(config)
|
||||||
|
|
||||||
@ -130,54 +168,46 @@ def db_changed():
|
|||||||
# are existing identity-service relations,, service entries need to be
|
# are existing identity-service relations,, service entries need to be
|
||||||
# recreated in the new database. Re-executing identity-service-changed
|
# recreated in the new database. Re-executing identity-service-changed
|
||||||
# will do this.
|
# will do this.
|
||||||
for id in relation_ids(relation_name='identity-service'):
|
for rid in utils.relation_ids('identity-service'):
|
||||||
for unit in relation_list(relation_id=id):
|
for unit in utils.relation_list(rid=rid):
|
||||||
juju_log("Re-exec'ing identity-service-changed for: %s - %s" %
|
utils.juju_log('INFO',
|
||||||
(id, unit))
|
"Re-exec'ing identity-service-changed"
|
||||||
identity_changed(relation_id=id, remote_unit=unit)
|
" for: %s - %s" % (rid, unit))
|
||||||
|
identity_changed(relation_id=rid, remote_unit=unit)
|
||||||
|
|
||||||
|
|
||||||
def ensure_valid_service(service):
|
def ensure_valid_service(service):
|
||||||
if service not in valid_services.keys():
|
if service not in valid_services.keys():
|
||||||
juju_log("WARN: Invalid service requested: '%s'" % service)
|
utils.juju_log('WARNING',
|
||||||
realtion_set({ "admin_token": -1 })
|
"Invalid service requested: '%s'" % service)
|
||||||
|
utils.relation_set(admin_token=-1)
|
||||||
return
|
return
|
||||||
|
|
||||||
def add_endpoint(region, service, public_url, admin_url, internal_url):
|
|
||||||
|
def add_endpoint(region, service, publicurl, adminurl, internalurl):
|
||||||
desc = valid_services[service]["desc"]
|
desc = valid_services[service]["desc"]
|
||||||
service_type = valid_services[service]["type"]
|
service_type = valid_services[service]["type"]
|
||||||
create_service_entry(service, service_type, desc)
|
create_service_entry(service, service_type, desc)
|
||||||
create_endpoint_template(region=region, service=service,
|
create_endpoint_template(region=region, service=service,
|
||||||
public_url=public_url,
|
publicurl=publicurl,
|
||||||
admin_url=admin_url,
|
adminurl=adminurl,
|
||||||
internal_url=internal_url)
|
internalurl=internalurl)
|
||||||
|
|
||||||
|
|
||||||
def identity_joined():
|
def identity_joined():
|
||||||
""" Do nothing until we get information about requested service """
|
""" Do nothing until we get information about requested service """
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def identity_changed(relation_id=None, remote_unit=None):
|
def identity_changed(relation_id=None, remote_unit=None):
|
||||||
""" A service has advertised its API endpoints, create an entry in the
|
""" A service has advertised its API endpoints, create an entry in the
|
||||||
service catalog.
|
service catalog.
|
||||||
Optionally allow this hook to be re-fired for an existing
|
Optionally allow this hook to be re-fired for an existing
|
||||||
relation+unit, for context see see db_changed().
|
relation+unit, for context see see db_changed().
|
||||||
"""
|
"""
|
||||||
def ensure_valid_service(service):
|
if not cluster.eligible_leader(CLUSTER_RES):
|
||||||
if service not in valid_services.keys():
|
utils.juju_log('INFO',
|
||||||
juju_log("WARN: Invalid service requested: '%s'" % service)
|
'Deferring identity_changed() to service leader.')
|
||||||
realtion_set({ "admin_token": -1 })
|
|
||||||
return
|
|
||||||
|
|
||||||
def add_endpoint(region, service, publicurl, adminurl, internalurl):
|
|
||||||
desc = valid_services[service]["desc"]
|
|
||||||
service_type = valid_services[service]["type"]
|
|
||||||
create_service_entry(service, service_type, desc)
|
|
||||||
create_endpoint_template(region=region, service=service,
|
|
||||||
publicurl=publicurl,
|
|
||||||
adminurl=adminurl,
|
|
||||||
internalurl=internalurl)
|
|
||||||
|
|
||||||
if not eligible_leader():
|
|
||||||
juju_log('Deferring identity_changed() to service leader.')
|
|
||||||
return
|
return
|
||||||
|
|
||||||
settings = relation_get_dict(relation_id=relation_id,
|
settings = relation_get_dict(relation_id=relation_id,
|
||||||
@ -187,7 +217,8 @@ def identity_changed(relation_id=None, remote_unit=None):
|
|||||||
# Currently used by Swift.
|
# Currently used by Swift.
|
||||||
if 'requested_roles' in settings and settings['requested_roles'] != 'None':
|
if 'requested_roles' in settings and settings['requested_roles'] != 'None':
|
||||||
roles = settings['requested_roles'].split(',')
|
roles = settings['requested_roles'].split(',')
|
||||||
juju_log("Creating requested roles: %s" % roles)
|
utils.juju_log('INFO',
|
||||||
|
"Creating requested roles: %s" % roles)
|
||||||
for role in roles:
|
for role in roles:
|
||||||
create_role(role, user=config['admin-user'], tenant='admin')
|
create_role(role, user=config['admin-user'], tenant='admin')
|
||||||
|
|
||||||
@ -196,25 +227,22 @@ def identity_changed(relation_id=None, remote_unit=None):
|
|||||||
'internal_url'])
|
'internal_url'])
|
||||||
if single.issubset(settings):
|
if single.issubset(settings):
|
||||||
# other end of relation advertised only one endpoint
|
# other end of relation advertised only one endpoint
|
||||||
if 'None' in [v for k,v in settings.iteritems()]:
|
if 'None' in [v for k, v in settings.iteritems()]:
|
||||||
# Some backend services advertise no endpoint but require a
|
# Some backend services advertise no endpoint but require a
|
||||||
# hook execution to update auth strategy.
|
# hook execution to update auth strategy.
|
||||||
relation_data = {}
|
relation_data = {}
|
||||||
# Check if clustered and use vip + haproxy ports if so
|
# Check if clustered and use vip + haproxy ports if so
|
||||||
if is_clustered():
|
if cluster.is_clustered():
|
||||||
relation_data["auth_host"] = config['vip']
|
relation_data["auth_host"] = config['vip']
|
||||||
relation_data["auth_port"] = SERVICE_PORTS['keystone_admin']
|
|
||||||
relation_data["service_host"] = config['vip']
|
relation_data["service_host"] = config['vip']
|
||||||
relation_data["service_port"] = SERVICE_PORTS['keystone_service']
|
|
||||||
else:
|
else:
|
||||||
relation_data["auth_host"] = config['hostname']
|
relation_data["auth_host"] = config['hostname']
|
||||||
relation_data["auth_port"] = config['admin-port']
|
|
||||||
relation_data["service_host"] = config['hostname']
|
relation_data["service_host"] = config['hostname']
|
||||||
relation_data["service_port"] = config['service-port']
|
relation_data["auth_port"] = config['admin-port']
|
||||||
relation_set(relation_data)
|
relation_data["service_port"] = config['service-port']
|
||||||
|
utils.relation_set(**relation_data)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
ensure_valid_service(settings['service'])
|
ensure_valid_service(settings['service'])
|
||||||
|
|
||||||
add_endpoint(region=settings['region'], service=settings['service'],
|
add_endpoint(region=settings['region'], service=settings['service'],
|
||||||
@ -242,7 +270,7 @@ def identity_changed(relation_id=None, remote_unit=None):
|
|||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
endpoints = {}
|
endpoints = {}
|
||||||
for k,v in settings.iteritems():
|
for k, v in settings.iteritems():
|
||||||
ep = k.split('_')[0]
|
ep = k.split('_')[0]
|
||||||
x = '_'.join(k.split('_')[1:])
|
x = '_'.join(k.split('_')[1:])
|
||||||
if ep not in endpoints:
|
if ep not in endpoints:
|
||||||
@ -267,18 +295,20 @@ def identity_changed(relation_id=None, remote_unit=None):
|
|||||||
https_cn = https_cn.hostname
|
https_cn = https_cn.hostname
|
||||||
service_username = '_'.join(services)
|
service_username = '_'.join(services)
|
||||||
|
|
||||||
if 'None' in [v for k,v in settings.iteritems()]:
|
if 'None' in [v for k, v in settings.iteritems()]:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not service_username:
|
if not service_username:
|
||||||
return
|
return
|
||||||
|
|
||||||
token = get_admin_token()
|
token = get_admin_token()
|
||||||
juju_log("Creating service credentials for '%s'" % service_username)
|
utils.juju_log('INFO',
|
||||||
|
"Creating service credentials for '%s'" % service_username)
|
||||||
|
|
||||||
service_password = get_service_password(service_username)
|
service_password = get_service_password(service_username)
|
||||||
create_user(service_username, service_password, config['service-tenant'])
|
create_user(service_username, service_password, config['service-tenant'])
|
||||||
grant_role(service_username, config['admin-role'], config['service-tenant'])
|
grant_role(service_username, config['admin-role'],
|
||||||
|
config['service-tenant'])
|
||||||
|
|
||||||
# As of https://review.openstack.org/#change,4675, all nodes hosting
|
# As of https://review.openstack.org/#change,4675, all nodes hosting
|
||||||
# an endpoint(s) needs a service username and password assigned to
|
# an endpoint(s) needs a service username and password assigned to
|
||||||
@ -305,27 +335,25 @@ def identity_changed(relation_id=None, remote_unit=None):
|
|||||||
relation_data['rid'] = relation_id
|
relation_data['rid'] = relation_id
|
||||||
|
|
||||||
# Check if clustered and use vip + haproxy ports if so
|
# Check if clustered and use vip + haproxy ports if so
|
||||||
if is_clustered():
|
if cluster.is_clustered():
|
||||||
relation_data["auth_host"] = config['vip']
|
relation_data["auth_host"] = config['vip']
|
||||||
relation_data["auth_port"] = SERVICE_PORTS['keystone_admin']
|
|
||||||
relation_data["service_host"] = config['vip']
|
relation_data["service_host"] = config['vip']
|
||||||
relation_data["service_port"] = SERVICE_PORTS['keystone_service']
|
|
||||||
|
|
||||||
# generate or get a new cert/key for service if set to manage certs.
|
# generate or get a new cert/key for service if set to manage certs.
|
||||||
if config['https-service-endpoints'] in ['True', 'true']:
|
if config['https-service-endpoints'] in ['True', 'true']:
|
||||||
ca = get_ca(user=SSH_USER)
|
ca = get_ca(user=SSH_USER)
|
||||||
service = os.getenv('JUJU_REMOTE_UNIT').split('/')[0]
|
|
||||||
cert, key = ca.get_cert_and_key(common_name=https_cn)
|
cert, key = ca.get_cert_and_key(common_name=https_cn)
|
||||||
ca_bundle= ca.get_ca_bundle()
|
ca_bundle = ca.get_ca_bundle()
|
||||||
relation_data['ssl_cert'] = b64encode(cert)
|
relation_data['ssl_cert'] = b64encode(cert)
|
||||||
relation_data['ssl_key'] = b64encode(key)
|
relation_data['ssl_key'] = b64encode(key)
|
||||||
relation_data['ca_cert'] = b64encode(ca_bundle)
|
relation_data['ca_cert'] = b64encode(ca_bundle)
|
||||||
relation_data['https_keystone'] = 'True'
|
relation_data['https_keystone'] = 'True'
|
||||||
unison.sync_to_peers(peer_interface='cluster',
|
unison.sync_to_peers(peer_interface='cluster',
|
||||||
paths=[SSL_DIR], user=SSH_USER, verbose=True)
|
paths=[SSL_DIR], user=SSH_USER, verbose=True)
|
||||||
relation_set_2(**relation_data)
|
utils.relation_set(**relation_data)
|
||||||
synchronize_service_credentials()
|
synchronize_service_credentials()
|
||||||
|
|
||||||
|
|
||||||
def config_changed():
|
def config_changed():
|
||||||
|
|
||||||
# Determine whether or not we should do an upgrade, based on the
|
# Determine whether or not we should do an upgrade, based on the
|
||||||
@ -334,7 +362,8 @@ def config_changed():
|
|||||||
installed = get_os_codename_package('keystone')
|
installed = get_os_codename_package('keystone')
|
||||||
|
|
||||||
if (available and
|
if (available and
|
||||||
get_os_version_codename(available) > get_os_version_codename(installed)):
|
get_os_version_codename(available) > \
|
||||||
|
get_os_version_codename(installed)):
|
||||||
do_openstack_upgrade(config['openstack-origin'], packages)
|
do_openstack_upgrade(config['openstack-origin'], packages)
|
||||||
|
|
||||||
env_vars = {'OPENSTACK_SERVICE_KEYSTONE': 'keystone',
|
env_vars = {'OPENSTACK_SERVICE_KEYSTONE': 'keystone',
|
||||||
@ -344,8 +373,10 @@ def config_changed():
|
|||||||
|
|
||||||
set_admin_token(config['admin-token'])
|
set_admin_token(config['admin-token'])
|
||||||
|
|
||||||
if eligible_leader():
|
if cluster.eligible_leader(CLUSTER_RES):
|
||||||
juju_log('Cluster leader - ensuring endpoint configuration is up to date')
|
utils.juju_log('INFO',
|
||||||
|
'Cluster leader - ensuring endpoint configuration'
|
||||||
|
' is up to date')
|
||||||
ensure_initial_admin(config)
|
ensure_initial_admin(config)
|
||||||
|
|
||||||
update_config_block('logger_root', level=config['log-level'],
|
update_config_block('logger_root', level=config['log-level'],
|
||||||
@ -354,69 +385,68 @@ def config_changed():
|
|||||||
# PKI introduced in Grizzly
|
# PKI introduced in Grizzly
|
||||||
configure_pki_tokens(config)
|
configure_pki_tokens(config)
|
||||||
|
|
||||||
execute("service keystone restart", echo=True)
|
utils.restart('keystone')
|
||||||
cluster_changed()
|
cluster_changed()
|
||||||
|
|
||||||
|
|
||||||
def upgrade_charm():
|
def upgrade_charm():
|
||||||
cluster_changed()
|
cluster_changed()
|
||||||
if eligible_leader():
|
if cluster.eligible_leader(CLUSTER_RES):
|
||||||
juju_log('Cluster leader - ensuring endpoint configuration is up to date')
|
utils.juju_log('INFO',
|
||||||
|
'Cluster leader - ensuring endpoint configuration'
|
||||||
|
' is up to date')
|
||||||
ensure_initial_admin(config)
|
ensure_initial_admin(config)
|
||||||
|
|
||||||
|
|
||||||
SERVICE_PORTS = {
|
|
||||||
"keystone_admin": int(config['admin-port']) + 1,
|
|
||||||
"keystone_service": int(config['service-port']) + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
def cluster_joined():
|
def cluster_joined():
|
||||||
unison.ssh_authorized_peers(user=SSH_USER,
|
unison.ssh_authorized_peers(user=SSH_USER,
|
||||||
group='keystone',
|
group='keystone',
|
||||||
peer_interface='cluster',
|
peer_interface='cluster',
|
||||||
ensure_user=True)
|
ensure_user=True)
|
||||||
|
update_config_block('DEFAULT',
|
||||||
|
public_port=cluster.determine_api_port(config["service-port"]))
|
||||||
|
update_config_block('DEFAULT',
|
||||||
|
admin_port=cluster.determine_api_port(config["admin-port"]))
|
||||||
|
utils.restart('keystone')
|
||||||
|
service_ports = {
|
||||||
|
"keystone_admin": \
|
||||||
|
cluster.determine_haproxy_port(config['admin-port']),
|
||||||
|
"keystone_service": \
|
||||||
|
cluster.determine_haproxy_port(config['service-port'])
|
||||||
|
}
|
||||||
|
haproxy.configure_haproxy(service_ports)
|
||||||
|
|
||||||
|
|
||||||
def cluster_changed():
|
def cluster_changed():
|
||||||
unison.ssh_authorized_peers(user=SSH_USER,
|
unison.ssh_authorized_peers(user=SSH_USER,
|
||||||
group='keystone',
|
group='keystone',
|
||||||
peer_interface='cluster',
|
peer_interface='cluster',
|
||||||
ensure_user=True)
|
ensure_user=True)
|
||||||
cluster_hosts = {}
|
|
||||||
cluster_hosts['self'] = config['hostname']
|
|
||||||
for r_id in relation_ids('cluster'):
|
|
||||||
for unit in relation_list(r_id):
|
|
||||||
# trigger identity-changed to reconfigure HTTPS
|
|
||||||
# as necessary.
|
|
||||||
identity_changed(relation_id=r_id, remote_unit=unit)
|
|
||||||
cluster_hosts[unit.replace('/','-')] = \
|
|
||||||
relation_get_dict(relation_id=r_id,
|
|
||||||
remote_unit=unit)['private-address']
|
|
||||||
configure_haproxy(cluster_hosts,
|
|
||||||
SERVICE_PORTS)
|
|
||||||
|
|
||||||
synchronize_service_credentials()
|
synchronize_service_credentials()
|
||||||
|
service_ports = {
|
||||||
|
"keystone_admin": \
|
||||||
|
cluster.determine_haproxy_port(config['admin-port']),
|
||||||
|
"keystone_service": \
|
||||||
|
cluster.determine_haproxy_port(config['service-port'])
|
||||||
|
}
|
||||||
|
haproxy.configure_haproxy(service_ports)
|
||||||
|
|
||||||
for r_id in relation_ids('identity-service'):
|
|
||||||
for unit in relation_list(r_id):
|
|
||||||
# trigger identity-changed to reconfigure HTTPS as necessary
|
|
||||||
identity_changed(relation_id=r_id, remote_unit=unit)
|
|
||||||
|
|
||||||
def ha_relation_changed():
|
def ha_relation_changed():
|
||||||
relation_data = relation_get_dict()
|
relation_data = relation_get_dict()
|
||||||
if ('clustered' in relation_data and
|
if ('clustered' in relation_data and
|
||||||
is_leader()):
|
cluster.is_leader(CLUSTER_RES)):
|
||||||
juju_log('Cluster configured, notifying other services and updating'
|
utils.juju_log('INFO',
|
||||||
'keystone endpoint configuration')
|
'Cluster configured, notifying other services'
|
||||||
|
' and updating keystone endpoint configuration')
|
||||||
# Update keystone endpoint to point at VIP
|
# Update keystone endpoint to point at VIP
|
||||||
ensure_initial_admin(config)
|
ensure_initial_admin(config)
|
||||||
# Tell all related services to start using
|
# Tell all related services to start using
|
||||||
# the VIP and haproxy ports instead
|
# the VIP and haproxy ports instead
|
||||||
for r_id in relation_ids('identity-service'):
|
for r_id in utils.relation_ids('identity-service'):
|
||||||
relation_set_2(rid=r_id,
|
utils.relation_set(rid=r_id,
|
||||||
auth_host=config['vip'],
|
auth_host=config['vip'],
|
||||||
service_host=config['vip'],
|
service_host=config['vip'])
|
||||||
service_port=SERVICE_PORTS['keystone_service'],
|
|
||||||
auth_port=SERVICE_PORTS['keystone_admin'])
|
|
||||||
|
|
||||||
|
|
||||||
def ha_relation_joined():
|
def ha_relation_joined():
|
||||||
@ -424,41 +454,33 @@ def ha_relation_joined():
|
|||||||
# include multicast port and interface to bind to.
|
# include multicast port and interface to bind to.
|
||||||
corosync_bindiface = config['ha-bindiface']
|
corosync_bindiface = config['ha-bindiface']
|
||||||
corosync_mcastport = config['ha-mcastport']
|
corosync_mcastport = config['ha-mcastport']
|
||||||
|
vip = config['vip']
|
||||||
|
vip_cidr = config['vip_cidr']
|
||||||
|
vip_iface = config['vip_iface']
|
||||||
|
|
||||||
# Obtain resources
|
# Obtain resources
|
||||||
resources = {
|
resources = {
|
||||||
'res_ks_vip':'ocf:heartbeat:IPaddr2',
|
'res_ks_vip': 'ocf:heartbeat:IPaddr2',
|
||||||
'res_ks_haproxy':'lsb:haproxy'
|
'res_ks_haproxy': 'lsb:haproxy'
|
||||||
}
|
}
|
||||||
# TODO: Obtain netmask and nic where to place VIP.
|
|
||||||
resource_params = {
|
resource_params = {
|
||||||
'res_ks_vip':'params ip="%s" cidr_netmask="%s" nic="%s"' % (config['vip'],
|
'res_ks_vip': 'params ip="%s" cidr_netmask="%s" nic="%s"' % \
|
||||||
config['vip_cidr'], config['vip_iface']),
|
(vip, vip_cidr, vip_iface),
|
||||||
'res_ks_haproxy':'op monitor interval="5s"'
|
'res_ks_haproxy': 'op monitor interval="5s"'
|
||||||
}
|
}
|
||||||
init_services = {
|
init_services = {
|
||||||
'res_ks_haproxy':'haproxy'
|
'res_ks_haproxy': 'haproxy'
|
||||||
}
|
}
|
||||||
groups = {
|
clones = {
|
||||||
'grp_ks_haproxy':'res_ks_vip res_ks_haproxy'
|
'gl_ks_haproxy': 'res_ks_haproxy'
|
||||||
}
|
}
|
||||||
#clones = {
|
|
||||||
# 'cln_ks_haproxy':'res_ks_haproxy meta globally-unique="false" interleave="true"'
|
|
||||||
# }
|
|
||||||
|
|
||||||
#orders = {
|
utils.relation_set(init_services=init_services,
|
||||||
# 'ord_vip_before_haproxy':'inf: res_ks_vip res_ks_haproxy'
|
corosync_bindiface=corosync_bindiface,
|
||||||
# }
|
corosync_mcastport=corosync_mcastport,
|
||||||
#colocations = {
|
resources=resources,
|
||||||
# 'col_vip_on_haproxy':'inf: res_ks_haproxy res_ks_vip'
|
resource_params=resource_params,
|
||||||
# }
|
clones=clones)
|
||||||
|
|
||||||
relation_set_2(init_services=init_services,
|
|
||||||
corosync_bindiface=corosync_bindiface,
|
|
||||||
corosync_mcastport=corosync_mcastport,
|
|
||||||
resources=resources,
|
|
||||||
resource_params=resource_params,
|
|
||||||
groups=groups)
|
|
||||||
|
|
||||||
|
|
||||||
hooks = {
|
hooks = {
|
||||||
@ -476,9 +498,4 @@ hooks = {
|
|||||||
"upgrade-charm": upgrade_charm
|
"upgrade-charm": upgrade_charm
|
||||||
}
|
}
|
||||||
|
|
||||||
# keystone-hooks gets called by symlink corresponding to the requested relation
|
utils.do_hooks(hooks)
|
||||||
# hook.
|
|
||||||
hook = os.path.basename(sys.argv[0])
|
|
||||||
if hook not in hooks.keys():
|
|
||||||
error_out("Unsupported hook: %s" % hook)
|
|
||||||
hooks[hook]()
|
|
@ -1,17 +1,23 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
import ConfigParser
|
import ConfigParser
|
||||||
import subprocess
|
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import os
|
|
||||||
import tarfile
|
|
||||||
import tempfile
|
|
||||||
import time
|
import time
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
|
||||||
from lib.openstack_common import *
|
from lib.openstack_common import(
|
||||||
|
get_os_codename_install_source,
|
||||||
|
get_os_codename_package,
|
||||||
|
error_out,
|
||||||
|
configure_installation_source
|
||||||
|
)
|
||||||
|
|
||||||
import keystone_ssl as ssl
|
import keystone_ssl as ssl
|
||||||
import lib.unison as unison
|
import lib.unison as unison
|
||||||
|
import lib.utils as utils
|
||||||
|
import lib.cluster_utils as cluster
|
||||||
|
|
||||||
|
|
||||||
keystone_conf = "/etc/keystone/keystone.conf"
|
keystone_conf = "/etc/keystone/keystone.conf"
|
||||||
stored_passwd = "/var/lib/keystone/keystone.passwd"
|
stored_passwd = "/var/lib/keystone/keystone.passwd"
|
||||||
@ -20,8 +26,9 @@ SERVICE_PASSWD_PATH = '/var/lib/keystone/services.passwd'
|
|||||||
|
|
||||||
SSL_DIR = '/var/lib/keystone/juju_ssl/'
|
SSL_DIR = '/var/lib/keystone/juju_ssl/'
|
||||||
SSL_CA_NAME = 'Ubuntu Cloud'
|
SSL_CA_NAME = 'Ubuntu Cloud'
|
||||||
|
CLUSTER_RES = 'res_ks_vip'
|
||||||
|
SSH_USER = 'juju_keystone'
|
||||||
|
|
||||||
SSH_USER='juju_keystone'
|
|
||||||
|
|
||||||
def execute(cmd, die=False, echo=False):
|
def execute(cmd, die=False, echo=False):
|
||||||
""" Executes a command
|
""" Executes a command
|
||||||
@ -35,8 +42,8 @@ def execute(cmd, die=False, echo=False):
|
|||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stdin=subprocess.PIPE,
|
stdin=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE)
|
stderr=subprocess.PIPE)
|
||||||
stdout=""
|
stdout = ""
|
||||||
stderr=""
|
stderr = ""
|
||||||
|
|
||||||
def print_line(l):
|
def print_line(l):
|
||||||
if echo:
|
if echo:
|
||||||
@ -59,7 +66,7 @@ def execute(cmd, die=False, echo=False):
|
|||||||
|
|
||||||
|
|
||||||
def config_get():
|
def config_get():
|
||||||
""" Obtain the units config via 'config-get'
|
""" Obtain the units config via 'config-get'
|
||||||
Returns a dict representing current config.
|
Returns a dict representing current config.
|
||||||
private-address and IP of the unit is also tacked on for
|
private-address and IP of the unit is also tacked on for
|
||||||
convienence
|
convienence
|
||||||
@ -68,71 +75,12 @@ def config_get():
|
|||||||
config = json.loads(output)
|
config = json.loads(output)
|
||||||
# make sure no config element is blank after config-get
|
# make sure no config element is blank after config-get
|
||||||
for c in config.keys():
|
for c in config.keys():
|
||||||
if not config[c]:
|
if not config[c]:
|
||||||
error_out("ERROR: Config option has no paramter: %s" % c)
|
error_out("ERROR: Config option has no paramter: %s" % c)
|
||||||
# tack on our private address and ip
|
# tack on our private address and ip
|
||||||
hostname = execute("unit-get private-address")[0].strip()
|
config["hostname"] = utils.unit_get('private-address')
|
||||||
config["hostname"] = execute("unit-get private-address")[0].strip()
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def relation_ids(relation_name=None):
|
|
||||||
j = execute('relation-ids --format=json %s' % relation_name)[0]
|
|
||||||
return json.loads(j)
|
|
||||||
|
|
||||||
def relation_list(relation_id=None):
|
|
||||||
cmd = 'relation-list --format=json'
|
|
||||||
if relation_id:
|
|
||||||
cmd += ' -r %s' % relation_id
|
|
||||||
j = execute(cmd)[0]
|
|
||||||
return json.loads(j)
|
|
||||||
|
|
||||||
def relation_set(relation_data):
|
|
||||||
""" calls relation-set for all key=values in dict """
|
|
||||||
for k in relation_data:
|
|
||||||
execute("relation-set %s=%s" % (k, relation_data[k]), die=True)
|
|
||||||
|
|
||||||
def relation_set_2(**kwargs):
|
|
||||||
cmd = [
|
|
||||||
'relation-set'
|
|
||||||
]
|
|
||||||
args = []
|
|
||||||
for k, v in kwargs.items():
|
|
||||||
if k == 'rid':
|
|
||||||
cmd.append('-r')
|
|
||||||
cmd.append(v)
|
|
||||||
else:
|
|
||||||
args.append('{}={}'.format(k, v))
|
|
||||||
cmd += args
|
|
||||||
subprocess.check_call(cmd)
|
|
||||||
|
|
||||||
|
|
||||||
def unit_get(attribute):
|
|
||||||
cmd = [
|
|
||||||
'unit-get',
|
|
||||||
attribute
|
|
||||||
]
|
|
||||||
value = subprocess.check_output(cmd).strip() # IGNORE:E1103
|
|
||||||
if value == "":
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
def relation_get(relation_data):
|
|
||||||
""" Obtain all current relation data
|
|
||||||
relation_data is a list of options to query from the relation
|
|
||||||
Returns a k,v dict of the results.
|
|
||||||
Leave empty responses out of the results as they haven't yet been
|
|
||||||
set on the other end.
|
|
||||||
Caller can then "len(results.keys()) == len(relation_data)" to find out if
|
|
||||||
all relation values have been set on the other side
|
|
||||||
"""
|
|
||||||
results = {}
|
|
||||||
for r in relation_data:
|
|
||||||
result = execute("relation-get %s" % r, die=True)[0].strip('\n')
|
|
||||||
if result != "":
|
|
||||||
results[r] = result
|
|
||||||
return results
|
|
||||||
|
|
||||||
def relation_get_dict(relation_id=None, remote_unit=None):
|
def relation_get_dict(relation_id=None, remote_unit=None):
|
||||||
"""Obtain all relation data as dict by way of JSON"""
|
"""Obtain all relation data as dict by way of JSON"""
|
||||||
@ -152,18 +100,23 @@ def relation_get_dict(relation_id=None, remote_unit=None):
|
|||||||
settings[str(k)] = str(v)
|
settings[str(k)] = str(v)
|
||||||
return settings
|
return settings
|
||||||
|
|
||||||
|
|
||||||
def set_admin_token(admin_token):
|
def set_admin_token(admin_token):
|
||||||
"""Set admin token according to deployment config or use a randomly
|
"""Set admin token according to deployment config or use a randomly
|
||||||
generated token if none is specified (default).
|
generated token if none is specified (default).
|
||||||
"""
|
"""
|
||||||
if admin_token != 'None':
|
if admin_token != 'None':
|
||||||
juju_log('Configuring Keystone to use a pre-configured admin token.')
|
utils.juju_log('INFO',
|
||||||
|
'Configuring Keystone to use'
|
||||||
|
' a pre-configured admin token.')
|
||||||
token = admin_token
|
token = admin_token
|
||||||
else:
|
else:
|
||||||
juju_log('Configuring Keystone to use a random admin token.')
|
utils.juju_log('INFO',
|
||||||
|
'Configuring Keystone to use a random admin token.')
|
||||||
if os.path.isfile(stored_token):
|
if os.path.isfile(stored_token):
|
||||||
msg = 'Loading a previously generated admin token from %s' % stored_token
|
msg = 'Loading a previously generated' \
|
||||||
juju_log(msg)
|
' admin token from %s' % stored_token
|
||||||
|
utils.juju_log('INFO', msg)
|
||||||
f = open(stored_token, 'r')
|
f = open(stored_token, 'r')
|
||||||
token = f.read().strip()
|
token = f.read().strip()
|
||||||
f.close()
|
f.close()
|
||||||
@ -174,6 +127,7 @@ def set_admin_token(admin_token):
|
|||||||
out.close()
|
out.close()
|
||||||
update_config_block('DEFAULT', admin_token=token)
|
update_config_block('DEFAULT', admin_token=token)
|
||||||
|
|
||||||
|
|
||||||
def get_admin_token():
|
def get_admin_token():
|
||||||
"""Temporary utility to grab the admin token as configured in
|
"""Temporary utility to grab the admin token as configured in
|
||||||
keystone.conf
|
keystone.conf
|
||||||
@ -188,6 +142,7 @@ def get_admin_token():
|
|||||||
keystone_conf)
|
keystone_conf)
|
||||||
error_out('Could not find admin_token line in %s' % keystone_conf)
|
error_out('Could not find admin_token line in %s' % keystone_conf)
|
||||||
|
|
||||||
|
|
||||||
def update_config_block(section, **kwargs):
|
def update_config_block(section, **kwargs):
|
||||||
""" Updates keystone.conf blocks given kwargs.
|
""" Updates keystone.conf blocks given kwargs.
|
||||||
Update a config setting in a specific setting of a config
|
Update a config setting in a specific setting of a config
|
||||||
@ -209,6 +164,7 @@ def update_config_block(section, **kwargs):
|
|||||||
with open(conf_file, 'wb') as out:
|
with open(conf_file, 'wb') as out:
|
||||||
config.write(out)
|
config.write(out)
|
||||||
|
|
||||||
|
|
||||||
def create_service_entry(service_name, service_type, service_desc, owner=None):
|
def create_service_entry(service_name, service_type, service_desc, owner=None):
|
||||||
""" Add a new service entry to keystone if one does not already exist """
|
""" Add a new service entry to keystone if one does not already exist """
|
||||||
import manager
|
import manager
|
||||||
@ -216,12 +172,15 @@ def create_service_entry(service_name, service_type, service_desc, owner=None):
|
|||||||
token=get_admin_token())
|
token=get_admin_token())
|
||||||
for service in [s._info for s in manager.api.services.list()]:
|
for service in [s._info for s in manager.api.services.list()]:
|
||||||
if service['name'] == service_name:
|
if service['name'] == service_name:
|
||||||
juju_log("Service entry for '%s' already exists." % service_name)
|
utils.juju_log('INFO',
|
||||||
|
"Service entry for '%s' already exists." % \
|
||||||
|
service_name)
|
||||||
return
|
return
|
||||||
manager.api.services.create(name=service_name,
|
manager.api.services.create(name=service_name,
|
||||||
service_type=service_type,
|
service_type=service_type,
|
||||||
description=service_desc)
|
description=service_desc)
|
||||||
juju_log("Created new service entry '%s'" % service_name)
|
utils.juju_log('INFO', "Created new service entry '%s'" % service_name)
|
||||||
|
|
||||||
|
|
||||||
def create_endpoint_template(region, service, publicurl, adminurl,
|
def create_endpoint_template(region, service, publicurl, adminurl,
|
||||||
internalurl):
|
internalurl):
|
||||||
@ -233,8 +192,9 @@ def create_endpoint_template(region, service, publicurl, adminurl,
|
|||||||
service_id = manager.resolve_service_id(service)
|
service_id = manager.resolve_service_id(service)
|
||||||
for ep in [e._info for e in manager.api.endpoints.list()]:
|
for ep in [e._info for e in manager.api.endpoints.list()]:
|
||||||
if ep['service_id'] == service_id and ep['region'] == region:
|
if ep['service_id'] == service_id and ep['region'] == region:
|
||||||
juju_log("Endpoint template already exists for '%s' in '%s'"
|
utils.juju_log('INFO',
|
||||||
% (service, region))
|
"Endpoint template already exists for '%s' in '%s'"
|
||||||
|
% (service, region))
|
||||||
|
|
||||||
up_to_date = True
|
up_to_date = True
|
||||||
for k in ['publicurl', 'adminurl', 'internalurl']:
|
for k in ['publicurl', 'adminurl', 'internalurl']:
|
||||||
@ -245,7 +205,9 @@ def create_endpoint_template(region, service, publicurl, adminurl,
|
|||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
# delete endpoint and recreate if endpoint urls need updating.
|
# delete endpoint and recreate if endpoint urls need updating.
|
||||||
juju_log("Updating endpoint template with new endpoint urls.")
|
utils.juju_log('INFO',
|
||||||
|
"Updating endpoint template with"
|
||||||
|
" new endpoint urls.")
|
||||||
manager.api.endpoints.delete(ep['id'])
|
manager.api.endpoints.delete(ep['id'])
|
||||||
|
|
||||||
manager.api.endpoints.create(region=region,
|
manager.api.endpoints.create(region=region,
|
||||||
@ -253,8 +215,9 @@ def create_endpoint_template(region, service, publicurl, adminurl,
|
|||||||
publicurl=publicurl,
|
publicurl=publicurl,
|
||||||
adminurl=adminurl,
|
adminurl=adminurl,
|
||||||
internalurl=internalurl)
|
internalurl=internalurl)
|
||||||
juju_log("Created new endpoint template for '%s' in '%s'" %
|
utils.juju_log('INFO', "Created new endpoint template for '%s' in '%s'" %
|
||||||
(region, service))
|
(region, service))
|
||||||
|
|
||||||
|
|
||||||
def create_tenant(name):
|
def create_tenant(name):
|
||||||
""" creates a tenant if it does not already exist """
|
""" creates a tenant if it does not already exist """
|
||||||
@ -265,9 +228,10 @@ def create_tenant(name):
|
|||||||
if not tenants or name not in [t['name'] for t in tenants]:
|
if not tenants or name not in [t['name'] for t in tenants]:
|
||||||
manager.api.tenants.create(tenant_name=name,
|
manager.api.tenants.create(tenant_name=name,
|
||||||
description='Created by Juju')
|
description='Created by Juju')
|
||||||
juju_log("Created new tenant: %s" % name)
|
utils.juju_log('INFO', "Created new tenant: %s" % name)
|
||||||
return
|
return
|
||||||
juju_log("Tenant '%s' already exists." % name)
|
utils.juju_log('INFO', "Tenant '%s' already exists." % name)
|
||||||
|
|
||||||
|
|
||||||
def create_user(name, password, tenant):
|
def create_user(name, password, tenant):
|
||||||
""" creates a user if it doesn't already exist, as a member of tenant """
|
""" creates a user if it doesn't already exist, as a member of tenant """
|
||||||
@ -283,9 +247,11 @@ def create_user(name, password, tenant):
|
|||||||
password=password,
|
password=password,
|
||||||
email='juju@localhost',
|
email='juju@localhost',
|
||||||
tenant_id=tenant_id)
|
tenant_id=tenant_id)
|
||||||
juju_log("Created new user '%s' tenant: %s" % (name, tenant_id))
|
utils.juju_log('INFO', "Created new user '%s' tenant: %s" % \
|
||||||
|
(name, tenant_id))
|
||||||
return
|
return
|
||||||
juju_log("A user named '%s' already exists" % name)
|
utils.juju_log('INFO', "A user named '%s' already exists" % name)
|
||||||
|
|
||||||
|
|
||||||
def create_role(name, user=None, tenant=None):
|
def create_role(name, user=None, tenant=None):
|
||||||
""" creates a role if it doesn't already exist. grants role to user """
|
""" creates a role if it doesn't already exist. grants role to user """
|
||||||
@ -295,9 +261,9 @@ def create_role(name, user=None, tenant=None):
|
|||||||
roles = [r._info for r in manager.api.roles.list()]
|
roles = [r._info for r in manager.api.roles.list()]
|
||||||
if not roles or name not in [r['name'] for r in roles]:
|
if not roles or name not in [r['name'] for r in roles]:
|
||||||
manager.api.roles.create(name=name)
|
manager.api.roles.create(name=name)
|
||||||
juju_log("Created new role '%s'" % name)
|
utils.juju_log('INFO', "Created new role '%s'" % name)
|
||||||
else:
|
else:
|
||||||
juju_log("A role named '%s' already exists" % name)
|
utils.juju_log('INFO', "A role named '%s' already exists" % name)
|
||||||
|
|
||||||
if not user and not tenant:
|
if not user and not tenant:
|
||||||
return
|
return
|
||||||
@ -308,32 +274,35 @@ def create_role(name, user=None, tenant=None):
|
|||||||
tenant_id = manager.resolve_tenant_id(tenant)
|
tenant_id = manager.resolve_tenant_id(tenant)
|
||||||
|
|
||||||
if None in [user_id, role_id, tenant_id]:
|
if None in [user_id, role_id, tenant_id]:
|
||||||
error_out("Could not resolve [user_id, role_id, tenant_id]" %
|
error_out("Could not resolve [%s, %s, %s]" %
|
||||||
[user_id, role_id, tenant_id])
|
(user_id, role_id, tenant_id))
|
||||||
|
|
||||||
grant_role(user, name, tenant)
|
grant_role(user, name, tenant)
|
||||||
|
|
||||||
|
|
||||||
def grant_role(user, role, tenant):
|
def grant_role(user, role, tenant):
|
||||||
"""grant user+tenant a specific role"""
|
"""grant user+tenant a specific role"""
|
||||||
import manager
|
import manager
|
||||||
manager = manager.KeystoneManager(endpoint='http://localhost:35357/v2.0/',
|
manager = manager.KeystoneManager(endpoint='http://localhost:35357/v2.0/',
|
||||||
token=get_admin_token())
|
token=get_admin_token())
|
||||||
juju_log("Granting user '%s' role '%s' on tenant '%s'" %\
|
utils.juju_log('INFO', "Granting user '%s' role '%s' on tenant '%s'" % \
|
||||||
(user, role, tenant))
|
(user, role, tenant))
|
||||||
user_id = manager.resolve_user_id(user)
|
user_id = manager.resolve_user_id(user)
|
||||||
role_id = manager.resolve_role_id(role)
|
role_id = manager.resolve_role_id(role)
|
||||||
tenant_id = manager.resolve_tenant_id(tenant)
|
tenant_id = manager.resolve_tenant_id(tenant)
|
||||||
|
|
||||||
cur_roles = manager.api.roles.roles_for_user(user_id, tenant_id)
|
cur_roles = manager.api.roles.roles_for_user(user_id, tenant_id)
|
||||||
if not cur_roles or role_id not in [r.id for r in cur_roles]:
|
if not cur_roles or role_id not in [r.id for r in cur_roles]:
|
||||||
manager.api.roles.add_user_role(user=user_id,
|
manager.api.roles.add_user_role(user=user_id,
|
||||||
role=role_id,
|
role=role_id,
|
||||||
tenant=tenant_id)
|
tenant=tenant_id)
|
||||||
juju_log("Granted user '%s' role '%s' on tenant '%s'" %\
|
utils.juju_log('INFO', "Granted user '%s' role '%s' on tenant '%s'" % \
|
||||||
(user, role, tenant))
|
(user, role, tenant))
|
||||||
else:
|
else:
|
||||||
juju_log("User '%s' already has role '%s' on tenant '%s'" %\
|
utils.juju_log('INFO',
|
||||||
(user, role, tenant))
|
"User '%s' already has role '%s' on tenant '%s'" % \
|
||||||
|
(user, role, tenant))
|
||||||
|
|
||||||
|
|
||||||
def generate_admin_token(config):
|
def generate_admin_token(config):
|
||||||
""" generate and add an admin token """
|
""" generate and add an admin token """
|
||||||
@ -345,12 +314,15 @@ def generate_admin_token(config):
|
|||||||
token = random.randrange(1000000000000, 9999999999999)
|
token = random.randrange(1000000000000, 9999999999999)
|
||||||
else:
|
else:
|
||||||
return config["admin-token"]
|
return config["admin-token"]
|
||||||
manager.api.add_token(token, config["admin-user"], "admin", config["token-expiry"])
|
manager.api.add_token(token, config["admin-user"],
|
||||||
juju_log("Generated and added new random admin token.")
|
"admin", config["token-expiry"])
|
||||||
|
utils.juju_log('INFO', "Generated and added new random admin token.")
|
||||||
return token
|
return token
|
||||||
|
|
||||||
|
|
||||||
def ensure_initial_admin(config):
|
def ensure_initial_admin(config):
|
||||||
""" Ensures the minimum admin stuff exists in whatever database we're using.
|
""" Ensures the minimum admin stuff exists in whatever database we're
|
||||||
|
using.
|
||||||
This and the helper functions it calls are meant to be idempotent and
|
This and the helper functions it calls are meant to be idempotent and
|
||||||
run during install as well as during db-changed. This will maintain
|
run during install as well as during db-changed. This will maintain
|
||||||
the admin tenant, user, role, service entry and endpoint across every
|
the admin tenant, user, role, service entry and endpoint across every
|
||||||
@ -365,10 +337,11 @@ def ensure_initial_admin(config):
|
|||||||
if config["admin-password"] != "None":
|
if config["admin-password"] != "None":
|
||||||
passwd = config["admin-password"]
|
passwd = config["admin-password"]
|
||||||
elif os.path.isfile(stored_passwd):
|
elif os.path.isfile(stored_passwd):
|
||||||
juju_log("Loading stored passwd from %s" % stored_passwd)
|
utils.juju_log('INFO', "Loading stored passwd from %s" % stored_passwd)
|
||||||
passwd = open(stored_passwd, 'r').readline().strip('\n')
|
passwd = open(stored_passwd, 'r').readline().strip('\n')
|
||||||
if passwd == "":
|
if passwd == "":
|
||||||
juju_log("Generating new passwd for user: %s" % config["admin-user"])
|
utils.juju_log('INFO', "Generating new passwd for user: %s" % \
|
||||||
|
config["admin-user"])
|
||||||
passwd = execute("pwgen -c 16 1", die=True)[0]
|
passwd = execute("pwgen -c 16 1", die=True)[0]
|
||||||
open(stored_passwd, 'w+').writelines("%s\n" % passwd)
|
open(stored_passwd, 'w+').writelines("%s\n" % passwd)
|
||||||
|
|
||||||
@ -380,22 +353,13 @@ def ensure_initial_admin(config):
|
|||||||
create_role("KeystoneServiceAdmin", config["admin-user"], 'admin')
|
create_role("KeystoneServiceAdmin", config["admin-user"], 'admin')
|
||||||
create_service_entry("keystone", "identity", "Keystone Identity Service")
|
create_service_entry("keystone", "identity", "Keystone Identity Service")
|
||||||
|
|
||||||
if is_clustered():
|
utils.juju_log('INFO', "Creating standard endpoint")
|
||||||
juju_log("Creating endpoint for clustered configuration")
|
for region in config['region'].split():
|
||||||
for region in config['region'].split():
|
create_keystone_endpoint(service_host=config["hostname"],
|
||||||
create_keystone_endpoint(service_host=config["vip"],
|
service_port=config["service-port"],
|
||||||
service_port=int(config["service-port"]) + 1,
|
auth_host=config["hostname"],
|
||||||
auth_host=config["vip"],
|
auth_port=config["admin-port"],
|
||||||
auth_port=int(config["admin-port"]) + 1,
|
region=region)
|
||||||
region=region)
|
|
||||||
else:
|
|
||||||
juju_log("Creating standard endpoint")
|
|
||||||
for region in config['region'].split():
|
|
||||||
create_keystone_endpoint(service_host=config["hostname"],
|
|
||||||
service_port=config["service-port"],
|
|
||||||
auth_host=config["hostname"],
|
|
||||||
auth_port=config["admin-port"],
|
|
||||||
region=region)
|
|
||||||
|
|
||||||
|
|
||||||
def create_keystone_endpoint(service_host, service_port,
|
def create_keystone_endpoint(service_host, service_port,
|
||||||
@ -411,14 +375,16 @@ def update_user_password(username, password):
|
|||||||
import manager
|
import manager
|
||||||
manager = manager.KeystoneManager(endpoint='http://localhost:35357/v2.0/',
|
manager = manager.KeystoneManager(endpoint='http://localhost:35357/v2.0/',
|
||||||
token=get_admin_token())
|
token=get_admin_token())
|
||||||
juju_log("Updating password for user '%s'" % username)
|
utils.juju_log('INFO', "Updating password for user '%s'" % username)
|
||||||
|
|
||||||
user_id = manager.resolve_user_id(username)
|
user_id = manager.resolve_user_id(username)
|
||||||
if user_id is None:
|
if user_id is None:
|
||||||
error_out("Could not resolve user id for '%s'" % username)
|
error_out("Could not resolve user id for '%s'" % username)
|
||||||
|
|
||||||
manager.api.users.update_password(user=user_id, password=password)
|
manager.api.users.update_password(user=user_id, password=password)
|
||||||
juju_log("Successfully updated password for user '%s'" % username)
|
utils.juju_log('INFO', "Successfully updated password for user '%s'" % \
|
||||||
|
username)
|
||||||
|
|
||||||
|
|
||||||
def load_stored_passwords(path=SERVICE_PASSWD_PATH):
|
def load_stored_passwords(path=SERVICE_PASSWD_PATH):
|
||||||
creds = {}
|
creds = {}
|
||||||
@ -431,10 +397,12 @@ def load_stored_passwords(path=SERVICE_PASSWD_PATH):
|
|||||||
creds[user] = passwd
|
creds[user] = passwd
|
||||||
return creds
|
return creds
|
||||||
|
|
||||||
|
|
||||||
def save_stored_passwords(path=SERVICE_PASSWD_PATH, **creds):
|
def save_stored_passwords(path=SERVICE_PASSWD_PATH, **creds):
|
||||||
with open(path, 'wb') as stored_passwd:
|
with open(path, 'wb') as stored_passwd:
|
||||||
[stored_passwd.write('%s:%s\n' % (u, p)) for u, p in creds.iteritems()]
|
[stored_passwd.write('%s:%s\n' % (u, p)) for u, p in creds.iteritems()]
|
||||||
|
|
||||||
|
|
||||||
def get_service_password(service_username):
|
def get_service_password(service_username):
|
||||||
creds = load_stored_passwords()
|
creds = load_stored_passwords()
|
||||||
if service_username in creds:
|
if service_username in creds:
|
||||||
@ -446,12 +414,13 @@ def get_service_password(service_username):
|
|||||||
|
|
||||||
return passwd
|
return passwd
|
||||||
|
|
||||||
|
|
||||||
def configure_pki_tokens(config):
|
def configure_pki_tokens(config):
|
||||||
'''Configure PKI token signing, if enabled.'''
|
'''Configure PKI token signing, if enabled.'''
|
||||||
if config['enable-pki'] not in ['True', 'true']:
|
if config['enable-pki'] not in ['True', 'true']:
|
||||||
update_config_block('signing', token_format='UUID')
|
update_config_block('signing', token_format='UUID')
|
||||||
else:
|
else:
|
||||||
juju_log('TODO: PKI Support, setting to UUID for now.')
|
utils.juju_log('INFO', 'TODO: PKI Support, setting to UUID for now.')
|
||||||
update_config_block('signing', token_format='UUID')
|
update_config_block('signing', token_format='UUID')
|
||||||
|
|
||||||
|
|
||||||
@ -462,10 +431,12 @@ def do_openstack_upgrade(install_src, packages):
|
|||||||
old_vers = get_os_codename_package('keystone')
|
old_vers = get_os_codename_package('keystone')
|
||||||
new_vers = get_os_codename_install_source(install_src)
|
new_vers = get_os_codename_install_source(install_src)
|
||||||
|
|
||||||
juju_log("Beginning Keystone upgrade: %s -> %s" % (old_vers, new_vers))
|
utils.juju_log('INFO',
|
||||||
|
"Beginning Keystone upgrade: %s -> %s" % \
|
||||||
|
(old_vers, new_vers))
|
||||||
|
|
||||||
# Backup previous config.
|
# Backup previous config.
|
||||||
juju_log("Backing up contents of /etc/keystone.")
|
utils.juju_log('INFO', "Backing up contents of /etc/keystone.")
|
||||||
stamp = time.strftime('%Y%m%d%H%M')
|
stamp = time.strftime('%Y%m%d%H%M')
|
||||||
cmd = 'tar -pcf /var/lib/juju/keystone-backup-%s.tar /etc/keystone' % stamp
|
cmd = 'tar -pcf /var/lib/juju/keystone-backup-%s.tar /etc/keystone' % stamp
|
||||||
execute(cmd, die=True, echo=True)
|
execute(cmd, die=True, echo=True)
|
||||||
@ -482,14 +453,16 @@ def do_openstack_upgrade(install_src, packages):
|
|||||||
set_admin_token(config['admin-token'])
|
set_admin_token(config['admin-token'])
|
||||||
|
|
||||||
# set the sql connection string if a shared-db relation is found.
|
# set the sql connection string if a shared-db relation is found.
|
||||||
ids = relation_ids(relation_name='shared-db')
|
ids = utils.relation_ids('shared-db')
|
||||||
|
|
||||||
if ids:
|
if ids:
|
||||||
for id in ids:
|
for rid in ids:
|
||||||
for unit in relation_list(id):
|
for unit in utils.relation_list(rid):
|
||||||
juju_log('Configuring new keystone.conf for datbase access '\
|
utils.juju_log('INFO',
|
||||||
'on existing database relation to %s' % unit)
|
'Configuring new keystone.conf for '
|
||||||
relation_data = relation_get_dict(relation_id=id,
|
'database access on existing database'
|
||||||
|
' relation to %s' % unit)
|
||||||
|
relation_data = relation_get_dict(relation_id=rid,
|
||||||
remote_unit=unit)
|
remote_unit=unit)
|
||||||
|
|
||||||
update_config_block('sql', connection="mysql://%s:%s@%s/%s" %
|
update_config_block('sql', connection="mysql://%s:%s@%s/%s" %
|
||||||
@ -498,66 +471,21 @@ def do_openstack_upgrade(install_src, packages):
|
|||||||
relation_data["private-address"],
|
relation_data["private-address"],
|
||||||
config["database"]))
|
config["database"]))
|
||||||
|
|
||||||
execute('service keystone stop', echo=True)
|
utils.stop('keystone')
|
||||||
if ((is_clustered() and is_leader()) or
|
if (cluster.eligible_leader(CLUSTER_RES)):
|
||||||
not is_clustered()):
|
utils.juju_log('INFO',
|
||||||
juju_log('Running database migrations for %s' % new_vers)
|
'Running database migrations for %s' % new_vers)
|
||||||
execute('keystone-manage db_sync', echo=True, die=True)
|
execute('keystone-manage db_sync', echo=True, die=True)
|
||||||
else:
|
else:
|
||||||
juju_log('Not cluster leader; snoozing whilst leader upgrades DB')
|
utils.juju_log('INFO',
|
||||||
|
'Not cluster leader; snoozing whilst'
|
||||||
|
' leader upgrades DB')
|
||||||
time.sleep(10)
|
time.sleep(10)
|
||||||
execute('service keystone start', echo=True)
|
utils.start('keystone')
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
juju_log('Completed Keystone upgrade: %s -> %s' % (old_vers, new_vers))
|
utils.juju_log('INFO',
|
||||||
|
'Completed Keystone upgrade: '
|
||||||
|
'%s -> %s' % (old_vers, new_vers))
|
||||||
def is_clustered():
|
|
||||||
for r_id in (relation_ids('ha') or []):
|
|
||||||
for unit in (relation_list(r_id) or []):
|
|
||||||
relation_data = \
|
|
||||||
relation_get_dict(relation_id=r_id,
|
|
||||||
remote_unit=unit)
|
|
||||||
if 'clustered' in relation_data:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def is_leader():
|
|
||||||
status = execute('crm resource show res_ks_vip', echo=True)[0].strip()
|
|
||||||
hostname = execute('hostname', echo=True)[0].strip()
|
|
||||||
if hostname in status:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
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 oldest_peer(peers):
|
|
||||||
local_unit_no = os.getenv('JUJU_UNIT_NAME').split('/')[1]
|
|
||||||
for peer in peers:
|
|
||||||
remote_unit_no = peer.split('/')[1]
|
|
||||||
if remote_unit_no < local_unit_no:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def eligible_leader():
|
|
||||||
if is_clustered():
|
|
||||||
if not is_leader():
|
|
||||||
juju_log('Deferring action to CRM leader.')
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
peers = peer_units()
|
|
||||||
if peers and not oldest_peer(peers):
|
|
||||||
juju_log('Deferring action to oldest service unit.')
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def synchronize_service_credentials():
|
def synchronize_service_credentials():
|
||||||
@ -565,15 +493,17 @@ def synchronize_service_credentials():
|
|||||||
Broadcast service credentials to peers or consume those that have been
|
Broadcast service credentials to peers or consume those that have been
|
||||||
broadcasted by peer, depending on hook context.
|
broadcasted by peer, depending on hook context.
|
||||||
'''
|
'''
|
||||||
if (not eligible_leader() or
|
if (not cluster.eligible_leader(CLUSTER_RES) or
|
||||||
not os.path.isfile(SERVICE_PASSWD_PATH)):
|
not os.path.isfile(SERVICE_PASSWD_PATH)):
|
||||||
return
|
return
|
||||||
juju_log('Synchronizing service passwords to all peers.')
|
utils.juju_log('INFO', 'Synchronizing service passwords to all peers.')
|
||||||
unison.sync_to_peers(peer_interface='cluster',
|
unison.sync_to_peers(peer_interface='cluster',
|
||||||
paths=[SERVICE_PASSWD_PATH], user=SSH_USER,
|
paths=[SERVICE_PASSWD_PATH], user=SSH_USER,
|
||||||
verbose=True)
|
verbose=True)
|
||||||
|
|
||||||
CA = []
|
CA = []
|
||||||
|
|
||||||
|
|
||||||
def get_ca(user='keystone', group='keystone'):
|
def get_ca(user='keystone', group='keystone'):
|
||||||
"""
|
"""
|
||||||
Initialize a new CA object if one hasn't already been loaded.
|
Initialize a new CA object if one hasn't already been loaded.
|
@ -13,7 +13,7 @@ ubuntu_openstack_release = {
|
|||||||
'oneiric': 'diablo',
|
'oneiric': 'diablo',
|
||||||
'precise': 'essex',
|
'precise': 'essex',
|
||||||
'quantal': 'folsom',
|
'quantal': 'folsom',
|
||||||
'raring' : 'grizzly',
|
'raring': 'grizzly',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -34,6 +34,7 @@ swift_codenames = {
|
|||||||
'1.7.7': 'grizzly',
|
'1.7.7': 'grizzly',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def juju_log(msg):
|
def juju_log(msg):
|
||||||
subprocess.check_call(['juju-log', msg])
|
subprocess.check_call(['juju-log', msg])
|
||||||
|
|
||||||
@ -78,6 +79,7 @@ def get_os_codename_install_source(src):
|
|||||||
if v in src:
|
if v in src:
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
|
||||||
def get_os_codename_version(vers):
|
def get_os_codename_version(vers):
|
||||||
'''Determine OpenStack codename from version number.'''
|
'''Determine OpenStack codename from version number.'''
|
||||||
try:
|
try:
|
||||||
@ -136,6 +138,7 @@ def get_os_version_package(pkg):
|
|||||||
e = "Could not determine OpenStack version for package: %s" % pkg
|
e = "Could not determine OpenStack version for package: %s" % pkg
|
||||||
error_out(e)
|
error_out(e)
|
||||||
|
|
||||||
|
|
||||||
def configure_installation_source(rel):
|
def configure_installation_source(rel):
|
||||||
'''Configure apt installation source.'''
|
'''Configure apt installation source.'''
|
||||||
|
|
||||||
@ -154,7 +157,7 @@ def configure_installation_source(rel):
|
|||||||
subprocess.check_call(["add-apt-repository", "-y", src])
|
subprocess.check_call(["add-apt-repository", "-y", src])
|
||||||
elif rel[:3] == "deb":
|
elif rel[:3] == "deb":
|
||||||
l = len(rel.split('|'))
|
l = len(rel.split('|'))
|
||||||
if l == 2:
|
if l == 2:
|
||||||
src, key = rel.split('|')
|
src, key = rel.split('|')
|
||||||
juju_log("Importing PPA key from keyserver for %s" % src)
|
juju_log("Importing PPA key from keyserver for %s" % src)
|
||||||
_import_key(key)
|
_import_key(key)
|
||||||
@ -211,6 +214,7 @@ def configure_installation_source(rel):
|
|||||||
HAPROXY_CONF = '/etc/haproxy/haproxy.cfg'
|
HAPROXY_CONF = '/etc/haproxy/haproxy.cfg'
|
||||||
HAPROXY_DEFAULT = '/etc/default/haproxy'
|
HAPROXY_DEFAULT = '/etc/default/haproxy'
|
||||||
|
|
||||||
|
|
||||||
def configure_haproxy(units, service_ports, template_dir=None):
|
def configure_haproxy(units, service_ports, template_dir=None):
|
||||||
template_dir = template_dir or 'templates'
|
template_dir = template_dir or 'templates'
|
||||||
import jinja2
|
import jinja2
|
||||||
@ -229,6 +233,7 @@ def configure_haproxy(units, service_ports, template_dir=None):
|
|||||||
with open(HAPROXY_DEFAULT, 'w') as f:
|
with open(HAPROXY_DEFAULT, 'w') as f:
|
||||||
f.write('ENABLED=1')
|
f.write('ENABLED=1')
|
||||||
|
|
||||||
|
|
||||||
def save_script_rc(script_path="scripts/scriptrc", **env_vars):
|
def save_script_rc(script_path="scripts/scriptrc", **env_vars):
|
||||||
"""
|
"""
|
||||||
Write an rc file in the charm-delivered directory containing
|
Write an rc file in the charm-delivered directory containing
|
||||||
@ -238,7 +243,7 @@ def save_script_rc(script_path="scripts/scriptrc", **env_vars):
|
|||||||
service changes.
|
service changes.
|
||||||
"""
|
"""
|
||||||
unit_name = os.getenv('JUJU_UNIT_NAME').replace('/', '-')
|
unit_name = os.getenv('JUJU_UNIT_NAME').replace('/', '-')
|
||||||
juju_rc_path="/var/lib/juju/units/%s/charm/%s" % (unit_name, script_path)
|
juju_rc_path = "/var/lib/juju/units/%s/charm/%s" % (unit_name, script_path)
|
||||||
with open(juju_rc_path, 'wb') as rc_script:
|
with open(juju_rc_path, 'wb') as rc_script:
|
||||||
rc_script.write(
|
rc_script.write(
|
||||||
"#!/bin/bash\n")
|
"#!/bin/bash\n")
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
from keystoneclient.v2_0 import client
|
from keystoneclient.v2_0 import client
|
||||||
|
|
||||||
|
|
||||||
class KeystoneManager(object):
|
class KeystoneManager(object):
|
||||||
def __init__(self, endpoint, token):
|
def __init__(self, endpoint, token):
|
||||||
self.api = client.Client(endpoint=endpoint, token=token)
|
self.api = client.Client(endpoint=endpoint, token=token)
|
||||||
|
@ -1 +1 @@
|
|||||||
keystone-hooks
|
keystone_hooks.py
|
@ -1 +1 @@
|
|||||||
keystone-hooks
|
keystone_hooks.py
|
@ -1 +1 @@
|
|||||||
keystone-hooks
|
keystone_hooks.py
|
Loading…
Reference in New Issue
Block a user