Add keystone charm and interface

- Bundles updated
- Installer updated

Change-Id: I0f8e9aafd51e9579159f9166864eb8634292f99c
Signed-off-by: David Garcia <david.garcia@canonical.com>
diff --git a/installers/charm/interfaces/keystone/interface.yaml b/installers/charm/interfaces/keystone/interface.yaml
new file mode 100644
index 0000000..be1d09b
--- /dev/null
+++ b/installers/charm/interfaces/keystone/interface.yaml
@@ -0,0 +1,16 @@
+# 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: Keystone Interface
+version: 1
diff --git a/installers/charm/interfaces/keystone/provides.py b/installers/charm/interfaces/keystone/provides.py
new file mode 100644
index 0000000..bda5d2f
--- /dev/null
+++ b/installers/charm/interfaces/keystone/provides.py
@@ -0,0 +1,63 @@
+# 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.
+from charms.reactive import Endpoint
+from charms.reactive import when
+from charms.reactive import set_flag, clear_flag
+
+
+class KeystoneProvides(Endpoint):
+    @when("endpoint.{endpoint_name}.joined")
+    def _joined(self):
+        set_flag(self.expand_name("{endpoint_name}.joined"))
+
+    @when("endpoint.{endpoint_name}.changed")
+    def _changed(self):
+        set_flag(self.expand_name("{endpoint_name}.ready"))
+
+    @when("endpoint.{endpoint_name}.departed")
+    def _departed(self):
+        set_flag(self.expand_name("{endpoint_name}.departed"))
+        clear_flag(self.expand_name("{endpoint_name}.joined"))
+
+    def publish_info(
+        self,
+        host,
+        port,
+        keystone_db_password,
+        region_id,
+        user_domain_name,
+        project_domain_name,
+        admin_username,
+        admin_password,
+        admin_project_name,
+        username,
+        password,
+        service,
+    ):
+        for relation in self.relations:
+            relation.to_publish["host"] = host
+            relation.to_publish["port"] = port
+            relation.to_publish["keystone_db_password"] = keystone_db_password
+            relation.to_publish["region_id"] = region_id
+            relation.to_publish["user_domain_name"] = user_domain_name
+            relation.to_publish["project_domain_name"] = project_domain_name
+            relation.to_publish["admin_username"] = admin_username
+            relation.to_publish["admin_password"] = admin_password
+            relation.to_publish["admin_project_name"] = admin_project_name
+            relation.to_publish["username"] = username
+            relation.to_publish["password"] = password
+            relation.to_publish["service"] = service
+
+    def mark_complete(self):
+        clear_flag(self.expand_name("{endpoint_name}.joined"))
diff --git a/installers/charm/interfaces/keystone/requires.py b/installers/charm/interfaces/keystone/requires.py
new file mode 100644
index 0000000..c0d8d47
--- /dev/null
+++ b/installers/charm/interfaces/keystone/requires.py
@@ -0,0 +1,72 @@
+# 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.
+from charms.reactive import Endpoint
+from charms.reactive import when
+from charms.reactive import set_flag, clear_flag
+
+
+class KeystoneRequires(Endpoint):
+    @when("endpoint.{endpoint_name}.joined")
+    def _joined(self):
+        set_flag(self.expand_name("{endpoint_name}.joined"))
+
+    @when("endpoint.{endpoint_name}.changed")
+    def _changed(self):
+        if len(self.keystones()) > 0:
+            set_flag(self.expand_name("{endpoint_name}.ready"))
+        else:
+            clear_flag(self.expand_name("{endpoint_name}.ready"))
+
+    @when("endpoint.{endpoint_name}.departed")
+    def _departed(self):
+        set_flag(self.expand_name("{endpoint_name}.departed"))
+        clear_flag(self.expand_name("{endpoint_name}.joined"))
+        clear_flag(self.expand_name("{endpoint_name}.ready"))
+
+    def keystones(self):
+        """
+        Return Keystone Data:
+        [{
+            'host': <host>,
+            'port': <port>,
+            'keystone_db_password: <keystone_db_password>,
+            'region_id: <region_id>,
+            'admin_username: <admin_username>,
+            'admin_password: <admin_password>,
+            'admin_project_name: <admin_project_name>,
+            'username: <username>,
+            'password: <password>,
+            'service: <service>
+        }]
+        """
+        keystones = []
+        for relation in self.relations:
+            for unit in relation.units:
+                data = {
+                    "host": unit.received["host"],
+                    "port": unit.received["port"],
+                    "keystone_db_password": unit.received["keystone_db_password"],
+                    "region_id": unit.received["region_id"],
+                    "user_domain_name": unit.received["user_domain_name"],
+                    "project_domain_name": unit.received["project_domain_name"],
+                    "admin_username": unit.received["admin_username"],
+                    "admin_password": unit.received["admin_password"],
+                    "admin_project_name": unit.received["admin_project_name"],
+                    "username": unit.received["username"],
+                    "password": unit.received["password"],
+                    "service": unit.received["service"],
+                }
+                if all(data.values()):
+                    keystones.append(data)
+        return keystones