def __pull_out_type_from_schema(self, schema, field): # static 경고 무시용. dummy = self._me schema_to_string = str(schema) schema_to_dict = json.loads(schema_to_string) data_list = schema_to_dict["data"] for row in data_list: try: # 하나의 schema data로부터 id를 추출. row_id = row["id"] # id가 persistentVolume인지를 확인. if row_id == PersistentVolumesConstant.PERSISTENT_VOLUME: # resourceFields를 추출. resource_fields = row["resourceFields"] # resourceFields로부터 field에 해당하는 Data를 추출. field_values = resource_fields[field] # field에 해당하는 data로부터 type을 추출. return field_values["type"] except Exception as ex: DummyError("Invalid schema." + "\n" + schema, ex) raise DummyError("field type doesn't exist in schema." + "\nfield:" + field + "\n" + schema)
def __targets_refactoring(self, application, clusters_mapping, projects_mapping): """ 대상 application 의 targets 의 target 정보를 기반으로 cluster 와 project 명을 추출하고, 추출한 cluster, project 명을 target 에 넣어준다.\n :param application: 대상 application :param clusters_mapping: cluster 명을 추출할 cluster mapping data :param projects_mapping: project 명을 추출할 project mapping data :return: refactoring 한 targets """ refactoring_result = [] targets = application['targets'] for target in targets: # project id 추출 project_id = target['projectId'] # cluster id 추출 colon_index = project_id.find(':') if colon_index == -1: raise DummyError("[targets.clusterId] has not colon.\n" + project_id) cluster_id = project_id[:colon_index] # cluster id 를 기반으로 해당 cluster 의 row 습득. cluster_row = self._me.__find_by_key_then_get_row( clusters_mapping, 'id', cluster_id) if cluster_row is None: raise DummyError("[clusters] does not include this id.\nid:" + cluster_id) # project id 를 기반으로 해당 project 의 row 습득. project_row = self._me.__find_by_key_then_get_row( projects_mapping, 'id', project_id) if cluster_row is None: raise DummyError("[projects] does not include this id.\nid:" + project_id) # cluster row 로부터 name 을 추출. target[Constant.CLUSTER_NAME] = cluster_row['name'] # project row 로부터 name 을 추출. target[Constant.PROJECT_NAME] = project_row['name'] # refactoring 한 target 을 결과 list 에 추가. refactoring_result.append(target.copy()) return refactoring_result
def __pull_out_field_name(self, options): """ View로부터 받은 payload로부터 Volume Source의 Field Name을 추출한다.\n :param options: View로부터 받은 payload :return: 추출한 Field Name. """ # static 경고 무시용. dummy = self._me # volume source mapping을 습득. volume_sources = PersistentVolumesConstant.VOLUME_SOURCE_DICTIONARY[PersistentVolumesConstant.VOLUME_SOURCE] # volume source mapping을 순회하면서 field를 추출하여 반환. for volume_source_value in volume_sources.values(): try: # 현재의 field명을 습득. current_field = volume_source_value[PersistentVolumesConstant.FIELD] # 현재 field명에 해당하는 정보가 options에 있는지 확인. # 만약 없을 경우, KeyError Exception이 발생하여 건너뛰게 됨. checker = options[current_field] # 있을 경우, 현재의 field를 반환. return current_field # 해당 field명에 부합하는 Data가 없을 경우, Key Error가 발생. 이 경우 무시. except KeyError: pass # 어느 Field에도 해당하지 않을 경우, Error를 반환함. # 보통은 부정적인 접근이나 또는 Coding Error로 인해 발생. ( Coding Error로 인한 발생이 거의 대부분일듯. ) raise DummyError("volume source field doesn't exist. please check your data." + "\n" + json.dumps(options))
def __refactoring_field(self, persistent_volume, field_name): # static 경고 제거용. dummy = self._me can_write_plugin = persistent_volume[field_name] if field_name == "hostPath": deeper = PersistentVolumesConstant.VOLUME_SOURCE_DICTIONARY[ PersistentVolumesConstant.VOLUME_SOURCE] deeper = deeper[PersistentVolumesConstant.TITLE_HOST_PATH] deeper = deeper[PersistentVolumesConstant.CONFIGURATION] deeper = deeper["kind"] deeper = deeper["items"] for item in deeper: if item["value"] == can_write_plugin["kind"]: deeper = item["label"] break deeper = None # TODO: error 내용 제대로 쓸 필요 있음. if deeper is None: raise DummyError("error..") can_write_plugin["kind"] = deeper return can_write_plugin
def add_form_persistent_volume(self, storage_classes): # 원본 data의 변동을 막기 위해 임시로 storage class dictionary를 복사한다. storage_classes_template_dict = PersistentVolumeConstant.VOLUME_SOURCE_DICTIONARY[ PersistentVolumeConstant.VOLUME_SOURCE].copy() result_view_write = { PersistentVolumeConstant.TITLE: "Add Persistent Volume" , PersistentVolumeConstant.VOLUME_SOURCES: self._me.__remove_unsupported(storage_classes_template_dict) , PersistentVolumeConstant.VOLUME_SOURCES_STRING: json.dumps( self._me.__remove_unsupported(storage_classes_template_dict)) , PersistentVolumeConstant.SELECTOR_OPERATOR: json.dumps(self._me.__get_volume_node_selector_operator()) , PersistentVolumeConstant.ACCESS_MODES: PersistentVolumeConstant.FORM_ACCESS_MODES } # RestObject 를 dictionary 객체로 변환 try: dict_storage_classes = JsonUtility.call().to_dictionary(storage_classes) except DummyError as de: raise de # dictionary 로부터 'data' dictionary를 추출. try: storage_classes_mapping = dict_storage_classes['data'] except KeyError: raise DummyError("storageClass['data'] row is not eixsts. please check your data.") result_view_write[PersistentVolumeConstant.STORAGE_CLASSES] = \ self._me.__get_all_storage_class_id(storage_classes_mapping) return result_view_write
def _detail_persistent_volume(self, options): # API로부터 특정 persistent volume만을 추출. persistent_volume = self._me.__caller.list_persistent_volumes(options) # 특정 persistent volume을 가공 처리. # 실제 결과는 1개이지만, list 형식으로 불려오게 됨. models = self._me.__lister.list_persistent_volumes(persistent_volume) if len(models) > 1: DummyError("Results are too many.") # list로부터 결과를 추출. model = self._me.__rower.row_persistent_volume(models[0]) return model
def list_persistent_volumes(self, persistent_volumes): """ API로부터 얻은 모든 Persistent Volumes를 View에 맞추어서 가공하여 반환한다.\n :param persistent_volumes: API로부터 얻은 모든 Persistent Volumes. :return: 가공 결과. """ result_persistent_volumes = [] # RestObject 를 dictionary 객체로 변환 try: dict_persistent_volumes = JsonUtility.call().to_dictionary( persistent_volumes) except DummyError as de: raise de # dictionary로부터 data를 추출 try: persistent_volumes_mapping = dict_persistent_volumes['data'] except KeyError: raise DummyError( "persistent_volumes['data'] row is not eixsts. please check your data." ) for persistent_volume in persistent_volumes_mapping: can_write_persistent_volume = persistent_volume.copy() # 해당 persistent volume의 삭제 가능 여부 flag setting. can_write_persistent_volume[ PersistentVolumesConstant.CAN_REMOVE] = self.__can_remove( persistent_volume) try: # Persistent Volume의 Source 를 얻음. can_write_persistent_volume[ PersistentVolumesConstant.SOURCE] = self.__getSource( persistent_volume) # source가 존재하지 않을 경우 무시. except Exception as e: raise e result_persistent_volumes.append( can_write_persistent_volume.copy()) return result_persistent_volumes
def string_to_datetime(self, string, formatting): """ 시간 문자열을 <datetime> 형식으로 변환.\n :param string: 시간 문자열. :param formatting: 변환 규칙. :return: <datetime> 형식의 시간. """ # static 경고 방지용. dummy = self._me try: return DateTime.strptime(string, formatting) except Exception as e: DummyError("fail to convert from string to date." + "\n" + "reason: " + str(e) + "\n" + "date string: " + string + "\n" + "format: " + formatting)
def datetime_to_string(self, date, formatting): """ <datetime> 형식의 시간을 문자열로 변환.\n :param date: <datetime> 형식의 시간. :param formatting: 변환 규칙. :return: 시간 문자열. """ # static 경고 방지용. dummy = self._me try: return date.strftime(formatting) except Exception as e: DummyError("fail to convert from date to string." + "\n" + "reason: " + str(e) + "\n" + "date: " + str(date) + "\n" + "format: " + formatting)
def __to_application_id(self, application): """ 대상 application 으로부터 application id 를 추출한다.\n :param application: 대상 application :return: 대상 application 의 id """ # static 경고 제거용. dummy = self._me template_version_id = application['templateVersionId'] last_hyphen_index = template_version_id.rfind('-') if last_hyphen_index == -1: raise DummyError("application 의 templateVersionId 에 - 이 없습니다.") return template_version_id[:last_hyphen_index]
def list_catalogs(self, catalogs): """ 모든 catalog 를 불러온다.\n :param catalogs: API 로부터 얻은 모든 catalog :return: 가공 처리가 완료된 catalog list """ # static 경고 방지용. dummy = self._me result_catalogs = [] # RestObject 를 dictionary 객체로 변환 try: dict_catalogs = JsonUtility.call().to_dictionary(catalogs) except DummyError as de: raise de # dictionary 로부터 'data' dictionary 를 추출. try: catalogs_mapping = dict_catalogs['data'] except KeyError: raise DummyError( "catalogs['data'] row is not eixsts. please check your data.") try: for cata in catalogs_mapping: # catalog 를 복제한다. can_write_catalog = copy.copy(cata) # 해당 catalog 는 Clone 이 가능한지 여부를 넣는다. catalog_name = can_write_catalog[CatalogConstant.NAME_STRING] can_write_catalog[CatalogConstant.CAN_CLONE_STRING] \ = not CatalogConstant.isDefaultCatalog(catalog_name) # catalog 에 scope 를 추가한다. can_write_catalog[ CatalogConstant.SCOPE] = CatalogConstant.CATALOG_SCOPE # refactoring 이 완료된 catalog 를 결과 list 에 추가한다. result_catalogs.append(can_write_catalog.copy()) except Exception as e: raise Exception("unknown exception...\n" + e) return result_catalogs
def filter_multi_cluster_application_templates(self, apps_templates, opts): """ 모든 Multi-Cluster Applications의 Templates를 임의의 Catalog 명으로 Filtering한다.\n :param apps_templates: 모든 Multi-Cluster Application의 Templates. :param opts: Filtering 및 모든 Multi-Cluster Applications의 Templates의 API 호출시의 options. :return: Filtering이 완료된 Multi-Cluster Applications의 Templates List. """ # category name을 추출한다. category_name = opts['category'] result_templates = { Constant.CATEGORY_COUNT_DICTIONARY: { "All": 0, }, Constant.CATEGORY_FOCUS: category_name, Constant.DATA: {}, } # RestObject 를 dictionary 로 변환 try: dict_templates = JsonUtility.call().to_dictionary(apps_templates) except DummyError as de: raise de # dictionary 로부터 'data' dictionary 를 추출. try: templates_mapping = dict_templates['data'] except: raise DummyError( "[data] row is not eixsts. please check your data.\n") for templ in templates_mapping: # apps_templates 를 복제한다. can_write_template = templ.copy() # 각 Category 에 따른 갯수 추가. self.__calculate_category_count(templ, result_templates) # Category 를 result mapping 에 분류하여 삽입. self.__classify_category(can_write_template, result_templates[Constant.DATA], category_name) return result_templates
def to_dictionary(self, source): """ 임의의 data 를 dictionary 형식의로 변환한다.\n 임의의 data 는 dictionary 형태로 변환할 수 있는 모형이여야 하며, 그렇지 않으면 예외를 발생시킨다.\n :param source: 변환 대싱인 임의의 data :exception: 변환 실패, DummyException 발생 :return: 변환이 완료된 dictionary 객체 """ try: try: return self.__literal_evaluation(source) # 만일 ast library 를 이용한 변환을 실패하였을 경우. except Exception as e: return self.__json_dumps_then_loads(source) # 만일 json library 를 사용한 변환에도 실패했을 경우. except (TypeError or json.JSONDecodeError) as e: # 변환 실패 exception 을 발생시킨다. raise DummyError( "this source can't convert to dinctionary. please check your source." + "\n" + source, e)
def list_storage_classes(self, storage_classes): """ API로부터 얻은 Storage Classes를 View에 맞게 가공하여 반환한다.\n :param storage_classes: API로부터 얻은 Storage Classes. :return: 가공된 Storage Classes List. """ result_storage_classes = [] # RestObject를 dictionary 객체로 변환 try: dict_storage_classes = JsonUtility.call().to_dictionary( storage_classes) except DummyError as de: raise de try: storage_classes_mapping = dict_storage_classes['data'] except KeyError: raise DummyError( "persistent_volumes['data'] row is not eixsts. please check your data." ) for storage_class in storage_classes_mapping: can_write_storage_class = storage_class.copy() # storage class의 상태를 active로 설정. (default) # TODO: 추후 화면 출력 Table을 Template화 하면, 상태를 넣을 필요가 있기 때문에 넣어준다. ( 사실 상태가 존재하지 않음. ) can_write_storage_class[ StorageClassesConstant. STATE_STRING] = StorageClassesConstant.DEFAULT_STATE # 화면에 출력할 title을 습득. can_write_storage_class[ StorageClassesConstant.PROVISIONER] = self.__get_provisioner( storage_class) result_storage_classes.append(can_write_storage_class.copy()) return result_storage_classes
def multi_cluster_application_templates(self, apps_templates): """ 모든 apps_templates multi-cluster appllications 을 불러온다.\n :param apps_templates: API 로부터 얻은 templates multi-cluster applications :return: 가공 처리가 완료된 apps_templates multi-cluster applications """ result_templates = { Constant.CATEGORY_COUNT_DICTIONARY: { "All": 0, }, Constant.CATEGORY_FOCUS: "All", Constant.DATA: {}, } # RestObject 를 dictionary 로 변환 try: dict_templates = JsonUtility.call().to_dictionary(apps_templates) except DummyError as de: raise de # dictionary 로부터 'data' dictionary 를 추출. try: templates_mapping = dict_templates['data'] except: raise DummyError( "[data] row is not eixsts. please check your data.") for templ in templates_mapping: # apps_templates 를 복제한다. can_write_template = copy.copy(templ) # 각 Category 에 따른 갯수 추가. self.__calculate_category_count(templ, result_templates) # Category 를 result mapping 에 분류하여 삽입. self.__classify_category(can_write_template, result_templates[Constant.DATA]) return result_templates
def __get_provisioner(self, storage_class): """ API로부터 얻은 data 중, provisioner에 해당하는 title을 습득한다.\n :param storage_class: provisioner를 추출할 API로부터 얻은 data. :return: 습득한 title. """ # static 경고 제거용. dummy = self._me provisioner = storage_class[StorageClassesConstant.PROVISIONER] STORAGE_CLASSES = StorageClassesConstant.STORAGE_CLASS_DICTIONARY[ StorageClassesConstant.STORAGE_CLASS] for one_class in STORAGE_CLASSES.values(): # provisioner 값을 기반으로 title 을 반환한다. if one_class[StorageClassesConstant.PROVISIONER] == provisioner: return one_class[StorageClassesConstant.TITLE] # 어느 field에도 해당하는 내용이 없을 경우, DummyEvolume)xception을 발생시킴. raise DummyError("invalid data --- provisioner does not exists." + "\n" + "data:" + json.dumps(storage_class))
def __pull_out_configuration(self, persistent_volume): """ 임의의 Persistent Volume의 정보를 기반으로 source를 추출하고, 해당 source의 configuration을 반환한다.\n :param persistent_volume: 임의의 persistent volume. :return: 해당 persistent volume에 맞는 configurtaion template. """ # static 경고 제거용. dummy = self._me VOLUME_SOURCES = PersistentVolumesConstant.VOLUME_SOURCE_DICTIONARY[ PersistentVolumesConstant.VOLUME_SOURCE] for value in VOLUME_SOURCES.values(): # field 명을 습득한다. field_name = value[PersistentVolumesConstant.FIELD] # 해당 field가 존재하므로 configuration을 반환. if field_name in persistent_volume and value[ PersistentVolumesConstant.SUPPORTED]: return value[PersistentVolumesConstant.CONFIGURATION] # 어느 field에도 해당하는 내용이 없는 경우, DummyException을 발생시킴. raise DummyError("invalid data -- source does not exists." + "\n" + "data:" + json.dumps(persistent_volume))
def __getSource(self, persistent_volume): """ 임의의 Persistent volume의 정보를 기반으로 source를 파악하여 source field를 생성 및 값을 입력한다.\n :param persistent_volume: 임의의 Persistent Volume. :return 해당 persistent volume에 맞는 title. """ # static 경고 제거용. dummy = self._me VOLUME_SOURCES = PersistentVolumesConstant.VOLUME_SOURCE_DICTIONARY[ PersistentVolumesConstant.VOLUME_SOURCE] for value in VOLUME_SOURCES.values(): # field 명을 습득한다. field_name = value[PersistentVolumesConstant.FIELD] # 해당 field가 존재하므로 field의 title을 반환. if field_name in persistent_volume and value[ PersistentVolumesConstant.SUPPORTED]: return value[PersistentVolumesConstant.TITLE] # 어느 field에도 해당하는 내용이 없을 경우, DummyException을 발생시킴. raise DummyError("invalid data --- source does not exists." + "\n" + "data:" + json.dumps(persistent_volume))
def replace_range(self, value, old, new, start, end): """ 임의의 문자열로부터 일정 범위 내에서 특정 문자열을 replace 하는 함수이다.\n :param value: 대상 문자열 :param old: replace 할 대상의 단어 :param new: replace 할 단어 :param start: 임의의 문자열의 시작 범위 :param end: 임의의 문자열의 종료 범위 :return: 대체 완료한 문자열 """ # static 경고 방지용. dummy = self._me # start 또는 end 가 정수가 아닌 경우. if not isinstance(start, int) or not isinstance(end, int): raise TypeError("start or end value are not digit.") # start 가 end 보다 큰 경우. if start > end: raise DummyError("end value is greater than start value.") # start 또는 end 가 음수인 경우. if start < 0 or end < 0: raise DummyError("start or end value is less than 0") # start 또는 end 가 대상 문자열의 길이보다 큰 경우. VALUE_LENGTH = len(value) if start >= VALUE_LENGTH or end >= VALUE_LENGTH: raise DummyError( "start or end value is greater than target value length.") # [start:end] 범위 외의 문자열을 따로 저장. prefix = value[:start] suffix = value[end:] # [start:end] 범위 내의 문자열 습득. range_string = value[start:end] result_string = '' OLD_LENGTH = len(old) while True: # old 문자열이 있는 시작 index 습득. start_index = range_string.find(old) # old 문자열이 더 이상 발견되지 않을 경우 종료. if start_index == -1: break # old 문자열의 시작점 이전 부분을 입력. result_string += range_string[:start_index] # old 문자열의 시작 위치에 new 문자열을 입력. result_string += new # 대상 문자열에서 old 문자열 이후의 문자열들을 저장. start_index += OLD_LENGTH range_string = range_string[start_index:] result_string = prefix + result_string + suffix return result_string
def list_applications(self, multi_cluster_apps, projects, clusters, template_apps): """ 모든 multi-cluster application 을 불러온다.\n projects 와 clusters 가 필요한 이유는 multi-cluster application 의 대상이 되고있는 project 와 cluster 명을 얻기 위해서이다.\n :param template_apps: API 로부터 얻은 모든 multi-cluster application teamplates :param multi_cluster_apps: API 로부터 얻은 모든 multi-cluster application :param projects: API 로부터 얻은 projects :param clusters: API 로부터 얻은 clusters :return: 가공 처리가 완료된 multi-cluster application list """ result_multi_cluster_applications = [] # RestObject 를 dictionary 객체로 변환 try: dict_multi_cluster_apps = JsonUtility.call().to_dictionary( multi_cluster_apps) dict_projects = JsonUtility.call().to_dictionary(projects) dict_clusters = JsonUtility.call().to_dictionary(clusters) dict_template_apps = JsonUtility.call().to_dictionary( template_apps) except DummyError as de: raise de # 각 dictionary 로부터 'data' dictionary 를 추출. try: multi_cluster_apps_mapping = dict_multi_cluster_apps['data'] projects_mapping = dict_projects['data'] clusters_mapping = dict_clusters['data'] template_apps_mapping = dict_template_apps['data'] except: raise DummyError( "[data] row is not eixsts. please check your data.") try: for application in multi_cluster_apps_mapping: # application 을 복제한다. can_write_application = copy.copy(application) # application id 를 추출한다. application_id = self._me.__to_application_id(application) # application id 를 이용하여, template 로부터 row 를 추출한다. template_row = self._me.__find_by_key_then_get_row( template_apps_mapping, 'id', application_id) if template_row is not None: # application 으로부터 apps_templates version 을 추출한다. can_write_application[Constant.TEMPLATE_VERSION] \ = self._me.__to_template_version(application) # icon link 를 추출한다. can_write_application['iconLink'] = template_row['links'][ 'icon'] # template의 latest(default) version 을 추출한다. can_write_application[ Constant. LATEST_VERSION] = template_row['defaultVersion'] # application 을 이용하여 targets 를 refactoring 한다. refactoring = self._me.__targets_refactoring( application, clusters_mapping, projects_mapping) can_write_application['targets'] = refactoring.copy() # refactoring 이 완료된 application 을 결과 list 에 추가한다. result_multi_cluster_applications.append( can_write_application.copy()) except DummyError as de: raise de except Exception as e: raise Exception("unknown exception...\n" + e) return result_multi_cluster_applications