Juju Charm - Keystone LDAP backend
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
4.8KB

  1. #
  2. # Copyright 2017 Canonical Ltd
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import charmhelpers.core as core
  16. import charmhelpers.core.host as ch_host
  17. import charmhelpers.core.hookenv as hookenv
  18. import charmhelpers.contrib.openstack.templating as os_templating
  19. import charmhelpers.contrib.openstack.utils as os_utils
  20. import charms_openstack.charm
  21. import charms_openstack.adapters
  22. import os
  23. # release detection is done via keystone package given that
  24. # openstack-origin is not present in the subordinate charm
  25. # see https://github.com/juju/charm-helpers/issues/83
  26. import charmhelpers.core.unitdata as unitdata
  27. from charms_openstack.charm.core import (
  28. register_os_release_selector
  29. )
  30. OPENSTACK_RELEASE_KEY = 'charmers.openstack-release-version'
  31. DOMAIN_CONF = "/etc/keystone/domains/keystone.{}.conf"
  32. KEYSTONE_CONF_TEMPLATE = "keystone.conf"
  33. @register_os_release_selector
  34. def select_release():
  35. """Determine the release based on the keystone package version.
  36. Note that this function caches the release after the first install so
  37. that it doesn't need to keep going and getting it from the package
  38. information.
  39. """
  40. release_version = unitdata.kv().get(OPENSTACK_RELEASE_KEY, None)
  41. if release_version is None:
  42. release_version = os_utils.os_release('keystone')
  43. unitdata.kv().set(OPENSTACK_RELEASE_KEY, release_version)
  44. return release_version
  45. class KeystoneLDAPConfigurationAdapter(
  46. charms_openstack.adapters.ConfigurationAdapter):
  47. '''Charm specific configuration adapter to deal with ldap
  48. config flag parsing
  49. '''
  50. @property
  51. def ldap_options(self):
  52. return os_utils.config_flags_parser(
  53. hookenv.config('ldap-config-flags')
  54. )
  55. class KeystoneLDAPCharm(charms_openstack.charm.OpenStackCharm):
  56. # Internal name of charm
  57. service_name = name = 'keystone-ldap'
  58. # Package to derive application version from
  59. version_package = 'keystone'
  60. # First release supported
  61. release = 'mitaka'
  62. # List of packages to install for this charm
  63. packages = ['python-ldappool']
  64. configuration_class = KeystoneLDAPConfigurationAdapter
  65. @property
  66. def domain_name(self):
  67. """Domain name for the running application
  68. :returns: string: containing the current domain name for the
  69. application
  70. """
  71. return hookenv.config('domain-name') or hookenv.service_name()
  72. @staticmethod
  73. def configuration_complete():
  74. """Determine whether sufficient configuration has been provided
  75. to configure keystone for use with a LDAP backend
  76. :returns: boolean indicating whether configuration is complete
  77. """
  78. required_config = {
  79. 'ldap_server': hookenv.config('ldap-server'),
  80. 'ldap_user': hookenv.config('ldap-user'),
  81. 'ldap_password': hookenv.config('ldap-password'),
  82. 'ldap_suffix': hookenv.config('ldap-suffix'),
  83. }
  84. return all(required_config.values())
  85. @property
  86. def configuration_file(self):
  87. """Configuration file for domain configuration"""
  88. return DOMAIN_CONF.format(self.domain_name)
  89. def assess_status(self):
  90. """Determine the current application status for the charm"""
  91. hookenv.application_version_set(self.application_version)
  92. if not self.configuration_complete():
  93. hookenv.status_set('blocked',
  94. 'LDAP configuration incomplete')
  95. else:
  96. hookenv.status_set('active',
  97. 'Unit is ready')
  98. def render_config(self, restart_trigger):
  99. """Render the domain specific LDAP configuration for the application
  100. """
  101. checksum = ch_host.file_hash(self.configuration_file)
  102. core.templating.render(
  103. source=KEYSTONE_CONF_TEMPLATE,
  104. template_loader=os_templating.get_loader(
  105. 'templates/', self.release),
  106. target=self.configuration_file,
  107. context=self.adapters_instance)
  108. if checksum != ch_host.file_hash(self.configuration_file):
  109. restart_trigger()
  110. def remove_config(self):
  111. """
  112. Remove the domain-specific LDAP configuration file and trigger
  113. keystone restart.
  114. """
  115. if os.path.exists(self.configuration_file):
  116. os.unlink(self.configuration_file)