# 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 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 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 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): """List services matching category""" res = [] for srv in self.all_services: if environment: if "environment" in srv and srv["environment"] != environment: continue if srv["service_category"] == category: res.append(copy.deepcopy(srv)) return res def services_with_docs_by_category(self, category, 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) res_doc.update(**service) if environment: if "environment" in doc and doc["environment"] != environment: continue res[cat].setdefault("docs", []) res[cat]["docs"].append(res_doc) return res def service_types_with_doc_types(self, 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: if "environment" in service: if service["environment"] != environment: continue if not service["service_title"]: continue if not service["service_type"]: continue doc_list = [] for doc in self.all_docs: if "environment" in doc: if doc["environment"] != environment: 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 services matching category :param str category: Category name :param str env: 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: res_doc = copy.deepcopy(doc) res_doc.update(**service) if environment: for srv_env in service["repositories"]: if srv_env.get("environment") == environment: res_doc["repository"] = srv_env["repo"] 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""" services = self.service_dict for doc in self.all_docs: if not doc["service_type"] in services: print(f"No service type {doc['service_type']}") continue service = services[doc["service_type"]] res_doc = copy.deepcopy(doc) res_doc.update(**service) if environment: for srv_env in service["repositories"]: if srv_env.get("environment") == environment: res_doc["repository"] = srv_env["repo"] for srv_assignees in service.get("assignees", []): if srv_assignees.get("environment") == environment: res_doc["assignees"] = srv_assignees["names"] yield res_doc def docs_html_by_category(self, 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" ] if "repositories" in srv and environment: for repo in srv["repositories"]: if ( "environment" in repo and repo["environment"] == environment ): srv_res["repository"] = repo["repo"] 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"] 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 break return res