Remove legacy keystone charm 41/13441/2
authorPatricia Reinoso <patricia.reinoso@canonical.com>
Wed, 24 May 2023 08:08:35 +0000 (08:08 +0000)
committerPatricia Reinoso <patricia.reinoso@canonical.com>
Wed, 24 May 2023 11:32:31 +0000 (11:32 +0000)
Change-Id: Ieef80de0273facc15c42aaf216867c6866f183ab
Signed-off-by: Patricia Reinoso <patricia.reinoso@canonical.com>
14 files changed:
devops-stages/stage-test.sh
installers/charm/keystone/.gitignore [deleted file]
installers/charm/keystone/.jujuignore [deleted file]
installers/charm/keystone/.yamllint.yaml [deleted file]
installers/charm/keystone/README.md [deleted file]
installers/charm/keystone/charmcraft.yaml [deleted file]
installers/charm/keystone/config.yaml [deleted file]
installers/charm/keystone/metadata.yaml [deleted file]
installers/charm/keystone/requirements-test.txt [deleted file]
installers/charm/keystone/requirements.txt [deleted file]
installers/charm/keystone/src/charm.py [deleted file]
installers/charm/keystone/tests/__init__.py [deleted file]
installers/charm/keystone/tests/test_charm.py [deleted file]
installers/charm/keystone/tox.ini [deleted file]

index af5953a..4f32d7e 100755 (executable)
@@ -21,7 +21,7 @@ CURRENT_DIR=`pwd`
 # Execute tests for charms
 CHARM_PATH="./installers/charm"
 NEW_CHARMS_NAMES="osm-lcm osm-mon osm-nbi osm-ng-ui osm-pol osm-ro vca-integrator-operator"
-OLD_CHARMS_NAMES="keystone prometheus grafana"
+OLD_CHARMS_NAMES="prometheus grafana"
 for charm in $NEW_CHARMS_NAMES; do
     if [ $(git diff --name-only "origin/${GERRIT_BRANCH}" -- "installers/charm/${charm}" | wc -l) -ne 0 ]; then
         echo "Running tox for ${charm}"
