skyline-apiserver/libs/skyline-nginx/skyline_nginx/cmd/generate_nginx.py
Reşit Demir 3aa06f7853 Add Trove configs and policies to Skyline-Apiserver
Change-Id: I28d627dc00dcaafc1582b13b9c0416966978b594
2022-04-06 09:32:10 +00:00

189 lines
5.7 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 sys
from logging import StreamHandler
from pathlib import Path, PurePath
from typing import Dict
from urllib.parse import urlparse
import click
import skyline_nginx
from jinja2 import Template
from keystoneauth1.identity.v3 import Password
from keystoneauth1.session import Session
from keystoneclient.client import Client as KeystoneClient
from pydantic import BaseModel
from skyline_console import static_path
from skyline_log import LOG, setup
from skyline_nginx.config import CONF, configure
class CommandException(Exception):
EXIT_CODE = 1
class ProxyEndpoint(BaseModel):
part: str
location: str
url: str
def get_system_session() -> Session:
auth = Password(
auth_url=CONF.openstack.keystone_url,
user_domain_name=CONF.openstack.system_user_domain,
username=CONF.openstack.system_user_name,
password=CONF.openstack.system_user_password,
project_name=CONF.openstack.system_project,
project_domain_name=CONF.openstack.system_project_domain,
reauthenticate=True,
)
return Session(auth=auth, verify=False, timeout=30)
def get_proxy_endpoints() -> Dict[str, ProxyEndpoint]:
ks_client = KeystoneClient(
session=get_system_session(),
interface=CONF.openstack.interface_type,
region_name=CONF.openstack.default_region,
)
endpoints_list = ks_client.endpoints.list(interface=CONF.openstack.interface_type)
service_list = ks_client.services.list()
services = {s.id: s.type for s in service_list}
endpoints = {}
for endpoint in endpoints_list:
proxy = ProxyEndpoint(part="", location="", url="")
region = endpoint.region
service_type = services.get(endpoint.service_id)
service = CONF.openstack.service_mapping.get(service_type)
if service is None:
continue
if f"{region}-{service_type}" in endpoints:
raise KeyError(
f'Region "{region}" service type "{service_type}" conflict in endpoints.',
)
proxy.part = f"# {region} {service}"
location = PurePath("/").joinpath(
CONF.openstack.nginx_prefix,
region.lower(),
service,
)
proxy.location = f"{str(location)}/"
raw_url = urlparse(endpoint.url)
path = ""
if raw_url.path:
raw_path = PurePath(raw_url.path)
if len(raw_path.parts) > 1:
if (
raw_path.match("%(tenant_id)s")
or raw_path.match("AUTH_%(tenant_id)s")
or raw_path.match("$(project_id)s")
or raw_path.match("AUTH_$(project_id)s")
):
path = "" if str(raw_path.parents[1]) == "/" else raw_path.parents[1]
elif raw_path.match("v[0-9]") or raw_path.match("v[0-9][.][0-9]"):
path = "" if str(raw_path.parents[0]) == "/" else raw_path.parents[0]
else:
path = raw_path
proxy.url = raw_url._replace(path=f"{str(path)}/").geturl()
endpoints[f"{region}-{service_type}"] = proxy
return dict(sorted(endpoints.items(), key=lambda d: d[0]))
@click.command(help="Generate nginx proxy config file.")
@click.option(
"-o",
"--output-file",
"output_file_path",
help=(
"The path of the output file, this file is to generate a reverse proxy configuration "
"file based on the openstack endpoint and should be used in the location part of nginx."
),
)
@click.option(
"--ssl-certfile",
"ssl_certfile",
help=("SSL certificate file path."),
)
@click.option(
"--ssl-keyfile",
"ssl_keyfile",
help=("SSL key file path."),
)
@click.option(
"--listen-address",
"listen_address",
help=("nginx listen address."),
)
@click.option(
"--log-dir",
"log_dir",
help=("skyline log file address."),
)
def main(
output_file_path: str,
ssl_certfile: str,
ssl_keyfile: str,
listen_address: str,
log_dir: str,
) -> None:
try:
configure("skyline")
setup(StreamHandler(), debug=CONF.default.debug)
template_file_path = (
Path(skyline_nginx.__file__).parent.joinpath("templates").joinpath("nginx.conf.j2")
)
content = ""
with template_file_path.open() as f:
content = f.read()
template = Template(content)
endpoints = get_proxy_endpoints()
context = {
"skyline_console_static_path": static_path,
"endpoints": [i.dict() for i in endpoints.values()],
}
if ssl_certfile:
context.update(ssl_certfile=ssl_certfile)
if ssl_keyfile:
context.update(ssl_keyfile=ssl_keyfile)
if listen_address:
context.update(listen_address=listen_address)
if log_dir:
context.update(log_dir=log_dir)
result = template.render(**context)
if output_file_path:
with open(output_file_path, mode="w") as f:
f.write(result)
else:
print(result)
except CommandException as e:
LOG.error(e)
sys.exit(e.EXIT_CODE)
if __name__ == "__main__":
main()