blob: b89fca353ba77a0c7e6a8c9e533e182ab0dbff83 [file] [log] [blame]
#######################################################################################
# Copyright ETSI Contributors and Others.
#
# 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 click
from osmclient.cli_commands import common
from osmclient.common.exceptions import ClientException
import logging
import yaml
logger = logging.getLogger("osmclient")
def verify_and_update_ksu(ctx, ksu):
def get_oka_id(ctx, oka_name):
logger.debug("")
resp = ctx.obj.oka.get(oka_name)
logger.debug(f"OKA obtained: {resp}")
if "_id" in resp:
return resp["_id"]
else:
raise ClientException("Unexpected failure when reading the OKA")
def get_profile_id(ctx, profile, profile_type):
logger.debug("")
get_function = {
"infra-controller-profile": ctx.obj.infra_controller_profile.get,
"infra-config-profile": ctx.obj.infra_config_profile.get,
"app-profile": ctx.obj.app_profile.get,
"resource-profile": ctx.obj.resource_profile.get,
}
resp = get_function[profile_type](profile)
logger.debug(f"Profile obtained: {resp}")
if "_id" in resp:
return resp["_id"]
else:
raise ClientException("Unexpected failure when reading the profile")
logger.debug("")
if "name" not in ksu:
raise ClientException("A name must be provided for each KSU")
else:
# TODO if ctx.command.name == "ksu-update", update ksu if needed
pass
if "profile" in ksu:
ksu_profile = ksu["profile"]
ksu_profile_type = ksu_profile.get("profile_type")
if "_id" in ksu_profile:
ksu_profile["_id"] = get_profile_id(
ctx, ksu_profile["_id"], ksu_profile_type
)
else:
raise ClientException("A profile id or name must be provided for each KSU")
else:
raise ClientException("A profile must be provided for each KSU")
if "oka" in ksu:
for oka in ksu["oka"]:
if "_id" in oka:
oka["_id"] = get_oka_id(ctx, oka["_id"])
elif "sw_catalog_path" not in oka:
raise ClientException(
"An OKA id or name, or a SW catalog path must be provided for each OKA"
)
else:
raise ClientException(
"At least one OKA or SW catalog path must be provided for each KSU"
)
def process_common_ksu_params(ctx, ksu_dict, ksu_args):
def process_common_oka_params(ctx, oka_dict, oka_args):
logger.debug("")
i = 0
while i < len(oka_args):
if oka_args[i] == "--oka":
if (i + 1 >= len(oka_args)) or oka_args[i + 1].startswith("--"):
raise ClientException("No OKA was provided after --oka")
oka_dict["_id"] = oka_args[i + 1]
i = i + 2
continue
if oka_args[i] == "--sw-catalog-path":
if (i + 1 >= len(oka_args)) or oka_args[i + 1].startswith("--"):
raise ClientException(
"No path was provided after --sw-catalog-path"
)
oka_dict["sw_catalog_path"] = oka_args[i + 1]
i = i + 2
continue
elif oka_args[i] == "--params":
if (i + 1 >= len(oka_args)) or oka_args[i + 1].startswith("--"):
raise ClientException("No params file was provided after --params")
with open(oka_args[i + 1], "r") as pf:
oka_dict["transformation"] = yaml.safe_load(pf.read())
i = i + 2
continue
else:
raise ClientException(f"Unknown option for OKA: {oka_args[i]}")
logger.debug("")
i = 0
while i < len(ksu_args):
if ksu_args[i] == "--description":
if (i + 1 >= len(ksu_args)) or ksu_args[i + 1].startswith("--"):
raise ClientException("No description was provided after --description")
ksu_dict["description"] = ksu_args[i + 1]
i = i + 2
continue
elif ksu_args[i] == "--profile":
if (i + 1 >= len(ksu_args)) or ksu_args[i + 1].startswith("--"):
raise ClientException(
"No profile name or ID was provided after --profile"
)
if "profile" not in ksu_dict:
ksu_dict["profile"] = {}
ksu_dict["profile"]["_id"] = ksu_args[i + 1]
i = i + 2
continue
elif ksu_args[i] == "--profile-type":
if (i + 1 >= len(ksu_args)) or ksu_args[i + 1].startswith("--"):
raise ClientException(
"No profile type was provided after --profile-type"
)
if "profile" not in ksu_dict:
ksu_dict["profile"] = {}
profile_type = ksu_args[i + 1]
profile_set = (
"infra-controller-profile",
"infra-config-profile",
"app-profile",
"resource-profile",
)
if profile_type not in profile_set:
raise ClientException(f"Profile type must be one of: {profile_set}")
ksu_dict["profile"]["profile_type"] = ksu_args[i + 1]
i = i + 2
continue
elif ksu_args[i] == "--oka" or ksu_args[i] == "--sw-catalog-path":
# Split the tuple by "--oka"
logger.debug(ksu_args[i:])
okas = common.iterator_split(ksu_args[i:], ("--oka", "--sw-catalog-path"))
logger.debug(f"OKAs: {okas}")
oka_list = []
for oka in okas:
oka_dict = {}
process_common_oka_params(ctx, oka_dict, oka)
oka_list.append(oka_dict)
ksu_dict["oka"] = oka_list
break
else:
if ksu_args[i] == "--params":
raise ClientException(
"Option --params must be specified for an OKA or sw-catalog-path"
)
else:
raise ClientException(f"Unknown option for KSU: {ksu_args[i]}")
return
def process_ksu_params(ctx, param, value):
"""
Processes the params in the commands ksu-create and ksu-update
Click does not allow advanced patterns for positional options like this:
--ksu jenkins --description "Jenkins KSU"
--profile profile1 --profile-type infra-controller-profile
--oka jenkins-controller --params jenkins-controller.yaml
--oka jenkins-config --params jenkins-config.yaml
--ksu prometheus --description "Prometheus KSU"
--profile profile2 --profile-type infra-controller-profile
--sw-catalog-path infra-controllers/prometheus --params prometheus-controller.yaml
It returns the dictionary with all the params stored in ctx.params["ksu_params"]
"""
logger.debug("")
logger.debug(f"Args: {value}")
if param.name != "args":
raise ClientException(f"Unexpected param: {param.name}")
# Split the tuple "value" by "--ksu"
ksus = common.iterator_split(value, ["--ksu"])
logger.debug(f"KSUs: {ksus}")
ksu_list = []
for ksu in ksus:
ksu_dict = {}
if ksu[1].startswith("--"):
raise ClientException("Expected a KSU after --ksu")
ksu_dict["name"] = ksu[1]
process_common_ksu_params(ctx, ksu_dict, ksu[2:])
ksu_list.append(ksu_dict)
ctx.params["ksu_params"] = ksu_list
logger.debug(f"KSU params: {ksu_list}")
return
@click.command(
name="ksu-create",
short_help="creates KSUs in OSM",
context_settings=dict(
ignore_unknown_options=True,
),
)
@click.argument(
"args",
nargs=-1,
type=click.UNPROCESSED,
callback=process_ksu_params,
)
@click.pass_context
def ksu_create(ctx, args, ksu_params):
"""creates one or several Kubernetes SW Units (KSU) in OSM
\b
Options:
--ksu NAME name of the KSU to be created
--profile NAME name or ID of the profile the KSU will belong to
--profile_type TYPE type of the profile:
[infra-controller-profile|infra-config-profile|app-profile|resource-profile]
--oka OKA_ID name or ID of the OKA that will be incorporated to the KSU
(either --oka or --sw_catalog must be used)
--sw_catalog TEXT folder in the SW catalog (git repo) that will be incorporated to the KSU
(either --oka or --sw_catalog must be used)
--params FILE file with the values that parametrize the OKA or the sw_catalog
\b
Example:
osm ksu-create --ksu jenkins --description "Jenkins KSU"
--profile profile1 --profile-type infra-controller-profile
--oka jenkins-controller --params jenkins-controller.yaml
--oka jenkins-config --params jenkins-config.yaml
--ksu prometheus --description "Prometheus KSU"
--profile profile2 --profile-type infra-controller-profile
--sw-catalog-path infra-controllers/prometheus --params prometheus-controller.yaml
"""
logger.debug("")
logger.debug(f"ksu_params:\n{yaml.safe_dump(ksu_params)}")
for ksu in ksu_params:
verify_and_update_ksu(ctx, ksu)
logger.debug(f"ksu_params:\n{yaml.safe_dump(ksu_params)}")
ctx.obj.ksu.multi_create_update(ksu_params, "create")
@click.command(name="ksu-delete", short_help="deletes one or several KSU")
@click.argument("ksus", type=str, nargs=-1, metavar="<KSU> [<KSU>...]")
@click.option(
"--force", is_flag=True, help="forces the deletion from the DB (not recommended)"
)
@click.pass_context
def ksu_delete(ctx, ksus, force):
"""deletes one or several KSUs
KSU: name or ID of the KSU to be deleted
"""
logger.debug("")
ctx.obj.ksu.multi_delete(ksus, "ksus", force=force)
@click.command(name="ksu-list")
@click.option(
"--filter",
help="restricts the list to the items matching the filter",
)
@click.pass_context
def ksu_list(ctx, filter):
"""list all Kubernetes SW Units (KSU)"""
logger.debug("")
common.generic_list(callback=ctx.obj.ksu.list, filter=filter)
@click.command(name="ksu-show", short_help="shows the details of a KSU")
@click.argument("name")
@click.pass_context
def ksu_show(ctx, name):
"""shows the details of a KSU
NAME: name or ID of the KSU
"""
logger.debug("")
common.generic_show(callback=ctx.obj.ksu.get, name=name)
@click.command(
name="ksu-update",
short_help="updates KSUs in OSM",
context_settings=dict(
ignore_unknown_options=True,
),
)
@click.argument(
"args",
nargs=-1,
type=click.UNPROCESSED,
callback=process_ksu_params,
)
@click.pass_context
def ksu_update(ctx, args, ksu_params):
"""updates one or several Kubernetes SW Units (KSU) in OSM
\b
Options:
--ksu NAME name of the KSU to be udpated
--profile NAME name or ID of the profile the KSU will belong to
--profile_type TYPE type of the profile:
[infra-controller-profile|infra-config-profile|app-profile|resource-profile]
--oka OKA_ID name or ID of the OKA that will be incorporated to the KSU
(either --oka or --sw_catalog must be used)
--sw_catalog TEXT folder in the SW catalog (git repo) that will be incorporated to the KSU
(either --oka or --sw_catalog must be used)
--params FILE file with the values that parametrize the OKA or the sw_catalog
\b
Example:
osm ksu-update --ksu jenkins --description "Jenkins KSU"
--profile profile1 --profile-type infra-controller-profile
--oka jenkins-controller --params jenkins-controller.yaml
--oka jenkins-config --params jenkins-config.yaml
--ksu prometheus --description "Prometheus KSU"
--profile profile2 --profile-type infra-controller-profile
--sw-catalog-path infra-controllers/prometheus --params prometheus-controller.yaml
"""
logger.debug("")
logger.debug(f"ksu_params:\n{yaml.safe_dump(ksu_params)}")
for ksu in ksu_params:
verify_and_update_ksu(ctx, ksu)
logger.debug(f"ksu_params:\n{yaml.safe_dump(ksu_params)}")
ctx.obj.ksu.multi_create_update(ksu_params, "create")