diff --git a/installers/charm/keystone/.gitignore b/installers/charm/keystone/.gitignore
deleted file mode 100644 (file)
index 493739e..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-# 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
-##
-
-venv
-.vscode
-build
-*.charm
-.coverage
-coverage.xml
-.stestr
-cover
-release
diff --git a/installers/charm/keystone/.jujuignore b/installers/charm/keystone/.jujuignore
deleted file mode 100644 (file)
index 3ae3e7d..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-# 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
-##
-
-venv
-.vscode
-build
-*.charm
-.coverage
-coverage.xml
-.gitignore
-.stestr
-cover
-release
-tests/
-requirements*
-tox.ini
diff --git a/installers/charm/keystone/.yamllint.yaml b/installers/charm/keystone/.yamllint.yaml
deleted file mode 100644 (file)
index d71fb69..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-# 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
-##
-
----
-extends: default
-
-yaml-files:
-  - "*.yaml"
-  - "*.yml"
-  - ".yamllint"
-ignore: |
-  .tox
-  cover/
-  build/
-  venv
-  release/
diff --git a/installers/charm/keystone/README.md b/installers/charm/keystone/README.md
deleted file mode 100644 (file)
index 1ca9764..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<!-- Copyright 2020 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. -->
-# Keystone operator Charm for Kubernetes
-
-## Requirements
-
diff --git a/installers/charm/keystone/charmcraft.yaml b/installers/charm/keystone/charmcraft.yaml
deleted file mode 100644 (file)
index 04b659a..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-# 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
-##
-
-type: charm
-bases:
-  - build-on:
-      - name: ubuntu
-        channel: "20.04"
-        architectures: ["amd64"]
-    run-on:
-      - name: ubuntu
-        channel: "20.04"
-        architectures:
-          - amd64
-          - aarch64
-          - arm64
-parts:
-  charm:
-    build-packages:
-      - git
-      - libffi-dev
-    charm-binary-python-packages:
-      - cryptography
diff --git a/installers/charm/keystone/config.yaml b/installers/charm/keystone/config.yaml
deleted file mode 100644 (file)
index dc0953a..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-# Copyright 2020 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.
-options:
-  max_file_size:
-    type: int
-    description: |
-      The maximum file size, in megabytes.
-
-      If there is a reverse proxy in front of Keystone, it may
-      need to be configured to handle the requested size.
-    default: 5
-  ingress_class:
-    type: string
-    description: |
-      Ingress class name. This is useful for selecting the ingress to be used
-      in case there are multiple ingresses in the underlying k8s clusters.
-  ingress_whitelist_source_range:
-    type: string
-    description: |
-      A comma-separated list of CIDRs to store in the
-      ingress.kubernetes.io/whitelist-source-range annotation.
-
-      This can be used to lock down access to
-      Keystone based on source IP address.
-    default: ""
-  tls_secret_name:
-    type: string
-    description: TLS Secret name
-    default: ""
-  site_url:
-    type: string
-    description: Ingress URL
-    default: ""
-  image_pull_policy:
-    type: string
-    description: |
-      ImagePullPolicy configuration for the pod.
-      Possible values: always, ifnotpresent, never
-    default: always
-  security_context:
-    description: Enables the security context of the pods
-    type: boolean
-    default: false
-  region_id:
-    type: string
-    description: Region ID to be created when starting the service
-    default: RegionOne
-  keystone_db_password:
-    type: string
-    description: Keystone DB Password
-    default: admin
-  mysql_uri:
-    type: string
-    description: |
-      Mysql uri with the following format:
-        mysql://<user>:<pass>@<host>:<port>/<database>
-  admin_username:
-    type: string
-    description: Admin username to be created when starting the service
-    default: admin
-  admin_password:
-    type: string
-    description: Admin password to be created when starting the service
-    default: admin
-  admin_project:
-    type: string
-    description: Admin project to be created when starting the service
-    default: admin
-  service_username:
-    type: string
-    description: Service Username to be created when starting the service
-    default: nbi
-  service_password:
-    type: string
-    description: Service Password to be created when starting the service
-    default: nbi
-  service_project:
-    type: string
-    description: Service Project to be created when starting the service
-    default: service
-  user_domain_name:
-    type: string
-    description: User domain name (Hardcoded in the container start.sh script)
-    default: default
-  project_domain_name:
-    type: string
-    description: |
-      Project domain name (Hardcoded in the container start.sh script)
-    default: default
-  token_expiration:
-    type: int
-    description: Token keys expiration in seconds
-    default: 172800
-  ldap_enabled:
-    type: boolean
-    description: Boolean to enable/disable LDAP authentication
-    default: false
-  ldap_authentication_domain_name:
-    type: string
-    description: Name of the domain which use LDAP authentication
-    default: ""
-  ldap_url:
-    type: string
-    description: URL of the LDAP server
-    default: "ldap://localhost"
-  ldap_bind_user:
-    type: string
-    description: User to bind and search for users
-    default: ""
-  ldap_bind_password:
-    type: string
-    description: Password to bind and search for users
-    default: ""
-  ldap_chase_referrals:
-    type: string
-    description: |
-      Sets keystone’s referral chasing behavior across directory partitions.
-      If left unset, the system’s default behavior will be used.
-    default: ""
-  ldap_page_size:
-    type: int
-    description: |
-      Defines the maximum number of results per page that keystone should
-      request from the LDAP server when listing objects. A value of zero (0)
-      disables paging.
-    default: 0
-  ldap_user_tree_dn:
-    type: string
-    description: |
-      Root of the tree in LDAP server in which Keystone will search for users
-    default: ""
-  ldap_user_objectclass:
-    type: string
-    description: |
-      LDAP object class that Keystone will filter on within user_tree_dn to
-      find user objects. Any objects of other classes will be ignored.
-    default: inetOrgPerson
-  ldap_user_id_attribute:
-    type: string
-    description: |
-      This set of options define the mapping to LDAP attributes for the three
-      key user attributes supported by Keystone. The LDAP attribute chosen for
-      user_id must be something that is immutable for a user and no more than
-      64 characters in length. Notice that Distinguished Name (DN) may be
-      longer than 64 characters and thus is not suitable. An uid, or mail may
-      be appropriate.
-    default: cn
-  ldap_user_name_attribute:
-    type: string
-    description: |
-      This set of options define the mapping to LDAP attributes for the three
-      key user attributes supported by Keystone. The LDAP attribute chosen for
-      user_id must be something that is immutable for a user and no more than
-      64 characters in length. Notice that Distinguished Name (DN) may be
-      longer than 64 characters and thus is not suitable. An uid, or mail may
-      be appropriate.
-    default: sn
-  ldap_user_pass_attribute:
-    type: string
-    description: |
-      This set of options define the mapping to LDAP attributes for the three
-      key user attributes supported by Keystone. The LDAP attribute chosen for
-      user_id must be something that is immutable for a user and no more than
-      64 characters in length. Notice that Distinguished Name (DN) may be
-      longer than 64 characters and thus is not suitable. An uid, or mail may
-      be appropriate.
-    default: userPassword
-  ldap_user_filter:
-    type: string
-    description: |
-      This filter option allow additional filter (over and above
-      user_objectclass) to be included into the search of user. One common use
-      of this is to provide more efficient searching, where the recommended
-      search for user objects is (&(objectCategory=person)(objectClass=user)).
-      By specifying user_objectclass as user and user_filter as
-      objectCategory=person in the Keystone configuration file, this can be
-      achieved.
-    default: ""
-  ldap_user_enabled_attribute:
-    type: string
-    description: |
-      In Keystone, a user entity can be either enabled or disabled. Setting
-      the above option will give a mapping to an equivalent attribute in LDAP,
-      allowing your LDAP management tools to disable a user.
-    default: enabled
-  ldap_user_enabled_mask:
-    type: int
-    description: |
-      Some LDAP schemas, rather than having a dedicated attribute for user
-      enablement, use a bit within a general control attribute (such as
-      userAccountControl) to indicate this. Setting user_enabled_mask will
-      cause Keystone to look at only the status of this bit in the attribute
-      specified by user_enabled_attribute, with the bit set indicating the
-      user is enabled.
-    default: 0
-  ldap_user_enabled_default:
-    type: string
-    description: |
-      Most LDAP servers use a boolean or bit in a control field to indicate
-      enablement. However, some schemas might use an integer value in an
-      attribute. In this situation, set user_enabled_default to the integer
-      value that represents a user being enabled.
-    default: "true"
-  ldap_user_enabled_invert:
-    type: boolean
-    description: |
-      Some LDAP schemas have an “account locked” attribute, which is the
-      equivalent to account being “disabled.” In order to map this to the
-      Keystone enabled attribute, you can utilize the user_enabled_invert
-      setting in conjunction with user_enabled_attribute to map the lock
-      status to disabled in Keystone.
-    default: false
-  ldap_group_objectclass:
-    type: string
-    description: The LDAP object class to use for groups.
-    default: groupOfNames
-  ldap_group_tree_dn:
-    type: string
-    description: The search base to use for groups.
-    default: ""
-  ldap_use_starttls:
-    type: boolean
-    description: |
-      Enable Transport Layer Security (TLS) for providing a secure connection
-      from Keystone to LDAP (StartTLS, not LDAPS).
-    default: false
-  ldap_tls_cacert_base64:
-    type: string
-    description: |
-      CA certificate in Base64 format (if you have the PEM file, text inside
-      "-----BEGIN CERTIFICATE-----"/"-----END CERTIFICATE-----" tags).
-    default: ""
-  ldap_tls_req_cert:
-    type: string
-    description: |
-      Defines how the certificates are checked for validity in the client
-      (i.e., Keystone end) of the secure connection (this doesn’t affect what
-      level of checking the server is doing on the certificates it receives
-      from Keystone). Possible values are "demand", "never", and "allow". The
-      default of demand means the client always checks the certificate and
-      will drop the connection if it is not provided or invalid. never is the
-      opposite—it never checks it, nor requires it to be provided. allow means
-      that if it is not provided then the connection is allowed to continue,
-      but if it is provided it will be checked—and if invalid, the connection
-      will be dropped.
-    default: demand
diff --git a/installers/charm/keystone/metadata.yaml b/installers/charm/keystone/metadata.yaml
deleted file mode 100644 (file)
index 38c03ed..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2020 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.
-name: keystone
-summary: A Keystone K8s charm
-description: |
-    A CAAS charm to deploy Keystone
-series:
-    - kubernetes
-min-juju-version: 2.8.0
-resources:
-    image:
-        type: oci-image
-        description: OSM docker image for NBI
-        upstream-source: "opensourcemano/keystone:latest"
-requires:
-    db:
-        interface: mysql
-        limit: 1
-provides:
-    keystone:
-        interface: keystone
-deployment:
-    type: stateless
-    service: cluster
diff --git a/installers/charm/keystone/requirements-test.txt b/installers/charm/keystone/requirements-test.txt
deleted file mode 100644 (file)
index cf61dd4..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-# 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
-mock==4.0.3
diff --git a/installers/charm/keystone/requirements.txt b/installers/charm/keystone/requirements.txt
deleted file mode 100644 (file)
index 5c18be8..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-# 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
-##
-cryptography
-git+https://github.com/charmed-osm/ops-lib-charmed-osm/@master
\ No newline at end of file
diff --git a/installers/charm/keystone/src/charm.py b/installers/charm/keystone/src/charm.py
deleted file mode 100755 (executable)
index 446d2e0..0000000
+++ /dev/null
@@ -1,895 +0,0 @@
-#!/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
-##
-
-# pylint: disable=E0213
-
-
-from datetime import datetime
-from ipaddress import ip_network
-import json
-import logging
-from typing import List, NoReturn, Optional, Tuple
-from urllib.parse import urlparse
-
-from cryptography.fernet import Fernet
-from ops.main import main
-from opslib.osm.charm import CharmedOsmBase, RelationsMissing
-from opslib.osm.interfaces.keystone import KeystoneServer
-from opslib.osm.interfaces.mysql import MysqlClient
-from opslib.osm.pod import (
-    ContainerV3Builder,
-    FilesV3Builder,
-    IngressResourceV3Builder,
-    PodRestartPolicy,
-    PodSpecV3Builder,
-)
-from opslib.osm.validator import ModelValidator, validator
-
-
-logger = logging.getLogger(__name__)
-
-
-REQUIRED_SETTINGS = ["token_expiration"]
-
-# This is hardcoded in the keystone container script
-DATABASE_NAME = "keystone"
-
-# We expect the keystone container to use the default port
-PORT = 5000
-
-# Number of keys need might need to be adjusted in the future
-NUMBER_FERNET_KEYS = 2
-NUMBER_CREDENTIAL_KEYS = 2
-
-# Path for keys
-CREDENTIAL_KEYS_PATH = "/etc/keystone/credential-keys"
-FERNET_KEYS_PATH = "/etc/keystone/fernet-keys"
-
-
-class ConfigModel(ModelValidator):
-    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
-    max_file_size: int
-    site_url: Optional[str]
-    ingress_class: Optional[str]
-    ingress_whitelist_source_range: Optional[str]
-    tls_secret_name: Optional[str]
-    mysql_host: Optional[str]
-    mysql_port: Optional[int]
-    mysql_root_password: Optional[str]
-    image_pull_policy: str
-    security_context: bool
-
-    @validator("max_file_size")
-    def validate_max_file_size(cls, v):
-        if v < 0:
-            raise ValueError("value must be equal or greater than 0")
-        return v
-
-    @validator("site_url")
-    def validate_site_url(cls, v):
-        if v:
-            parsed = urlparse(v)
-            if not parsed.scheme.startswith("http"):
-                raise ValueError("value must start with http")
-        return v
-
-    @validator("ingress_whitelist_source_range")
-    def validate_ingress_whitelist_source_range(cls, v):
-        if v:
-            ip_network(v)
-        return v
-
-    @validator("mysql_port")
-    def validate_mysql_port(cls, v):
-        if v and (v <= 0 or v >= 65535):
-            raise ValueError("Mysql port out of range")
-        return v
-
-    @validator("image_pull_policy")
-    def validate_image_pull_policy(cls, v):
-        values = {
-            "always": "Always",
-            "ifnotpresent": "IfNotPresent",
-            "never": "Never",
-        }
-        v = v.lower()
-        if v not in values.keys():
-            raise ValueError("value must be always, ifnotpresent or never")
-        return values[v]
-
-
-class ConfigLdapModel(ModelValidator):
-    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]
-
-    @validator
-    def validate_ldap_user_enabled_default(cls, v):
-        if v:
-            if v not in ["true", "false"]:
-                raise ValueError('must be equal to "true" or "false"')
-        return v
-
-
-class KeystoneCharm(CharmedOsmBase):
-    def __init__(self, *args) -> NoReturn:
-        super().__init__(
-            *args,
-            oci_image="image",
-            mysql_uri=True,
-        )
-        self.state.set_default(fernet_keys=None)
-        self.state.set_default(credential_keys=None)
-        self.state.set_default(keys_timestamp=0)
-
-        self.keystone_server = KeystoneServer(self, "keystone")
-        self.mysql_client = MysqlClient(self, "db")
-        self.framework.observe(self.on["db"].relation_changed, self.configure_pod)
-        self.framework.observe(self.on["db"].relation_broken, self.configure_pod)
-        self.framework.observe(self.on.update_status, self.configure_pod)
-
-        self.framework.observe(
-            self.on["keystone"].relation_joined, self._publish_keystone_info
-        )
-
-    def _publish_keystone_info(self, event):
-        if self.unit.is_leader():
-            config = ConfigModel(**dict(self.config))
-            self.keystone_server.publish_info(
-                host=f"http://{self.app.name}:{PORT}/v3",
-                port=PORT,
-                user_domain_name=config.user_domain_name,
-                project_domain_name=config.project_domain_name,
-                username=config.service_username,
-                password=config.service_password,
-                service=config.service_project,
-                keystone_db_password=config.keystone_db_password,
-                region_id=config.region_id,
-                admin_username=config.admin_username,
-                admin_password=config.admin_password,
-                admin_project_name=config.admin_project,
-            )
-
-    def _check_missing_dependencies(self, config: ConfigModel, external_db: bool):
-        missing_relations = []
-        if not external_db and self.mysql_client.is_missing_data_in_unit():
-            missing_relations.append("mysql")
-        if missing_relations:
-            raise RelationsMissing(missing_relations)
-
-    def _generate_keys(self) -> Tuple[List[str], List[str]]:
-        """Generating new fernet tokens.
-
-        Returns:
-            Tuple[List[str], List[str]]: contains two lists of strings. First
-                                         list contains strings that represent
-                                         the keys for fernet and the second
-                                         list contains strins that represent
-                                         the keys for credentials.
-        """
-        fernet_keys = [
-            Fernet.generate_key().decode() for _ in range(NUMBER_FERNET_KEYS)
-        ]
-        credential_keys = [
-            Fernet.generate_key().decode() for _ in range(NUMBER_CREDENTIAL_KEYS)
-        ]
-
-        return (fernet_keys, credential_keys)
-
-    def _get_keys(self):
-        keys_timestamp = self.state.keys_timestamp
-        if fernet_keys := self.state.fernet_keys:
-            fernet_keys = json.loads(fernet_keys)
-
-        if credential_keys := self.state.credential_keys:
-            credential_keys = json.loads(credential_keys)
-
-        now = datetime.now().timestamp()
-        token_expiration = self.config["token_expiration"]
-
-        valid_keys = (now - keys_timestamp) < token_expiration
-        if not credential_keys or not fernet_keys or not valid_keys:
-            fernet_keys, credential_keys = self._generate_keys()
-            self.state.fernet_keys = json.dumps(fernet_keys)
-            self.state.credential_keys = json.dumps(credential_keys)
-            self.state.keys_timestamp = now
-        return credential_keys, fernet_keys
-
-    def _build_files(
-        self, config: ConfigModel, credential_keys: List, fernet_keys: List
-    ):
-        credentials_files_builder = FilesV3Builder()
-        fernet_files_builder = FilesV3Builder()
-        for key_id, _ in enumerate(credential_keys):
-            credentials_files_builder.add_file(str(key_id), str(key_id), secret=True)
-        for key_id, _ in enumerate(fernet_keys):
-            fernet_files_builder.add_file(str(key_id), str(key_id), secret=True)
-        return credentials_files_builder.build(), fernet_files_builder.build()
-
-    def build_pod_spec(self, image_info, **kwargs):
-        # Validate config
-        config = ConfigModel(**dict(self.config))
-        mysql_config = kwargs["mysql_config"]
-        config_ldap = ConfigLdapModel(**dict(self.config))
-
-        if mysql_config.mysql_uri and not self.mysql_client.is_missing_data_in_unit():
-            raise Exception("Mysql data cannot be provided via config and relation")
-        # Check relations
-        external_db = True if mysql_config.mysql_uri else False
-        self._check_missing_dependencies(config, external_db)
-
-        # Create Builder for the PodSpec
-        pod_spec_builder = PodSpecV3Builder(
-            enable_security_context=config.security_context
-        )
-        container_builder = ContainerV3Builder(
-            self.app.name,
-            image_info,
-            config.image_pull_policy,
-            run_as_non_root=config.security_context,
-        )
-
-        # Build files
-        credential_keys, fernet_keys = self._get_keys()
-        credential_files, fernet_files = self._build_files(
-            config, credential_keys, fernet_keys
-        )
-
-        # Add pod secrets
-        fernet_keys_secret_name = f"{self.app.name}-fernet-keys-secret"
-        pod_spec_builder.add_secret(
-            fernet_keys_secret_name,
-            {str(key_id): value for (key_id, value) in enumerate(fernet_keys)},
-        )
-        credential_keys_secret_name = f"{self.app.name}-credential-keys-secret"
-        pod_spec_builder.add_secret(
-            credential_keys_secret_name,
-            {str(key_id): value for (key_id, value) in enumerate(credential_keys)},
-        )
-        mysql_secret_name = f"{self.app.name}-mysql-secret"
-
-        pod_spec_builder.add_secret(
-            mysql_secret_name,
-            {
-                "host": mysql_config.host,
-                "port": str(mysql_config.port),
-                "user": mysql_config.username,
-                "password": mysql_config.password,
-            }
-            if mysql_config.mysql_uri
-            else {
-                "host": self.mysql_client.host,
-                "port": str(self.mysql_client.port),
-                "user": "root",
-                "password": self.mysql_client.root_password,
-            },
-        )
-        keystone_secret_name = f"{self.app.name}-keystone-secret"
-        pod_spec_builder.add_secret(
-            keystone_secret_name,
-            {
-                "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,
-            },
-        )
-        # Build Container
-        container_builder.add_volume_config(
-            "credential-keys",
-            CREDENTIAL_KEYS_PATH,
-            credential_files,
-            secret_name=credential_keys_secret_name,
-        )
-        container_builder.add_volume_config(
-            "fernet-keys",
-            FERNET_KEYS_PATH,
-            fernet_files,
-            secret_name=fernet_keys_secret_name,
-        )
-        container_builder.add_port(name=self.app.name, port=PORT)
-        container_builder.add_envs(
-            {
-                "REGION_ID": config.region_id,
-                "KEYSTONE_HOST": self.app.name,
-            }
-        )
-        container_builder.add_secret_envs(
-            secret_name=mysql_secret_name,
-            envs={
-                "DB_HOST": "host",
-                "DB_PORT": "port",
-                "ROOT_DB_USER": "user",
-                "ROOT_DB_PASSWORD": "password",
-            },
-        )
-        container_builder.add_secret_envs(
-            secret_name=keystone_secret_name,
-            envs={
-                "KEYSTONE_DB_PASSWORD": "db_password",
-                "ADMIN_USERNAME": "admin_username",
-                "ADMIN_PASSWORD": "admin_password",
-                "ADMIN_PROJECT": "admin_project",
-                "SERVICE_USERNAME": "service_username",
-                "SERVICE_PASSWORD": "service_password",
-                "SERVICE_PROJECT": "service_project",
-            },
-        )
-        ldap_secret_name = f"{self.app.name}-ldap-secret"
-        if config_ldap.ldap_enabled:
-            # Add ldap secrets and envs
-            ldap_secrets = {
-                "authentication_domain_name": config_ldap.ldap_authentication_domain_name,
-                "url": config_ldap.ldap_url,
-                "page_size": str(config_ldap.ldap_page_size),
-                "user_objectclass": config_ldap.ldap_user_objectclass,
-                "user_id_attribute": config_ldap.ldap_user_id_attribute,
-                "user_name_attribute": config_ldap.ldap_user_name_attribute,
-                "user_pass_attribute": config_ldap.ldap_user_pass_attribute,
-                "user_enabled_mask": str(config_ldap.ldap_user_enabled_mask),
-                "user_enabled_default": config_ldap.ldap_user_enabled_default,
-                "user_enabled_invert": str(config_ldap.ldap_user_enabled_invert),
-                "group_objectclass": config_ldap.ldap_group_objectclass,
-            }
-            ldap_envs = {
-                "LDAP_AUTHENTICATION_DOMAIN_NAME": "authentication_domain_name",
-                "LDAP_URL": "url",
-                "LDAP_PAGE_SIZE": "page_size",
-                "LDAP_USER_OBJECTCLASS": "user_objectclass",
-                "LDAP_USER_ID_ATTRIBUTE": "user_id_attribute",
-                "LDAP_USER_NAME_ATTRIBUTE": "user_name_attribute",
-                "LDAP_USER_PASS_ATTRIBUTE": "user_pass_attribute",
-                "LDAP_USER_ENABLED_MASK": "user_enabled_mask",
-                "LDAP_USER_ENABLED_DEFAULT": "user_enabled_default",
-                "LDAP_USER_ENABLED_INVERT": "user_enabled_invert",
-                "LDAP_GROUP_OBJECTCLASS": "group_objectclass",
-            }
-            if config_ldap.ldap_bind_user:
-                ldap_secrets["bind_user"] = config_ldap.ldap_bind_user
-                ldap_envs["LDAP_BIND_USER"] = "bind_user"
-
-            if config_ldap.ldap_bind_password:
-                ldap_secrets["bind_password"] = config_ldap.ldap_bind_password
-                ldap_envs["LDAP_BIND_PASSWORD"] = "bind_password"
-
-            if config_ldap.ldap_user_tree_dn:
-                ldap_secrets["user_tree_dn"] = config_ldap.ldap_user_tree_dn
-                ldap_envs["LDAP_USER_TREE_DN"] = "user_tree_dn"
-
-            if config_ldap.ldap_user_filter:
-                ldap_secrets["user_filter"] = config_ldap.ldap_user_filter
-                ldap_envs["LDAP_USER_FILTER"] = "user_filter"
-
-            if config_ldap.ldap_user_enabled_attribute:
-                ldap_secrets[
-                    "user_enabled_attribute"
-                ] = config_ldap.ldap_user_enabled_attribute
-                ldap_envs["LDAP_USER_ENABLED_ATTRIBUTE"] = "user_enabled_attribute"
-            if config_ldap.ldap_chase_referrals:
-                ldap_secrets["chase_referrals"] = config_ldap.ldap_chase_referrals
-                ldap_envs["LDAP_CHASE_REFERRALS"] = "chase_referrals"
-
-            if config_ldap.ldap_group_tree_dn:
-                ldap_secrets["group_tree_dn"] = config_ldap.ldap_group_tree_dn
-                ldap_envs["LDAP_GROUP_TREE_DN"] = "group_tree_dn"
-
-            if config_ldap.ldap_tls_cacert_base64:
-                ldap_secrets["tls_cacert_base64"] = config_ldap.ldap_tls_cacert_base64
-                ldap_envs["LDAP_TLS_CACERT_BASE64"] = "tls_cacert_base64"
-
-            if config_ldap.ldap_use_starttls:
-                ldap_secrets["use_starttls"] = str(config_ldap.ldap_use_starttls)
-                ldap_secrets["tls_cacert_base64"] = config_ldap.ldap_tls_cacert_base64
-                ldap_secrets["tls_req_cert"] = config_ldap.ldap_tls_req_cert
-                ldap_envs["LDAP_USE_STARTTLS"] = "use_starttls"
-                ldap_envs["LDAP_TLS_CACERT_BASE64"] = "tls_cacert_base64"
-                ldap_envs["LDAP_TLS_REQ_CERT"] = "tls_req_cert"
-
-            pod_spec_builder.add_secret(
-                ldap_secret_name,
-                ldap_secrets,
-            )
-            container_builder.add_secret_envs(
-                secret_name=ldap_secret_name,
-                envs=ldap_envs,
-            )
-
-        container = container_builder.build()
-
-        # Add container to pod spec
-        pod_spec_builder.add_container(container)
-
-        # Add Pod Restart Policy
-        restart_policy = PodRestartPolicy()
-        restart_policy.add_secrets(
-            secret_names=(mysql_secret_name, keystone_secret_name, ldap_secret_name)
-        )
-        pod_spec_builder.set_restart_policy(restart_policy)
-
-        # Add ingress resources to pod spec if site url exists
-        if config.site_url:
-            parsed = urlparse(config.site_url)
-            annotations = {
-                "nginx.ingress.kubernetes.io/proxy-body-size": "{}".format(
-                    str(config.max_file_size) + "m"
-                    if config.max_file_size > 0
-                    else config.max_file_size
-                )
-            }
-            if config.ingress_class:
-                annotations["kubernetes.io/ingress.class"] = config.ingress_class
-            ingress_resource_builder = IngressResourceV3Builder(
-                f"{self.app.name}-ingress", annotations
-            )
-
-            if config.ingress_whitelist_source_range:
-                annotations[
-                    "nginx.ingress.kubernetes.io/whitelist-source-range"
-                ] = config.ingress_whitelist_source_range
-
-            if parsed.scheme == "https":
-                ingress_resource_builder.add_tls(
-                    [parsed.hostname], config.tls_secret_name
-                )
-            else:
-                annotations["nginx.ingress.kubernetes.io/ssl-redirect"] = "false"
-
-            ingress_resource_builder.add_rule(parsed.hostname, self.app.name, PORT)
-            ingress_resource = ingress_resource_builder.build()
-            pod_spec_builder.add_ingress_resource(ingress_resource)
-        return pod_spec_builder.build()
-
-
-if __name__ == "__main__":
-    main(KeystoneCharm)
-
-# LOGGER = logging.getLogger(__name__)
-
-
-# class ConfigurePodEvent(EventBase):
-#     """Configure Pod event"""
-
-#     pass
-
-
-# class KeystoneEvents(CharmEvents):
-#     """Keystone Events"""
-
-#     configure_pod = EventSource(ConfigurePodEvent)
-
-# class KeystoneCharm(CharmBase):
-#     """Keystone K8s Charm"""
-
-#     state = StoredState()
-#     on = KeystoneEvents()
-
-#     def __init__(self, *args) -> NoReturn:
-#         """Constructor of the Charm object.
-#         Initializes internal state and register events it can handle.
-#         """
-#         super().__init__(*args)
-#         self.state.set_default(db_host=None)
-#         self.state.set_default(db_port=None)
-#         self.state.set_default(db_user=None)
-#         self.state.set_default(db_password=None)
-#         self.state.set_default(pod_spec=None)
-#         self.state.set_default(fernet_keys=None)
-#         self.state.set_default(credential_keys=None)
-#         self.state.set_default(keys_timestamp=0)
-
-#         # Register all of the events we want to observe
-#         self.framework.observe(self.on.config_changed, self.configure_pod)
-#         self.framework.observe(self.on.start, self.configure_pod)
-#         self.framework.observe(self.on.upgrade_charm, self.configure_pod)
-#         self.framework.observe(self.on.leader_elected, self.configure_pod)
-#         self.framework.observe(self.on.update_status, self.configure_pod)
-
-#         # Registering custom internal events
-#         self.framework.observe(self.on.configure_pod, self.configure_pod)
-
-#         # Register relation events
-#         self.framework.observe(
-#             self.on.db_relation_changed, self._on_db_relation_changed
-#         )
-#         self.framework.observe(
-#             self.on.db_relation_broken, self._on_db_relation_broken
-#         )
-#         self.framework.observe(
-#             self.on.keystone_relation_joined, self._publish_keystone_info
-#         )
-
-#     def _publish_keystone_info(self, event: EventBase) -> NoReturn:
-#         """Publishes keystone information for NBI usage through the keystone
-#            relation.
-
-#         Args:
-#             event (EventBase): Keystone relation event to update NBI.
-#         """
-#         config = self.model.config
-#         rel_data = {
-#             "host": f"http://{self.app.name}:{KEYSTONE_PORT}/v3",
-#             "port": str(KEYSTONE_PORT),
-#             "keystone_db_password": config["keystone_db_password"],
-#             "region_id": config["region_id"],
-#             "user_domain_name": config["user_domain_name"],
-#             "project_domain_name": config["project_domain_name"],
-#             "admin_username": config["admin_username"],
-#             "admin_password": config["admin_password"],
-#             "admin_project_name": config["admin_project"],
-#             "username": config["service_username"],
-#             "password": config["service_password"],
-#             "service": config["service_project"],
-#         }
-#         for k, v in rel_data.items():
-#             event.relation.data[self.model.unit][k] = v
-
-#     def _on_db_relation_changed(self, event: EventBase) -> NoReturn:
-#         """Reads information about the DB relation, in order for keystone to
-#            access it.
-
-#         Args:
-#             event (EventBase): DB relation event to access database
-#                                information.
-#         """
-#         if not event.unit in event.relation.data:
-#             return
-#         relation_data = event.relation.data[event.unit]
-#         db_host = relation_data.get("host")
-#         db_port = int(relation_data.get("port", 3306))
-#         db_user = "root"
-#         db_password = relation_data.get("root_password")
-
-#         if (
-#             db_host
-#             and db_port
-#             and db_user
-#             and db_password
-#             and (
-#                 self.state.db_host != db_host
-#                 or self.state.db_port != db_port
-#                 or self.state.db_user != db_user
-#                 or self.state.db_password != db_password
-#             )
-#         ):
-#             self.state.db_host = db_host
-#             self.state.db_port = db_port
-#             self.state.db_user = db_user
-#             self.state.db_password = db_password
-#             self.on.configure_pod.emit()
-
-
-#     def _on_db_relation_broken(self, event: EventBase) -> NoReturn:
-#         """Clears data from db relation.
-
-#         Args:
-#             event (EventBase): DB relation event.
-
-#         """
-#         self.state.db_host = None
-#         self.state.db_port = None
-#         self.state.db_user = None
-#         self.state.db_password = None
-#         self.on.configure_pod.emit()
-
-#     def _check_settings(self) -> str:
-#         """Check if there any settings missing from Keystone configuration.
-
-#         Returns:
-#             str: Information about the problems found (if any).
-#         """
-#         problems = []
-#         config = self.model.config
-
-#         for setting in REQUIRED_SETTINGS:
-#             if not config.get(setting):
-#                 problem = f"missing config {setting}"
-#                 problems.append(problem)
-
-#         return ";".join(problems)
-
-#     def _make_pod_image_details(self) -> Dict[str, str]:
-#         """Generate the pod image details.
-
-#         Returns:
-#             Dict[str, str]: pod image details.
-#         """
-#         config = self.model.config
-#         image_details = {
-#             "imagePath": config["image"],
-#         }
-#         if config["image_username"]:
-#             image_details.update(
-#                 {
-#                     "username": config["image_username"],
-#                     "password": config["image_password"],
-#                 }
-#             )
-#         return image_details
-
-#     def _make_pod_ports(self) -> List[Dict[str, Any]]:
-#         """Generate the pod ports details.
-
-#         Returns:
-#             List[Dict[str, Any]]: pod ports details.
-#         """
-#         return [
-#             {"name": "keystone", "containerPort": KEYSTONE_PORT, "protocol": "TCP"},
-#         ]
-
-#     def _make_pod_envconfig(self) -> Dict[str, Any]:
-#         """Generate pod environment configuraiton.
-
-#         Returns:
-#             Dict[str, Any]: pod environment configuration.
-#         """
-#         config = self.model.config
-
-#         envconfig = {
-#             "DB_HOST": self.state.db_host,
-#             "DB_PORT": self.state.db_port,
-#             "ROOT_DB_USER": self.state.db_user,
-#             "ROOT_DB_PASSWORD": self.state.db_password,
-#             "KEYSTONE_DB_PASSWORD": config["keystone_db_password"],
-#             "REGION_ID": config["region_id"],
-#             "KEYSTONE_HOST": self.app.name,
-#             "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.get("ldap_enabled"):
-#             envconfig["LDAP_AUTHENTICATION_DOMAIN_NAME"] = config[
-#                 "ldap_authentication_domain_name"
-#             ]
-#             envconfig["LDAP_URL"] = config["ldap_url"]
-#             envconfig["LDAP_PAGE_SIZE"] = config["ldap_page_size"]
-#             envconfig["LDAP_USER_OBJECTCLASS"] = config["ldap_user_objectclass"]
-#             envconfig["LDAP_USER_ID_ATTRIBUTE"] = config["ldap_user_id_attribute"]
-#             envconfig["LDAP_USER_NAME_ATTRIBUTE"] = config["ldap_user_name_attribute"]
-#             envconfig["LDAP_USER_PASS_ATTRIBUTE"] = config["ldap_user_pass_attribute"]
-#             envconfig["LDAP_USER_ENABLED_MASK"] = config["ldap_user_enabled_mask"]
-#             envconfig["LDAP_USER_ENABLED_DEFAULT"] = config["ldap_user_enabled_default"]
-#             envconfig["LDAP_USER_ENABLED_INVERT"] = config["ldap_user_enabled_invert"]
-#             envconfig["LDAP_GROUP_OBJECTCLASS"] = config["ldap_group_objectclass"]
-
-#             if config["ldap_bind_user"]:
-#                 envconfig["LDAP_BIND_USER"] = config["ldap_bind_user"]
-
-#             if config["ldap_bind_password"]:
-#                 envconfig["LDAP_BIND_PASSWORD"] = config["ldap_bind_password"]
-
-#             if config["ldap_user_tree_dn"]:
-#                 envconfig["LDAP_USER_TREE_DN"] = config["ldap_user_tree_dn"]
-
-#             if config["ldap_user_filter"]:
-#                 envconfig["LDAP_USER_FILTER"] = config["ldap_user_filter"]
-
-#             if config["ldap_user_enabled_attribute"]:
-#                 envconfig["LDAP_USER_ENABLED_ATTRIBUTE"] = config[
-#                     "ldap_user_enabled_attribute"
-#                 ]
-
-#             if config["ldap_chase_referrals"]:
-#                 envconfig["LDAP_CHASE_REFERRALS"] = config["ldap_chase_referrals"]
-
-#             if config["ldap_group_tree_dn"]:
-#                 envconfig["LDAP_GROUP_TREE_DN"] = config["ldap_group_tree_dn"]
-
-#             if config["ldap_use_starttls"]:
-#                 envconfig["LDAP_USE_STARTTLS"] = config["ldap_use_starttls"]
-#                 envconfig["LDAP_TLS_CACERT_BASE64"] = config["ldap_tls_cacert_base64"]
-#                 envconfig["LDAP_TLS_REQ_CERT"] = config["ldap_tls_req_cert"]
-
-#         return envconfig
-
-#     def _make_pod_ingress_resources(self) -> List[Dict[str, Any]]:
-#         """Generate pod ingress resources.
-
-#         Returns:
-#             List[Dict[str, Any]]: pod ingress resources.
-#         """
-#         site_url = self.model.config["site_url"]
-
-#         if not site_url:
-#             return
-
-#         parsed = urlparse(site_url)
-
-#         if not parsed.scheme.startswith("http"):
-#             return
-
-#         max_file_size = self.model.config["max_file_size"]
-#         ingress_whitelist_source_range = self.model.config[
-#             "ingress_whitelist_source_range"
-#         ]
-
-#         annotations = {
-#             "nginx.ingress.kubernetes.io/proxy-body-size": "{}m".format(max_file_size)
-#         }
-
-#         if ingress_whitelist_source_range:
-#             annotations[
-#                 "nginx.ingress.kubernetes.io/whitelist-source-range"
-#             ] = ingress_whitelist_source_range
-
-#         ingress_spec_tls = None
-
-#         if parsed.scheme == "https":
-#             ingress_spec_tls = [{"hosts": [parsed.hostname]}]
-#             tls_secret_name = self.model.config["tls_secret_name"]
-#             if tls_secret_name:
-#                 ingress_spec_tls[0]["secretName"] = tls_secret_name
-#         else:
-#             annotations["nginx.ingress.kubernetes.io/ssl-redirect"] = "false"
-
-#         ingress = {
-#             "name": "{}-ingress".format(self.app.name),
-#             "annotations": annotations,
-#             "spec": {
-#                 "rules": [
-#                     {
-#                         "host": parsed.hostname,
-#                         "http": {
-#                             "paths": [
-#                                 {
-#                                     "path": "/",
-#                                     "backend": {
-#                                         "serviceName": self.app.name,
-#                                         "servicePort": KEYSTONE_PORT,
-#                                     },
-#                                 }
-#                             ]
-#                         },
-#                     }
-#                 ],
-#             },
-#         }
-#         if ingress_spec_tls:
-#             ingress["spec"]["tls"] = ingress_spec_tls
-
-#         return [ingress]
-
-#     def _generate_keys(self) -> Tuple[List[str], List[str]]:
-#         """Generating new fernet tokens.
-
-#         Returns:
-#             Tuple[List[str], List[str]]: contains two lists of strings. First
-#                                          list contains strings that represent
-#                                          the keys for fernet and the second
-#                                          list contains strins that represent
-#                                          the keys for credentials.
-#         """
-#         fernet_keys = [
-#             Fernet.generate_key().decode() for _ in range(NUMBER_FERNET_KEYS)
-#         ]
-#         credential_keys = [
-#             Fernet.generate_key().decode() for _ in range(NUMBER_CREDENTIAL_KEYS)
-#         ]
-
-#         return (fernet_keys, credential_keys)
-
-#     def configure_pod(self, event: EventBase) -> NoReturn:
-#         """Assemble the pod spec and apply it, if possible.
-
-#         Args:
-#             event (EventBase): Hook or Relation event that started the
-#                                function.
-#         """
-#         if not self.state.db_host:
-#             self.unit.status = WaitingStatus("Waiting for database relation")
-#             event.defer()
-#             return
-
-#         if not self.unit.is_leader():
-#             self.unit.status = ActiveStatus("ready")
-#             return
-
-#         if fernet_keys := self.state.fernet_keys:
-#             fernet_keys = json.loads(fernet_keys)
-
-#         if credential_keys := self.state.credential_keys:
-#             credential_keys = json.loads(credential_keys)
-
-#         now = datetime.now().timestamp()
-#         keys_timestamp = self.state.keys_timestamp
-#         token_expiration = self.model.config["token_expiration"]
-
-#         valid_keys = (now - keys_timestamp) < token_expiration
-#         if not credential_keys or not fernet_keys or not valid_keys:
-#             fernet_keys, credential_keys = self._generate_keys()
-#             self.state.fernet_keys = json.dumps(fernet_keys)
-#             self.state.credential_keys = json.dumps(credential_keys)
-#             self.state.keys_timestamp = now
-
-#         # Check problems in the settings
-#         problems = self._check_settings()
-#         if problems:
-#             self.unit.status = BlockedStatus(problems)
-#             return
-
-#         self.unit.status = BlockedStatus("Assembling pod spec")
-#         image_details = self._make_pod_image_details()
-#         ports = self._make_pod_ports()
-#         env_config = self._make_pod_envconfig()
-#         ingress_resources = self._make_pod_ingress_resources()
-#         files = self._make_pod_files(fernet_keys, credential_keys)
-
-#         pod_spec = {
-#             "version": 3,
-#             "containers": [
-#                 {
-#                     "name": self.framework.model.app.name,
-#                     "imageDetails": image_details,
-#                     "ports": ports,
-#                     "envConfig": env_config,
-#                     "volumeConfig": files,
-#                 }
-#             ],
-#             "kubernetesResources": {"ingressResources": ingress_resources or []},
-#         }
-
-#         if self.state.pod_spec != (
-#             pod_spec_json := json.dumps(pod_spec, sort_keys=True)
-#         ):
-#             self.state.pod_spec = pod_spec_json
-#             self.model.pod.set_spec(pod_spec)
-
-#         self.unit.status = ActiveStatus("ready")
-
-
-# if __name__ == "__main__":
-#     main(KeystoneCharm)
diff --git a/installers/charm/keystone/tests/__init__.py b/installers/charm/keystone/tests/__init__.py
deleted file mode 100644 (file)
index 446d5ce..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/env python3
-# Copyright 2020 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
-##
-
-"""Init mocking for unit tests."""
-
-import sys
-
-
-import mock
-
-
-class OCIImageResourceErrorMock(Exception):
-    pass
-
-
-sys.path.append("src")
-
-oci_image = mock.MagicMock()
-oci_image.OCIImageResourceError = OCIImageResourceErrorMock
-sys.modules["oci_image"] = oci_image
-sys.modules["oci_image"].OCIImageResource().fetch.return_value = {}
diff --git a/installers/charm/keystone/tests/test_charm.py b/installers/charm/keystone/tests/test_charm.py
deleted file mode 100644 (file)
index 2a95029..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-#!/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
-##
-
-import sys
-from typing import NoReturn
-import unittest
-
-
-from charm import KeystoneCharm
-from ops.model import ActiveStatus, BlockedStatus
-from ops.testing import Harness
-
-
-class TestCharm(unittest.TestCase):
-    """Keystone Charm unit tests."""
-
-    def setUp(self) -> NoReturn:
-        """Test setup"""
-        self.image_info = sys.modules["oci_image"].OCIImageResource().fetch()
-        self.harness = Harness(KeystoneCharm)
-        self.harness.set_leader(is_leader=True)
-        self.harness.begin()
-        self.config = {
-            "region_id": "str",
-            "keystone_db_password": "str",
-            "mysql_host": "",
-            "mysql_port": 3306,
-            "mysql_root_password": "manopw",
-            "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": 10,
-            "max_file_size": 1,
-            "site_url": "http://keystone.com",
-            "ldap_enabled": False,
-        }
-        self.harness.update_config(self.config)
-
-    def test_config_changed_no_relations(
-        self,
-    ) -> NoReturn:
-        """Test ingress resources without HTTP."""
-
-        self.harness.charm.on.config_changed.emit()
-
-        # Assertions
-        self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
-        self.assertTrue(
-            all(
-                relation in self.harness.charm.unit.status.message
-                for relation in ["mysql"]
-            )
-        )
-
-    def test_config_changed_non_leader(
-        self,
-    ) -> NoReturn:
-        """Test ingress resources without HTTP."""
-        self.harness.set_leader(is_leader=False)
-        self.harness.charm.on.config_changed.emit()
-
-        # Assertions
-        self.assertIsInstance(self.harness.charm.unit.status, ActiveStatus)
-
-    def test_with_config(self) -> NoReturn:
-        "Test with mysql config"
-        self.initialize_mysql_config()
-        # Verifying status
-        self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
-
-    def test_with_relations(
-        self,
-    ) -> NoReturn:
-        "Test with relations"
-        self.initialize_mysql_relation()
-        # Verifying status
-        self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
-
-    def test_exception_mysql_relation_and_config(
-        self,
-    ) -> NoReturn:
-        "Test with relations and config. Must throw exception"
-        self.initialize_mysql_config()
-        self.initialize_mysql_relation()
-        # Verifying status
-        self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
-
-    def initialize_mysql_config(self):
-        self.harness.update_config({"mysql_uri": "mysql://root:manopw@mysql:3306/"})
-
-    def initialize_mysql_relation(self):
-        relation_id = self.harness.add_relation("db", "mysql")
-        self.harness.add_relation_unit(relation_id, "mysql/0")
-        self.harness.update_relation_data(
-            relation_id,
-            "mysql/0",
-            {
-                "host": "mysql",
-                "port": 3306,
-                "user": "mano",
-                "password": "manopw",
-                "root_password": "rootmanopw",
-            },
-        )
-
-
-if __name__ == "__main__":
-    unittest.main()
-
-
-# class TestCharm(unittest.TestCase):
-#     """Prometheus Charm unit tests."""
-
-#     def setUp(self) -> NoReturn:
-#         """Test setup"""
-#         self.image_info = sys.modules["oci_image"].OCIImageResource().fetch()
-#         self.harness = Harness(KeystoneCharm)
-#         self.harness.set_leader(is_leader=True)
-#         self.harness.begin()
-#         self.config = {
-#             "enable_ng_ro": True,
-#             "database_commonkey": "commonkey",
-#             "log_level": "INFO",
-#             "vim_database": "db_name",
-#             "ro_database": "ro_db_name",
-#             "openmano_tenant": "mano",
-#         }
-
-#     def test_config_changed_no_relations(
-#         self,
-#     ) -> NoReturn:
-#         """Test ingress resources without HTTP."""
-
-#         self.harness.charm.on.config_changed.emit()
-
-#         # Assertions
-#         self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
-#         self.assertTrue(
-#             all(
-#                 relation in self.harness.charm.unit.status.message
-#                 for relation in ["mongodb", "kafka"]
-#             )
-#         )
-
-#         # Disable ng-ro
-#         self.harness.update_config({"enable_ng_ro": False})
-#         self.assertIsInstance(self.harness.charm.unit.status, BlockedStatus)
-#         self.assertTrue(
-#             all(
-#                 relation in self.harness.charm.unit.status.message
-#                 for relation in ["mysql"]
-#             )
-#         )
-
-#     def test_config_changed_non_leader(
-#         self,
-#     ) -> NoReturn:
-#         """Test ingress resources without HTTP."""
-#         self.harness.set_leader(is_leader=False)
-#         self.harness.charm.on.config_changed.emit()
-
-#         # Assertions
-#         self.assertIsInstance(self.harness.charm.unit.status, ActiveStatus)
-
-#     def test_with_relations_ng(
-#         self,
-#     ) -> NoReturn:
-#         "Test with relations (ng-ro)"
-
-#         # Initializing the kafka relation
-#         kafka_relation_id = self.harness.add_relation("kafka", "kafka")
-#         self.harness.add_relation_unit(kafka_relation_id, "kafka/0")
-#         self.harness.update_relation_data(
-#             kafka_relation_id, "kafka/0", {"host": "kafka", "port": 9092}
-#         )
-
-#         # Initializing the mongo relation
-#         mongodb_relation_id = self.harness.add_relation("mongodb", "mongodb")
-#         self.harness.add_relation_unit(mongodb_relation_id, "mongodb/0")
-#         self.harness.update_relation_data(
-#             mongodb_relation_id,
-#             "mongodb/0",
-#             {"connection_string": "mongodb://mongo:27017"},
-#         )
-
-#         self.harness.charm.on.config_changed.emit()
-
-#         # Verifying status
-#         self.assertNotIsInstance(self.harness.charm.unit.status, BlockedStatus)
-
-
-# if __name__ == "__main__":
-#     unittest.main()
diff --git a/installers/charm/keystone/tox.ini b/installers/charm/keystone/tox.ini
deleted file mode 100644 (file)
index 88fd16a..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-# 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
-##
-#######################################################################################
-
-[tox]
-envlist = black, cover, flake8, pylint, yamllint, safety
-skipsdist = true
-
-[tox:jenkins]
-toxworkdir = /tmp/.tox
-
-[testenv]
-basepython = python3.8
-setenv = VIRTUAL_ENV={envdir}
-         PYTHONDONTWRITEBYTECODE = 1
-deps =  -r{toxinidir}/requirements.txt
-
-
-#######################################################################################
-[testenv:black]
-deps = black
-commands =
-        black --check --diff src/ tests/
-
-
-#######################################################################################
-[testenv:cover]
-deps =  {[testenv]deps}
-        -r{toxinidir}/requirements-test.txt
-        coverage
-        nose2
-commands =
-        sh -c 'rm -f nosetests.xml'
-        coverage erase
-        nose2 -C --coverage src
-        coverage report --omit='*tests*'
-        coverage html -d ./cover --omit='*tests*'
-        coverage xml -o coverage.xml --omit=*tests*
-whitelist_externals = sh
-
-
-#######################################################################################
-[testenv:flake8]
-deps =  flake8
-        flake8-import-order
-commands =
-        flake8 src/ tests/
-
-
-#######################################################################################
-[testenv:pylint]
-deps =  {[testenv]deps}
-        -r{toxinidir}/requirements-test.txt
-        pylint==2.10.2
-commands =
-    pylint -E src/ tests/
-
-
-#######################################################################################
-[testenv:safety]
-setenv =
-        LC_ALL=C.UTF-8
-        LANG=C.UTF-8
-deps =  {[testenv]deps}
-        safety
-commands =
-        - safety check --full-report
-
-
-#######################################################################################
-[testenv:yamllint]
-deps =  {[testenv]deps}
-        -r{toxinidir}/requirements-test.txt
-        yamllint
-commands = yamllint .
-
-#######################################################################################
-[testenv:build]
-passenv=HTTP_PROXY HTTPS_PROXY NO_PROXY
-whitelist_externals =
-  charmcraft
-  sh
-commands =
-  charmcraft pack
-  sh -c 'ubuntu_version=20.04; \
-        architectures="amd64-aarch64-arm64"; \
-        charm_name=`cat metadata.yaml | grep -E "^name: " | cut -f 2 -d " "`; \
-        mv $charm_name"_ubuntu-"$ubuntu_version-$architectures.charm $charm_name.charm'
-
-#######################################################################################
-[flake8]
-ignore =
-        W291,
-        W293,
-        W503,
-        E123,
-        E125,
-        E226,
-        E241,
-exclude =
-        .git,
-        __pycache__,
-        .tox,
-max-line-length = 120
-show-source = True
-builtins = _
-; max-complexity = 10
-import-order-style = google