--- /dev/null
+#!/usr/bin/env python3
+# Copyright 2021 Canonical Ltd.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact: legal@canonical.com
+#
+# To get in touch with the maintainers, please contact:
+# osm-charmers@lists.launchpad.net
+#
+#
+# This file populates the Actions tab on Charmhub.
+# See https://juju.is/docs/some-url-to-be-determined/ for a checklist and guidance.
+
+"""Module that takes take of the charm configuration."""
+
+import re
+from typing import Any, Dict, Optional
+
+from config_validator import ConfigValidator, ValidationError
+from ops.model import ConfigData
+
+
+class MysqlConnectionData:
+ """Mysql Connection Data class."""
+
+ _compiled_regex = re.compile(
+ r"^mysql\:\/\/{}@{}\/{}?$".format(
+ r"(?P<username>[_\w]+):(?P<password>[\w\W]+)",
+ r"(?P<host>[\-\.\w]+):(?P<port>\d+)",
+ r"(?P<database>[_\w]+)",
+ )
+ )
+
+ def __init__(self, mysql_uri: str):
+ match = self._compiled_regex.search(mysql_uri)
+ if not match:
+ raise ValidationError("mysql_uri is not properly formed")
+ mysql_data = match.groupdict()
+ self.host = mysql_data.get("host")
+ self.port = int(mysql_data.get("port"))
+ self.username = mysql_data.get("username")
+ self.password = mysql_data.get("password")
+ self.database = mysql_data.get("database")
+ self.uri = mysql_uri
+
+
+def validate_config(config: ConfigData):
+ """Validate charm configuration.
+
+ Args:
+ config (ConfigData): Charm configuration.
+
+ Raises:
+ config_validator.ValidationError if the validation failed.
+ """
+ kwargs: Dict[str, Any] = config
+ ConfigModel(**kwargs)
+ ConfigLdapModel(**kwargs)
+
+
+def get_environment(
+ service_name: str, config: ConfigData, mysql_data: MysqlConnectionData
+) -> Dict[str, Any]:
+ """Get environment variables.
+
+ Args:
+ service_name (str): Cluster IP service name.
+ config (ConfigData): Charm configuration.
+
+ Returns:
+ Dict[str, Any]: Dictionary with the environment variables for Keystone service.
+ """
+ kwargs: Dict[str, Any] = config
+ config = ConfigModel(**kwargs)
+ config_ldap = ConfigLdapModel(**kwargs)
+ environment = {
+ "DB_HOST": mysql_data.host,
+ "DB_PORT": mysql_data.port,
+ "ROOT_DB_USER": mysql_data.username,
+ "ROOT_DB_PASSWORD": mysql_data.password,
+ "REGION_ID": config.region_id,
+ "KEYSTONE_HOST": service_name,
+ "KEYSTONE_DB_PASSWORD": config.keystone_db_password,
+ "ADMIN_USERNAME": config.admin_username,
+ "ADMIN_PASSWORD": config.admin_password,
+ "ADMIN_PROJECT": config.admin_project,
+ "SERVICE_USERNAME": config.service_username,
+ "SERVICE_PASSWORD": config.service_password,
+ "SERVICE_PROJECT": config.service_project,
+ }
+ if config_ldap.ldap_enabled:
+ environment.update(
+ {
+ "LDAP_AUTHENTICATION_DOMAIN_NAME": config_ldap.ldap_authentication_domain_name,
+ "LDAP_URL": config_ldap.ldap_url,
+ "LDAP_PAGE_SIZE": str(config_ldap.ldap_page_size),
+ "LDAP_USER_OBJECTCLASS": config_ldap.ldap_user_objectclass,
+ "LDAP_USER_ID_ATTRIBUTE": config_ldap.ldap_user_id_attribute,
+ "LDAP_USER_NAME_ATTRIBUTE": config_ldap.ldap_user_name_attribute,
+ "LDAP_USER_PASS_ATTRIBUTE": config_ldap.ldap_user_pass_attribute,
+ "LDAP_USER_ENABLED_MASK": str(config_ldap.ldap_user_enabled_mask),
+ "LDAP_USER_ENABLED_DEFAULT": config_ldap.ldap_user_enabled_default,
+ "LDAP_USER_ENABLED_INVERT": str(config_ldap.ldap_user_enabled_invert),
+ "LDAP_GROUP_OBJECTCLASS": config_ldap.ldap_group_objectclass,
+ }
+ )
+ if config_ldap.ldap_use_starttls:
+ environment.update(
+ {
+ "LDAP_USE_STARTTLS": str(config_ldap.ldap_use_starttls),
+ "LDAP_TLS_CACERT_BASE64": config_ldap.ldap_tls_cacert_base64,
+ "LDAP_TLS_REQ_CERT": config_ldap.ldap_tls_req_cert,
+ }
+ )
+ optional_ldap_configs = {
+ "LDAP_BIND_USER": config_ldap.ldap_bind_user,
+ "LDAP_BIND_PASSWORD": config_ldap.ldap_bind_password,
+ "LDAP_USER_TREE_DN": config_ldap.ldap_user_tree_dn,
+ "LDAP_USER_FILTER": config_ldap.ldap_user_filter,
+ "LDAP_USER_ENABLED_ATTRIBUTE": config_ldap.ldap_user_enabled_attribute,
+ "LDAP_CHASE_REFERRALS": config_ldap.ldap_chase_referrals,
+ "LDAP_GROUP_TREE_DN": config_ldap.ldap_group_tree_dn,
+ "LDAP_TLS_CACERT_BASE64": config_ldap.ldap_tls_cacert_base64,
+ }
+ for env, value in optional_ldap_configs.items():
+ if value:
+ environment[env] = value
+ return environment
+
+
+class ConfigModel(ConfigValidator):
+ """Keystone Configuration."""
+
+ region_id: str
+ keystone_db_password: str
+ admin_username: str
+ admin_password: str
+ admin_project: str
+ service_username: str
+ service_password: str
+ service_project: str
+ user_domain_name: str
+ project_domain_name: str
+ token_expiration: int
+ mysql_uri: Optional[str]
+
+
+class ConfigLdapModel(ConfigValidator):
+ """LDAP Configuration."""
+
+ ldap_enabled: bool
+ ldap_authentication_domain_name: Optional[str]
+ ldap_url: Optional[str]
+ ldap_bind_user: Optional[str]
+ ldap_bind_password: Optional[str]
+ ldap_chase_referrals: Optional[str]
+ ldap_page_size: Optional[int]
+ ldap_user_tree_dn: Optional[str]
+ ldap_user_objectclass: Optional[str]
+ ldap_user_id_attribute: Optional[str]
+ ldap_user_name_attribute: Optional[str]
+ ldap_user_pass_attribute: Optional[str]
+ ldap_user_filter: Optional[str]
+ ldap_user_enabled_attribute: Optional[str]
+ ldap_user_enabled_mask: Optional[int]
+ ldap_user_enabled_default: Optional[str]
+ ldap_user_enabled_invert: Optional[bool]
+ ldap_group_objectclass: Optional[str]
+ ldap_group_tree_dn: Optional[str]
+ ldap_use_starttls: Optional[bool]
+ ldap_tls_cacert_base64: Optional[str]
+ ldap_tls_req_cert: Optional[str]