zhu.boxiang 8cb60f0833 chore: Move skyline_apiserver out of libs
1. move skyline_apiserver out of libs
2. remove libs folder
3. remove old skyline folder
4. adjust zull, devstack and dockerfile

Change-Id: I27a4babd3df077d1dfc7555f67a6ea618d4b2966
2022-05-18 17:21:00 +08:00

168 lines
5.5 KiB
Python

# Copyright 2021 99cloud
#
# 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 __future__ import annotations
import warnings
from dataclasses import InitVar, dataclass, field
from pathlib import Path, PurePath
from typing import Any, Dict, Iterator, NamedTuple, Sequence, Tuple, Type
import yaml
from immutables import Map, MapItems, MapKeys, MapValues
from pydantic import BaseModel, create_model
class ConfigPath(NamedTuple):
config_dir_path: str
config_file_path: str
@dataclass(frozen=True)
class Opt:
name: str
description: str
schema: Any
default: Any = None
deprecated: bool = False
value: Any = field(init=False, default=None)
_schema_model: Type[BaseModel] = field(init=False, repr=False)
def __post_init__(self) -> None:
object.__setattr__(
self,
"_schema_model",
create_model(f"Opt(name='{self.name}')", value=(self.schema, ...)),
)
def load(self, value: Any) -> None:
value = self.default if value is None else value
self._schema_model(value=value)
object.__setattr__(self, "value", value)
if self.deprecated:
warnings.warn(
f"The config opt {self.name} is deprecated, will be deleted in the"
" future version",
DeprecationWarning,
)
@dataclass(repr=False, frozen=True)
class Group:
name: str
init_opts: InitVar[Sequence[Opt]] = tuple()
_opts: Map[str, Opt] = field(init=False, repr=False)
def __post_init__(self, init_opts: Sequence[Opt]) -> None:
object.__setattr__(self, "_opts", Map({opt.name: opt for opt in init_opts}))
def __getattr__(self, name: str) -> Any:
if name in self._opts:
return self._opts[name].value
raise AttributeError(name)
def __contains__(self, key: Any) -> bool:
return self._opts.__contains__(key)
def __iter__(self) -> Iterator[Any]:
return self._opts.__iter__()
def __len__(self) -> int:
return self._opts.__len__()
def __repr__(self) -> str:
items = ", ".join((f"{opt}=Opt(name='{opt}')" for opt in self._opts))
return f"Group({items})"
def keys(self) -> MapKeys[str]:
return self._opts.keys()
def values(self) -> MapValues[Opt]:
return self._opts.values()
def items(self) -> MapItems[str, Opt]:
return self._opts.items()
@dataclass(repr=False, frozen=True)
class Configuration:
init_groups: InitVar[Sequence[Group]] = tuple()
config: Dict[str, Any] = field(init=False, default_factory=dict, repr=False)
_groups: Map[str, Group] = field(init=False, repr=False)
def __post_init__(self, init_groups: Sequence[Group]) -> None:
object.__setattr__(self, "_groups", Map({group.name: group for group in init_groups}))
@staticmethod
def get_config_path(project: str, env: Dict[str, str]) -> Tuple[str, str]:
config_dir_path = env.get("OS_CONFIG_DIR", PurePath("/etc", project).as_posix())
config_file_path = PurePath(config_dir_path).joinpath(f"{project}.yaml").as_posix()
return ConfigPath(config_dir_path.strip(), config_file_path.strip())
def setup(self, project: str, env: Dict[str, str]) -> None:
config_dir_path, config_file_path = self.get_config_path(project, env)
if not Path(config_file_path).exists():
raise ValueError(f"Not found config file: {config_file_path}")
with open(config_file_path) as f:
try:
object.__setattr__(self, "config", yaml.safe_load(f))
except Exception:
raise ValueError("Load config file error")
for group in self._groups.values():
for opt in group._opts.values():
value = self.config.get(group.name, {}).get(opt.name)
opt.load(value)
def cleanup(self) -> None:
for group in self._groups.values():
for opt in group._opts.values():
object.__setattr__(opt, "value", None)
object.__setattr__(self, "_groups", Map())
object.__setattr__(self, "config", {})
def __call__(self, init_groups: Sequence[Group]) -> Any:
object.__setattr__(self, "_groups", Map({group.name: group for group in init_groups}))
def __getattr__(self, name: str) -> Group:
if name in self._groups:
return self._groups[name]
raise AttributeError(name)
def __contains__(self, key: Any) -> bool:
return self._groups.__contains__(key)
def __iter__(self) -> Iterator[Any]:
return self._groups.__iter__()
def __len__(self) -> int:
return self._groups.__len__()
def __repr__(self) -> str:
items = ", ".join((f"{group}=Group(name='{group}')" for group in self._groups))
return f"Configuration({items})"
def keys(self) -> MapKeys[str]:
return self._groups.keys()
def values(self) -> MapValues[Group]:
return self._groups.values()
def items(self) -> MapItems[str, Group]:
return self._groups.items()
__all__ = ("Opt", "Group", "Configuration")