# 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. import copy import warnings import json import otc_metadata.data __all__ = ["Services"] BUILTIN_DATA = otc_metadata.data.read_data("services.yaml") def _normalize_type(service_type): if service_type: return service_type.replace("_", "-") class Services(object): """Encapsulation of the OTC Services data""" def __init__(self): self._service_data = BUILTIN_DATA def _sort_data(self): # Sort every doc item by key sorted_docs = [] for doc in self._service_data["documents"]: sorted_docs.append(dict(sorted(doc.items(), key=lambda kv: kv[0]))) # sort docs list by _ self._service_data["documents"] = sorted( sorted_docs, key=lambda x: f"{x.get('service_type')}{x.get('title')}", ) # sort services by <service_type>_<service_title> self._service_data["services"] = sorted( self._service_data["services"], key=lambda x: f"{x.get('service_type')}{x.get('service_title')}", ) # sort repositories by <service_type> self._service_data["repositories"] = sorted( self._service_data["repositories"], key=lambda x: f"{x.get('service_type')}", ) # sort service categories by <name>_<title> self._service_data["service_categories"] = sorted( self._service_data["service_categories"], key=lambda x: f"{x.get('name')}{x.get('title')}", ) other = {'name': 'other', 'title': 'Other'} if other in self._service_data["service_categories"]: self._service_data["service_categories"].remove(other) self._service_data["service_categories"].append(other) def _rewrite_data(self): otc_metadata.data.rewrite_data("services.yaml", self._service_data) @property def all_services(self): "Service Categories data listing." return copy.deepcopy(self._service_data["services"]) @property def all_docs(self): "Service Docs data listing." return copy.deepcopy(self._service_data["documents"]) @property def all_repositories(self): "Service Repositories data listing." return copy.deepcopy(self._service_data["repositories"]) @property def service_dict(self): "Service Docs data listing." res = dict() for srv in self.all_services: res[srv["service_type"]] = copy.deepcopy(srv) return res @property def service_categories(self): """List services categories""" res = [] for cat in self._service_data["service_categories"]: res.append(copy.deepcopy(cat)) return res def services_by_category(self, category, environment=None, cloud_environment=None): """List services matching category""" res = [] for srv in self.all_services: if environment and cloud_environment: cloud_environment_check = False if srv["is_global"] is not True: for srv_cloud_environment in srv["cloud_environments"]: if srv_cloud_environment["name"] == cloud_environment: if srv_cloud_environment["visibility"] == environment: cloud_environment_check = True else: continue if cloud_environment_check is False: continue if srv["service_category"] == category: for repositories in self.all_repositories: if repositories["service_type"] == srv["service_type"]: srv["repositories"] = repositories["repositories"] res.append(copy.deepcopy(srv)) return res def services_with_docs_by_category(self, category, environment=None, cloud_environment=None): """Retrieve service category docs data :param str category: Optional Category filter :param str env: Optional service environment. Influeces "repository" field """ res = dict() services = self.service_dict for doc in self.all_docs: cat = doc["service_type"] service = services.get(cat) if not service: warnings.warn("No Service defition of type %s" % (cat)) continue if category and service["service_category"] != category: continue res.setdefault(cat, service) res_doc = copy.deepcopy(doc) if environment and cloud_environment: cloud_environment_check = False for doc_cloud_environment in doc["cloud_environments"]: if doc_cloud_environment["name"] == cloud_environment: if doc_cloud_environment["visibility"] == environment: cloud_environment_check = True else: continue if cloud_environment_check is False: continue for repositories in self.all_repositories: if repositories["service_type"] == service["service_type"]: res["repositories"] = repositories["repositories"] res[cat].setdefault("docs", []) res[cat]["docs"].append(res_doc) return res def service_types_with_doc_types(self, cloud_environment, environment=None): """Retrieve type and title from services and corresponding docs. As well as a list of all available doc types with title. :param str environment: Optional service environment. """ service_list = [] docs = [] for service in self.all_services: cloud_environment_service_check = False cloud_visibility_check = False if service["is_global"] is not True: for cloud_environment_service in service["cloud_environments"]: if cloud_environment_service["name"] == cloud_environment: cloud_environment_service_check = True if environment: if cloud_environment_service["visibility"] == environment: cloud_visibility_check = True else: cloud_visibility_check = True break if cloud_environment_service_check is False or cloud_visibility_check is False: continue if not service["service_title"]: continue if not service["service_type"]: continue doc_list = [] for doc in self.all_docs: cloud_environment_doc_check = False cloud_doc_visibility_check = False for cloud_environment_doc in doc["cloud_environments"]: if cloud_environment_doc["name"] == cloud_environment: cloud_environment_doc_check = True if environment: if cloud_environment_service["visibility"] == environment: cloud_doc_visibility_check = True else: cloud_doc_visibility_check = True break if cloud_environment_doc_check is False or cloud_doc_visibility_check is False: continue if doc["service_type"] == service["service_type"]: doc_list.append({ "title": doc["title"], "type": doc["type"] }) new_doc = { "type": doc["type"], "title": doc["title"] } type_exists = any( doc_dict["type"] == new_doc["type"] for doc_dict in docs ) if not type_exists: docs.append(new_doc) service_list.append({ "service_title": service["service_title"], "service_type": service["service_type"], "docs": doc_list }) res = { "services": service_list, "docs": docs } return res def docs_by_service_category(self, category, environment=None): """List docs matching category :param str category: Category name :param str environment: Optional service environment. Influeces "repository" field """ res = [] services = self.service_dict for doc in self.all_docs: cat = doc["service_type"] service = services.get(cat) if not service: warnings.warn("No Service defition of type %s" % (cat)) continue if service["service_category"] == category: for repositories in self.all_repositories: if repositories["service_type"] == service["service_type"]: res_doc = copy.deepcopy(doc) res_doc["repositories"] = repositories["repositories"] res_doc.update(**service) # Get the cloud environments from the document instead of service res_doc["cloud_environments"] = doc["cloud_environments"] if environment: repo_env_filter = [] for repo in repositories["repositories"]: if repo["environment"] == environment: repo_env_filter.append(repo) res_doc["repositories"] = repo_env_filter res.append(res_doc) return res def docs_by_service_type(self, service_type): """List documents of the service :param str service_type: Service type :returns: generator for documents """ for doc in self.all_docs: if doc["service_type"] != service_type: continue yield copy.deepcopy(doc) def all_docs_full(self, environment): """Return list or documents with full service data""" res = [] services = self.service_dict for doc in self.all_docs: cat = doc["service_type"] service = services.get(cat) if not service: warnings.warn("No Service defition of type %s" % (cat)) continue for repositories in self.all_repositories: if repositories["service_type"] == service["service_type"]: res_doc = copy.deepcopy(doc) res_doc["repositories"] = repositories["repositories"] res_doc.update(**service) # Get the cloud environments from the document instead of service res_doc["cloud_environments"] = doc["cloud_environments"] if environment: repo_env_filter = [] for repo in repositories["repositories"]: if repo["environment"] == environment: repo_env_filter.append(repo) res_doc["repositories"] = repo_env_filter res.append(res_doc) return res def docs_html_by_category(self, environment, cloud_environment): """Generate structure for doc-exports repository""" doc_struct = dict() for srv in self.all_services: doc_struct.setdefault(srv["service_category"], []) srv_res = dict( service_title=srv["service_title"], service_type=srv["service_type"], service_category=srv["service_category"], service_environment=environment, docs=[], ) if "teams" in srv: srv_res["teams"] = [ x for x in srv["teams"] if x["permission"] == "write" ] srv["repositories"] = [] for repositories in self.all_repositories: if repositories["service_type"] == srv["service_type"]: for single_repo in repositories["repositories"]: if single_repo["cloud_environments"][0] == cloud_environment: srv["repositories"].append(single_repo) if "repositories" in srv and environment: internal_exists = False for repo in srv["repositories"]: if ( "environment" in repo and repo["environment"] == environment ): srv_res["repository"] = repo["repo"] if repo["environment"] == "internal": internal_exists = True # internal repo does not exist # service will be left out from metadata.yaml if not internal_exists: continue for doc in self.all_docs: if ( "html_location" in doc and doc["service_type"] == srv_res["service_type"] ): doc_res = dict( html_location=doc["html_location"], rst_location=doc["rst_location"], title=doc["title"], type=doc.get("type", "dummy"), link=doc["link"], ) if "pdf_name" in doc: doc_res["pdf_name"] = doc["pdf_name"] if "hc_location" in doc: doc_res["hc_location"] = doc["hc_location"] if "disable_import" in doc: doc_res["disable_import"] = doc["disable_import"] else: doc_res["disable_import"] = False srv_res["docs"].append(doc_res) if len(srv_res["docs"]) > 0: doc_struct[srv["service_category"]].append(srv_res) return dict(categories=doc_struct) def get_service_with_docs_by_service_type(self, service_type): """Retrieve service and service docs by service_type :param str service_type: Filter by service_type """ res = dict() res["service"] = {} docs = [] services = self._service_data for doc in services["documents"]: if doc["service_type"] == service_type: docs.append(doc) res["documents"] = docs for service in services["services"]: if service["service_type"] == service_type: res["service"] = service for repositories in self.all_repositories: if repositories["service_type"] == service["service_type"]: res["service"]["repositories"] = repositories["repositories"] break break return res def get_service_with_repo_by_service_type(self, service_type): """Retrieve service with repos by service_type :param str service_type: Filter by service_type """ res = dict() res = {} services = self.all_services for service in services: if service["service_type"] == service_type: res = service for repositories in self.all_repositories: if repositories["service_type"] == service["service_type"]: res["repositories"] = repositories["repositories"] break break return res def services_with_repos(self): """Retrieve all services with repos """ res = [] services = self.all_services for i, service in enumerate(services): res.append(service) for repositories in self.all_repositories: if repositories["service_type"] == service["service_type"]: res[i]["repositories"] = repositories["repositories"] break return res def all_services_by_categories(self, cloud_environment, environments): """Retrieve all services sorted by categories """ res = self.service_categories for i, category in enumerate(res): res[i]["services"] = [] for srv in self.all_services: if environments and cloud_environment: cloud_environment_check = False if srv["is_global"] is not True: for srv_cloud_environment in srv["cloud_environments"]: if srv_cloud_environment["name"] == cloud_environment: for environment in environments: if srv_cloud_environment["visibility"] == environment: cloud_environment_check = True else: continue if cloud_environment_check is False: continue for i, category in enumerate(res): if category["name"] == srv["service_category"]: res[i]["services"].append(srv) # Sort services for category in res: category["services"].sort(key=lambda x: x.get("service_title", "").lower()) # Sort categories res.sort(key=lambda x: x.get("name", "").lower()) return res