diff --git a/README.md b/README.md index 72ad4db3..ab559f7d 100644 --- a/README.md +++ b/README.md @@ -81,71 +81,6 @@ go down, it must be removed from Juju i.e. Otherwise it will be assumed that this unit may come back at some point and therefore must be know to be in-sync with the rest before continuing. -Deploying from source ---------------------- - -The minimum openstack-origin-git config required to deploy from source is: - - openstack-origin-git: include-file://keystone-juno.yaml - - keystone-juno.yaml - repositories: - - {name: requirements, - repository: 'git://github.com/openstack/requirements', - branch: stable/juno} - - {name: keystone, - repository: 'git://github.com/openstack/keystone', - branch: stable/juno} - -Note that there are only two 'name' values the charm knows about: 'requirements' -and 'keystone'. These repositories must correspond to these 'name' values. -Additionally, the requirements repository must be specified first and the -keystone repository must be specified last. All other repostories are installed -in the order in which they are specified. - -The following is a full list of current tip repos (may not be up-to-date): - - openstack-origin-git: include-file://keystone-master.yaml - - keystone-master.yaml - repositories: - - {name: requirements, - repository: 'git://github.com/openstack/requirements', - branch: master} - - {name: oslo-concurrency, - repository: 'git://github.com/openstack/oslo.concurrency', - branch: master} - - {name: oslo-config, - repository: 'git://github.com/openstack/oslo.config', - branch: master} - - {name: oslo-db, - repository: 'git://github.com/openstack/oslo.db', - branch: master} - - {name: oslo-i18n, - repository: 'git://github.com/openstack/oslo.i18n', - branch: master} - - {name: oslo-serialization, - repository: 'git://github.com/openstack/oslo.serialization', - branch: master} - - {name: oslo-utils, - repository: 'git://github.com/openstack/oslo.utils', - branch: master} - - {name: pbr, - repository: 'git://github.com/openstack-dev/pbr', - branch: master} - - {name: python-keystoneclient, - repository: 'git://github.com/openstack/python-keystoneclient', - branch: master} - - {name: sqlalchemy-migrate, - repository: 'git://github.com/stackforge/sqlalchemy-migrate', - branch: master} - - {name: keystonemiddleware, - repository: 'git://github.com/openstack/keystonemiddleware', - branch: master} - - {name: keystone, - repository: 'git://github.com/openstack/keystone', - branch: master} - Network Space support --------------------- diff --git a/charmhelpers/contrib/hahelpers/cluster.py b/charmhelpers/contrib/hahelpers/cluster.py index aa0b515d..92325a96 100644 --- a/charmhelpers/contrib/hahelpers/cluster.py +++ b/charmhelpers/contrib/hahelpers/cluster.py @@ -41,10 +41,11 @@ from charmhelpers.core.hookenv import ( relation_get, config as config_get, INFO, - ERROR, + DEBUG, WARNING, unit_get, - is_leader as juju_is_leader + is_leader as juju_is_leader, + status_set, ) from charmhelpers.core.decorators import ( retry_on_exception, @@ -60,6 +61,10 @@ class HAIncompleteConfig(Exception): pass +class HAIncorrectConfig(Exception): + pass + + class CRMResourceNotFound(Exception): pass @@ -274,27 +279,71 @@ def get_hacluster_config(exclude_keys=None): Obtains all relevant configuration from charm configuration required for initiating a relation to hacluster: - ha-bindiface, ha-mcastport, vip + ha-bindiface, ha-mcastport, vip, os-internal-hostname, + os-admin-hostname, os-public-hostname param: exclude_keys: list of setting key(s) to be excluded. returns: dict: A dict containing settings keyed by setting name. - raises: HAIncompleteConfig if settings are missing. + raises: HAIncompleteConfig if settings are missing or incorrect. ''' - settings = ['ha-bindiface', 'ha-mcastport', 'vip'] + settings = ['ha-bindiface', 'ha-mcastport', 'vip', 'os-internal-hostname', + 'os-admin-hostname', 'os-public-hostname'] conf = {} for setting in settings: if exclude_keys and setting in exclude_keys: continue conf[setting] = config_get(setting) - missing = [] - [missing.append(s) for s, v in six.iteritems(conf) if v is None] - if missing: - log('Insufficient config data to configure hacluster.', level=ERROR) - raise HAIncompleteConfig + + if not valid_hacluster_config(): + raise HAIncorrectConfig('Insufficient or incorrect config data to ' + 'configure hacluster.') return conf +def valid_hacluster_config(): + ''' + Check that either vip or dns-ha is set. If dns-ha then one of os-*-hostname + must be set. + + Note: ha-bindiface and ha-macastport both have defaults and will always + be set. We only care that either vip or dns-ha is set. + + :returns: boolean: valid config returns true. + raises: HAIncompatibileConfig if settings conflict. + raises: HAIncompleteConfig if settings are missing. + ''' + vip = config_get('vip') + dns = config_get('dns-ha') + if not(bool(vip) ^ bool(dns)): + msg = ('HA: Either vip or dns-ha must be set but not both in order to ' + 'use high availability') + status_set('blocked', msg) + raise HAIncorrectConfig(msg) + + # If dns-ha then one of os-*-hostname must be set + if dns: + dns_settings = ['os-internal-hostname', 'os-admin-hostname', + 'os-public-hostname'] + # At this point it is unknown if one or all of the possible + # network spaces are in HA. Validate at least one is set which is + # the minimum required. + for setting in dns_settings: + if config_get(setting): + log('DNS HA: At least one hostname is set {}: {}' + ''.format(setting, config_get(setting)), + level=DEBUG) + return True + + msg = ('DNS HA: At least one os-*-hostname(s) must be set to use ' + 'DNS HA') + status_set('blocked', msg) + raise HAIncompleteConfig(msg) + + log('VIP HA: VIP is set {}'.format(vip), level=DEBUG) + return True + + def canonical_url(configs, vip_setting='vip'): ''' Returns the correct HTTP URL to this host given the state of HTTPS diff --git a/charmhelpers/contrib/openstack/ip.py b/charmhelpers/contrib/openstack/ip.py index 532a1dc1..7875b997 100644 --- a/charmhelpers/contrib/openstack/ip.py +++ b/charmhelpers/contrib/openstack/ip.py @@ -109,7 +109,7 @@ def _get_address_override(endpoint_type=PUBLIC): return addr_override.format(service_name=service_name()) -def resolve_address(endpoint_type=PUBLIC): +def resolve_address(endpoint_type=PUBLIC, override=True): """Return unit address depending on net config. If unit is clustered with vip(s) and has net splits defined, return vip on @@ -119,10 +119,13 @@ def resolve_address(endpoint_type=PUBLIC): split if one is configured, or a Juju 2.0 extra-binding has been used. :param endpoint_type: Network endpoing type + :param override: Accept hostname overrides or not """ - resolved_address = _get_address_override(endpoint_type) - if resolved_address: - return resolved_address + resolved_address = None + if override: + resolved_address = _get_address_override(endpoint_type) + if resolved_address: + return resolved_address vips = config('vip') if vips: diff --git a/charmhelpers/contrib/openstack/utils.py b/charmhelpers/contrib/openstack/utils.py index bd6efc48..8da5c5ed 100644 --- a/charmhelpers/contrib/openstack/utils.py +++ b/charmhelpers/contrib/openstack/utils.py @@ -51,6 +51,7 @@ from charmhelpers.core.hookenv import ( related_units, relation_ids, relation_set, + service_name, status_set, hook_name ) @@ -207,6 +208,27 @@ PACKAGE_CODENAMES = { ]), } +GIT_DEFAULT_REPOS = { + 'requirements': 'git://github.com/openstack/requirements', + 'cinder': 'git://github.com/openstack/cinder', + 'glance': 'git://github.com/openstack/glance', + 'horizon': 'git://github.com/openstack/horizon', + 'keystone': 'git://github.com/openstack/keystone', + 'neutron': 'git://github.com/openstack/neutron', + 'neutron-fwaas': 'git://github.com/openstack/neutron-fwaas', + 'neutron-lbaas': 'git://github.com/openstack/neutron-lbaas', + 'neutron-vpnaas': 'git://github.com/openstack/neutron-vpnaas', + 'nova': 'git://github.com/openstack/nova', +} + +GIT_DEFAULT_BRANCHES = { + 'icehouse': 'icehouse-eol', + 'kilo': 'stable/kilo', + 'liberty': 'stable/liberty', + 'mitaka': 'stable/mitaka', + 'master': 'master', +} + DEFAULT_LOOPBACK_SIZE = '5G' @@ -703,6 +725,61 @@ def git_install_requested(): requirements_dir = None +def git_default_repos(projects_yaml): + """ + Returns default repos if a default openstack-origin-git value is specified. + """ + service = service_name() + core_project = service + + for default, branch in GIT_DEFAULT_BRANCHES.iteritems(): + if projects_yaml == default: + + # add the requirements repo first + repo = { + 'name': 'requirements', + 'repository': GIT_DEFAULT_REPOS['requirements'], + 'branch': branch, + } + repos = [repo] + + # neutron-* and nova-* charms require some additional repos + if service in ['neutron-api', 'neutron-gateway', + 'neutron-openvswitch']: + core_project = 'neutron' + for project in ['neutron-fwaas', 'neutron-lbaas', + 'neutron-vpnaas']: + repo = { + 'name': project, + 'repository': GIT_DEFAULT_REPOS[project], + 'branch': branch, + } + repos.append(repo) + + elif service in ['nova-cloud-controller', 'nova-compute']: + core_project = 'nova' + repo = { + 'name': 'neutron', + 'repository': GIT_DEFAULT_REPOS['neutron'], + 'branch': branch, + } + repos.append(repo) + elif service == 'openstack-dashboard': + core_project = 'horizon' + + # finally add the current service's core project repo + repo = { + 'name': core_project, + 'repository': GIT_DEFAULT_REPOS[core_project], + 'branch': branch, + } + repos.append(repo) + + return yaml.dump(dict(repositories=repos)) + + return projects_yaml + + def _git_yaml_load(projects_yaml): """ Load the specified yaml into a dictionary. diff --git a/config.yaml b/config.yaml index 3f07aa61..91c3837e 100644 --- a/config.yaml +++ b/config.yaml @@ -45,14 +45,29 @@ options: default: type: string description: | - Specifies a YAML-formatted dictionary listing the git - repositories and branches from which to install OpenStack and - its dependencies. + Specifies a default OpenStack release name, or a YAML dictionary + listing the git repositories to install from. + + The default Openstack release name may be one of the following, where + the corresponding OpenStack github branch will be used: + * icehouse + * kilo + * liberty + * mitaka + * master + + The YAML must minimally include requirements and keystone repositories, + and may also include repositories for other dependencies: + repositories: + - {name: requirements, + repository: 'git://github.com/openstack/requirements', + branch: master} + - {name: keystone, + repository: 'git://github.com/openstack/keystone', + branch: master} Note that the installed config files will be determined based on the OpenStack release of the openstack-origin option. - - For more details see README.md. config-file: default: "/etc/keystone/keystone.conf" type: string diff --git a/hooks/keystone_utils.py b/hooks/keystone_utils.py index 22ed7d23..30a572f9 100644 --- a/hooks/keystone_utils.py +++ b/hooks/keystone_utils.py @@ -46,6 +46,7 @@ from charmhelpers.contrib.openstack.utils import ( get_os_codename_install_source, git_install_requested, git_clone_and_install, + git_default_repos, git_src_dir, git_yaml_value, git_pip_venv_dir, @@ -2057,6 +2058,7 @@ def git_install(projects_yaml): """Perform setup, and install git repos specified in yaml parameter.""" if git_install_requested(): git_pre_install() + projects_yaml = git_default_repos(projects_yaml) git_clone_and_install(projects_yaml, core_project='keystone') git_post_install(projects_yaml)