diff --git a/src/spaceone/core/handler/authentication_handler.py b/src/spaceone/core/handler/authentication_handler.py index c32b52e..dedb4e8 100644 --- a/src/spaceone/core/handler/authentication_handler.py +++ b/src/spaceone/core/handler/authentication_handler.py @@ -1,7 +1,7 @@ import json import logging -from spaceone.core import cache +from spaceone.core import cache, config from spaceone.core.connector.space_connector import SpaceConnector from spaceone.core.auth.jwt import JWTAuthenticator, JWTUtil from spaceone.core.transaction import get_transaction @@ -43,9 +43,11 @@ def verify(self, params: dict) -> None: @cache.cacheable(key="handler:authentication:{domain_id}:public-key", alias="local") def _get_public_key(self, domain_id: str) -> str: + system_token = config.get_global("TOKEN") + _LOGGER.debug(f"[_get_public_key] get jwk from identity service: {domain_id}") response = self.identity_conn.dispatch( - "Domain.get_public_key", {"domain_id": domain_id} + "Domain.get_public_key", {"domain_id": domain_id}, token=system_token ) return response["public_key"] @@ -54,6 +56,8 @@ def _get_public_key(self, domain_id: str) -> str: key="handler:authentication:{domain_id}:client:{client_id}", alias="local" ) def _check_app(self, client_id, domain_id) -> list: + system_token = config.get_global("TOKEN") + _LOGGER.debug(f"[_check_app] check app from identity service: {client_id}") response = self.identity_conn.dispatch( "App.check", @@ -61,6 +65,7 @@ def _check_app(self, client_id, domain_id) -> list: "client_id": client_id, "domain_id": domain_id, }, + token=system_token, ) return response.get("permissions", []) diff --git a/src/spaceone/core/pygrpc/api.py b/src/spaceone/core/pygrpc/api.py index bd80a42..2d1f8fa 100644 --- a/src/spaceone/core/pygrpc/api.py +++ b/src/spaceone/core/pygrpc/api.py @@ -42,19 +42,25 @@ def service_name(self): return self.pb2.DESCRIPTOR.services_by_name[self.__class__.__name__].full_name def _load_grpc_messages(self): - service_desc: ServiceDescriptor = self._desc_pool.FindServiceByName(self.service_name) + service_desc: ServiceDescriptor = self._desc_pool.FindServiceByName( + self.service_name + ) for method_desc in service_desc.methods: self._grpc_messages[method_desc.name] = { - 'request': method_desc.input_type.name, - 'response': method_desc.output_type.name + "request": method_desc.input_type.name, + "response": method_desc.output_type.name, } def _check_variables(self): - if not hasattr(self, 'pb2'): - raise Exception(f'gRPC Servicer has not set variable. (servicer={self.__class__.__name__})') + if not hasattr(self, "pb2"): + raise Exception( + f"gRPC Servicer has not set variable. (servicer={self.__class__.__name__})" + ) - if not hasattr(self, 'pb2_grpc'): - raise Exception(f'gRPC Servicer has not set variable. (servicer={self.__class__.__name__})') + if not hasattr(self, "pb2_grpc"): + raise Exception( + f"gRPC Servicer has not set variable. (servicer={self.__class__.__name__})" + ) def _get_grpc_servicer(self): grpc_servicer = None @@ -63,14 +69,18 @@ def _get_grpc_servicer(self): grpc_servicer = base_class if grpc_servicer is None: - raise Exception(f'gRPC servicer is not set. (servicer={self.__class__.__name__})') + raise Exception( + f"gRPC servicer is not set. (servicer={self.__class__.__name__})" + ) return grpc_servicer def _set_grpc_method(self): grpc_servicer = self._get_grpc_servicer() - for f_name, f_object in inspect.getmembers(self.__class__, predicate=inspect.isfunction): + for f_name, f_object in inspect.getmembers( + self.__class__, predicate=inspect.isfunction + ): if hasattr(grpc_servicer, f_name): setattr(self, f_name, self._grpc_method(f_object)) @@ -79,10 +89,10 @@ def _error_method(error, context): if not isinstance(error, ERROR_BASE): error = ERROR_UNKNOWN(message=error) - if not error.meta.get('skip_error_log'): - _LOGGER.error(f'(Error) => {error.message} {error}', exc_info=True) + if not error.meta.get("skip_error_log"): + _LOGGER.error(f"(Error) => {error.message} {error}", exc_info=True) - details = f'{error.error_code}: {error.message}' + details = f"{error.error_code}: {error.message}" context.abort(grpc.StatusCode[error.status_code], details) def _generate_response(self, response_iterator, context): @@ -118,8 +128,7 @@ def _get_metadata(context): for key, value in context.invocation_metadata(): metadata[key.strip()] = value.strip() - metadata.update({'peer': context.peer()}) - + metadata.update({"peer": context.peer()}) return metadata def _generate_message(self, request_iterator): @@ -128,9 +137,13 @@ def _generate_message(self, request_iterator): def parse_request(self, request_or_iterator, context): if isinstance(request_or_iterator, Iterable): - return self._generate_message(request_or_iterator), self._get_metadata(context) + return self._generate_message(request_or_iterator), self._get_metadata( + context + ) else: - return self._convert_message(request_or_iterator), self._get_metadata(context) + return self._convert_message(request_or_iterator), self._get_metadata( + context + ) def empty(self): return Empty() @@ -139,17 +152,19 @@ def dict_to_message(self, response: dict): # Get grpc method name from call stack method_name = inspect.stack()[1][3] - response_message_name = self._grpc_messages[method_name]['response'] + response_message_name = self._grpc_messages[method_name]["response"] if hasattr(self.pb2, response_message_name): response_message = getattr(self.pb2, response_message_name)() - elif response_message_name == 'Struct': + elif response_message_name == "Struct": response_message = Struct() else: - raise Exception(f'Not found response message in pb2. (message={response_message_name})') + raise Exception( + f"Not found response message in pb2. (message={response_message_name})" + ) return ParseDict(response, response_message) @staticmethod def get_minimal(params: dict): - return params.get('query', {}).get('minimal', False) + return params.get("query", {}).get("minimal", False) diff --git a/src/spaceone/core/utils.py b/src/spaceone/core/utils.py index 42a0c4c..4c6ffcd 100644 --- a/src/spaceone/core/utils.py +++ b/src/spaceone/core/utils.py @@ -17,20 +17,24 @@ YAML_LOADER = yaml.Loader YAML_LOADER.add_implicit_resolver( - u'tag:yaml.org,2002:float', - re.compile(u'''^(?: + "tag:yaml.org,2002:float", + re.compile( + """^(?: [-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)? |[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+) |\\.[0-9_]+(?:[eE][-+][0-9]+)? |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]* |[-+]?\\.(?:inf|Inf|INF) - |\\.(?:nan|NaN|NAN))$''', re.X), - list(u'-+0123456789.')) + |\\.(?:nan|NaN|NAN))$""", + re.X, + ), + list("-+0123456789."), +) -def generate_id(prefix: str = 'id', nbytes: int = 6) -> str: +def generate_id(prefix: str = "id", nbytes: int = 6) -> str: random_id = secrets.token_hex(nbytes) - return f'{prefix}-{random_id}' + return f"{prefix}-{random_id}" def generate_trace_id() -> int: @@ -43,7 +47,7 @@ def generate_secret(nbytes: int = 32) -> str: def generate_password(length: int = 8) -> str: # create alphanumerical from string constants - printable = f'{string.ascii_letters}{string.digits}' + printable = f"{string.ascii_letters}{string.digits}" # convert printable from string to list and shuffle printable = list(printable) @@ -57,7 +61,7 @@ def generate_password(length: int = 8) -> str: random_password.append(random.choices(list(string.ascii_uppercase))[0]) random_password.append(random.choices(list(string.digits))[0]) - random_password = ''.join(random_password) + random_password = "".join(random_password) return random_password @@ -74,64 +78,64 @@ def dump_json(data, indent=None, sort_keys=False) -> str: try: return json.dumps(data, indent=indent, sort_keys=sort_keys, ensure_ascii=False) except Exception as e: - raise ValueError(f'JSON Dump Error: {str(e)}') + raise ValueError(f"JSON Dump Error: {str(e)}") def save_json_to_file(data, json_file: str, indent=None, sort_keys=False): try: json_str = dump_json(data, indent, sort_keys) - with open(json_file, 'w') as f: + with open(json_file, "w") as f: f.write(json_str) f.close() except Exception as e: - raise ValueError(f'JSON Save Error: {str(e)}') + raise ValueError(f"JSON Save Error: {str(e)}") def load_json(json_str: str) -> dict: try: return json.loads(json_str) except Exception: - raise ValueError(f'JSON Load Error: {json_str}') + raise ValueError(f"JSON Load Error: {json_str}") def load_json_from_file(json_file: str) -> dict: try: - with open(json_file, 'r') as f: + with open(json_file, "r") as f: return load_json(f.read()) except Exception: - raise Exception(f'JSON Load Error: {json_file}') + raise Exception(f"JSON Load Error: {json_file}") def dump_yaml(data: dict) -> str: try: return yaml.dump(data, allow_unicode=True) except Exception as e: - raise ValueError(f'YAML Dump Error: {str(e)}') + raise ValueError(f"YAML Dump Error: {str(e)}") def save_yaml_to_file(data: dict, yaml_file: str): try: yaml_str = dump_yaml(data) - with open(yaml_file, 'w') as f: + with open(yaml_file, "w") as f: f.write(yaml_str) f.close() except Exception as e: - raise ValueError(f'YAML Save Error: {str(e)}') + raise ValueError(f"YAML Save Error: {str(e)}") def load_yaml(yaml_str: str) -> dict: try: return yaml.load(yaml_str, Loader=YAML_LOADER) except Exception: - raise ValueError(f'YAML Load Error: {yaml_str}') + raise ValueError(f"YAML Load Error: {yaml_str}") def load_yaml_from_file(yaml_file: str) -> dict: try: - with open(yaml_file, 'r') as f: + with open(yaml_file, "r") as f: return load_yaml(f.read()) except Exception: - raise Exception(f'YAML Load Error: {yaml_file}') + raise Exception(f"YAML Load Error: {yaml_file}") def load_yaml_from_url(url: str) -> dict: @@ -139,41 +143,38 @@ def load_yaml_from_url(url: str) -> dict: f = urllib.urlopen(url) return load_yaml(f.read()) except Exception as e: - raise Exception(f'Http call error: {url}. e={e}') + raise Exception(f"Http call error: {url}. e={e}") def parse_endpoint(endpoint: str) -> dict: try: o = urlparse(endpoint) except Exception: - raise ValueError(f'Endpoint is invalid. ({endpoint})') + raise ValueError(f"Endpoint is invalid. ({endpoint})") - return { - 'scheme': o.scheme, - 'hostname': o.hostname, - 'port': o.port, - 'path': o.path - } + return {"scheme": o.scheme, "hostname": o.hostname, "port": o.port, "path": o.path} def parse_grpc_endpoint(endpoint: str) -> dict: try: endpoint_info = parse_endpoint(endpoint) - if endpoint_info['scheme'] not in ['grpc', 'grpc+ssl']: - raise ValueError(f'Unsupported protocol. (supported_protocol=grpc|grpc+ssl, endpoint={endpoint})') + if endpoint_info["scheme"] not in ["grpc", "grpc+ssl"]: + raise ValueError( + f"Unsupported protocol. (supported_protocol=grpc|grpc+ssl, endpoint={endpoint})" + ) except Exception: - raise ValueError(f'gRPC Endpoint is invalid. (endpoint={endpoint})') + raise ValueError(f"gRPC Endpoint is invalid. (endpoint={endpoint})") - if endpoint_info['scheme'] == 'grpc+ssl': + if endpoint_info["scheme"] == "grpc+ssl": ssl_enabled = True else: ssl_enabled = False return { - 'endpoint': f'{endpoint_info["hostname"]}:{endpoint_info["port"]}', - 'ssl_enabled': ssl_enabled + "endpoint": f'{endpoint_info["hostname"]}:{endpoint_info["port"]}', + "ssl_enabled": ssl_enabled, } @@ -181,25 +182,28 @@ def parse_grpc_uri(uri: str) -> dict: try: endpoint_info = parse_endpoint(uri) - if endpoint_info['scheme'] not in ['grpc', 'grpc+ssl']: - raise ValueError(f'Unsupported protocol. (supported_protocol=grpc|grpc+ssl, uri={uri})') + if endpoint_info["scheme"] not in ["grpc", "grpc+ssl"]: + raise ValueError( + f"Unsupported protocol. (supported_protocol=grpc|grpc+ssl, uri={uri})" + ) - version, service, method = \ - filter(lambda x: x.strip() != '', endpoint_info['path'].split('/')) + version, service, method = filter( + lambda x: x.strip() != "", endpoint_info["path"].split("/") + ) except Exception: - raise ValueError(f'gRPC URI is invalid. (uri={uri})') + raise ValueError(f"gRPC URI is invalid. (uri={uri})") - if endpoint_info['scheme'] == 'grpc+ssl': + if endpoint_info["scheme"] == "grpc+ssl": ssl_enabled = True else: ssl_enabled = False return { - 'endpoint': f'{endpoint_info["hostname"]}:{endpoint_info["port"]}', - 'version': version, - 'service': service, - 'method': method, - 'ssl_enabled': ssl_enabled + "endpoint": f'{endpoint_info["hostname"]}:{endpoint_info["port"]}', + "version": version, + "service": service, + "method": method, + "ssl_enabled": ssl_enabled, } @@ -217,67 +221,71 @@ def deep_merge(from_dict: dict, into_dict: dict) -> dict: def parse_timediff_query(query: str) -> datetime: try: time_info, include_operator = _parse_timediff_from_regex(query) - base_dt = _convert_base_time(time_info['base_time']) + base_dt = _convert_base_time(time_info["base_time"]) if include_operator: - time_delta = _convert_time_delta(time_info['time_delta_number'], time_info['time_delta_unit']) - if time_info['operator'] == '+': + time_delta = _convert_time_delta( + time_info["time_delta_number"], time_info["time_delta_unit"] + ) + if time_info["operator"] == "+": return base_dt + time_delta else: return base_dt - time_delta else: return base_dt except Exception as e: - raise ValueError(f'Timediff format is invalid. (value={query})') + raise ValueError(f"Timediff format is invalid. (value={query})") -def _convert_time_delta(time_delta_number: str, time_delta_unit: str) -> datetime.timedelta: +def _convert_time_delta( + time_delta_number: str, time_delta_unit: str +) -> datetime.timedelta: _time_delta_map = { - 's': 'seconds', - 'm': 'minutes', - 'h': 'hours', - 'd': 'days', - 'w': 'weeks' + "s": "seconds", + "m": "minutes", + "h": "hours", + "d": "days", + "w": "weeks", } - time_delta_params = { - _time_delta_map[time_delta_unit]: int(time_delta_number) - } + time_delta_params = {_time_delta_map[time_delta_unit]: int(time_delta_number)} return datetime.timedelta(**time_delta_params) def _convert_base_time(time_str: str) -> datetime: now = datetime.datetime.utcnow() - if time_str == 'now': + if time_str == "now": return now - elif time_str == 'now/d': + elif time_str == "now/d": return datetime.datetime.combine(now.date(), datetime.time(0)) - elif time_str == 'now/w': + elif time_str == "now/w": today = datetime.datetime.combine(now.date(), datetime.time(0)) return today - datetime.timedelta(days=now.date().weekday()) - elif time_str == 'now/m': + elif time_str == "now/m": today = datetime.datetime.combine(now.date(), datetime.time(0)) return today.replace(day=1) def _parse_timediff_from_regex(query: str) -> Tuple[dict, bool]: - p = r'^\s?(?Pnow(\/[dwm])?)\s?' \ - r'(?P[+|-])\s?' \ - r'(?P\d+)' \ - r'(?P[s|m|h|d|w])\s?$' + p = ( + r"^\s?(?Pnow(\/[dwm])?)\s?" + r"(?P[+|-])\s?" + r"(?P\d+)" + r"(?P[s|m|h|d|w])\s?$" + ) rule = re.compile(p) match = rule.match(query) if match: return match.groupdict(), True else: - if query.strip() not in ['now', 'now/d', 'now/w', 'now/m']: - raise ValueError(f'Timediff format is invalid. (value={query})') + if query.strip() not in ["now", "now/d", "now/w", "now/m"]: + raise ValueError(f"Timediff format is invalid. (value={query})") - return {'base_time': query.strip()}, False + return {"base_time": query.strip()}, False def get_dict_value(data: dict, dotted_key: str, default_value: any = None): - if '.' in dotted_key: + if "." in dotted_key: key, rest = dotted_key.split(".", 1) if isinstance(data, dict) and key in data: @@ -301,34 +309,34 @@ def get_dict_value(data: dict, dotted_key: str, default_value: any = None): def get_list_values(values: list, dotted_key: str, default_value: any = None): - match_option = 'contain' + match_option = "contain" if len(dotted_key) > 1 and dotted_key[0] == "?": condition = True try: - cond_option, rest = dotted_key[1:].split('=>', 1) - cond_key, cond_value = cond_option.split(':', 1) + cond_option, rest = dotted_key[1:].split("=>", 1) + cond_key, cond_value = cond_option.split(":", 1) except Exception as e: # Syntax Error return default_value - if cond_value[:1] == '=': - match_option = 'eq' + if cond_value[:1] == "=": + match_option = "eq" cond_value = cond_value[1:] - elif cond_value[:1] == '!': - match_option = 'not' + elif cond_value[:1] == "!": + match_option = "not" cond_value = cond_value[1:] else: try: # Get value by index - if '.' in dotted_key: - index, rest = dotted_key.split('.', 1) + if "." in dotted_key: + index, rest = dotted_key.split(".", 1) index = int(index) if index >= len(values): return default_value else: - if rest.strip() != '' and isinstance(values[index], dict): + if rest.strip() != "" and isinstance(values[index], dict): return get_dict_value(values[index], rest, default_value) else: values = values[index] @@ -345,8 +353,10 @@ def get_list_values(values: list, dotted_key: str, default_value: any = None): results = [] for value in values: # Get value from condition - if not isinstance(value, dict) \ - or (condition and not _check_condition(match_option, value[cond_key], cond_value)): + if not isinstance(value, dict) or ( + condition + and not _check_condition(match_option, value[cond_key], cond_value) + ): continue # Get value from dict key @@ -371,11 +381,11 @@ def _check_condition(match_option: str, val1, val2): val1 = str(val1).lower() val2 = str(val2).lower() - if match_option == 'eq': + if match_option == "eq": if val1 == val2: return True - elif match_option == 'not': + elif match_option == "not": if val1.find(val2) < 0: return True @@ -386,39 +396,53 @@ def _check_condition(match_option: str, val1, val2): return False -def change_dict_value(data: dict, dotted_key: str, change_value, change_type='value') -> dict: +def change_dict_value( + data: dict, dotted_key: str, change_value, change_type="value" +) -> dict: # change_value = func or value(any type) - if '.' in dotted_key: - key, rest = dotted_key.split('.', 1) + if "." in dotted_key: + key, rest = dotted_key.split(".", 1) if key in data: - if rest.startswith('[]') and isinstance(data[key], list): + if rest.startswith("[]") and isinstance(data[key], list): list_data = [] for sub_data in data[key]: - if rest.strip() == '[]': - list_data.append(_change_value_by_type(change_type, sub_data, change_value)) + if rest.strip() == "[]": + list_data.append( + _change_value_by_type(change_type, sub_data, change_value) + ) else: - sub_rest = rest.split('.', 1)[1] - list_data.append(change_dict_value(sub_data, sub_rest, change_value, change_type)) + sub_rest = rest.split(".", 1)[1] + list_data.append( + change_dict_value( + sub_data, sub_rest, change_value, change_type + ) + ) data[key] = list_data elif isinstance(data[key], dict): - data[key] = change_dict_value(data[key], rest, change_value, change_type) + data[key] = change_dict_value( + data[key], rest, change_value, change_type + ) else: if dotted_key in data: - data[dotted_key] = _change_value_by_type(change_type, data[dotted_key], change_value) + data[dotted_key] = _change_value_by_type( + change_type, data[dotted_key], change_value + ) return data def _change_value_by_type(change_type, original_value, change_value): - if change_type == 'value': + if change_type == "value": return change_value - elif change_type == 'func': + elif change_type == "func": return change_value(original_value) else: return original_value -def date_to_string(value: datetime.date, date_format: str = '%Y-%m-%d') -> Union[str, None]: +def date_to_string( + value: datetime.date, date_format: str = "%Y-%m-%d" +) -> Union[str, None]: if isinstance(value, datetime.date): return value.strftime(date_format) @@ -438,7 +462,7 @@ def iso8601_to_datetime(value: str) -> Union[datetime.datetime, None]: try: return isoparse(value) except Exception as e: - raise ValueError(f'Datetime(ISO8601) format is invalid. (value={value})') + raise ValueError(f"Datetime(ISO8601) format is invalid. (value={value})") return None @@ -455,7 +479,7 @@ def tags_to_dict(tags: list) -> Union[dict, None]: if isinstance(tags, list): dict_value = {} for tag in tags: - dict_value[tag['key']] = tag['value'] + dict_value[tag["key"]] = tag["value"] return dict_value @@ -467,10 +491,7 @@ def dict_to_tags(dict_value: dict) -> list: tags = [] if isinstance(dict_value, dict): for key, value in dict_value.items(): - tags.append({ - 'key': key, - 'value': value - }) + tags.append({"key": key, "value": value}) return tags @@ -489,16 +510,18 @@ def string_to_hash(str_value: str) -> str: return dhash.hexdigest() -def change_dict_with_dot_notation(dict_value: dict, key='', dots=None) -> dict: +def change_dict_with_dot_notation(dict_value: dict, key="", dots=None) -> dict: if dots is None: dots = {} if isinstance(dict_value, dict): - for (k, v) in dict_value.items(): - change_dict_with_dot_notation(dict_value[k], f'{key}.{k}' if key else k, dots) + for k, v in dict_value.items(): + change_dict_with_dot_notation( + dict_value[k], f"{key}.{k}" if key else k, dots + ) else: dots[key] = dict_value return dots -if __name__ == '__main__': +if __name__ == "__main__": pass