From 41b2db9f60a21a4084cb00749c1441b5f25aa18f Mon Sep 17 00:00:00 2001 From: rshri Date: Wed, 11 Jun 2025 11:17:42 +0000 Subject: [PATCH] Update cluster configuration to support feature 11055 Change-Id: Ide21bc1d4ce6bdb54b8c82ab3cc456e4ba8bb39f Signed-off-by: rshri --- osm_nbi/k8s_topics.py | 196 +++++++++++++++++++++++++++--------------- osm_nbi/validation.py | 40 +++++---- 2 files changed, 150 insertions(+), 86 deletions(-) diff --git a/osm_nbi/k8s_topics.py b/osm_nbi/k8s_topics.py index 3cf676b..90b85c9 100644 --- a/osm_nbi/k8s_topics.py +++ b/osm_nbi/k8s_topics.py @@ -171,47 +171,58 @@ class ClusterTopic(ACMTopic): EngineException, ValidationError, DbException, FsException, MsgException. Note: Exceptions are not captured on purpose. They should be captured at called """ + step = "checking quotas" # first step must be defined outside try try: - self.check_quota(session) + if self.multiproject: + self.check_quota(session) + + content = self._remove_envelop(indata) + step = "name unique check" - # self.check_unique_name(session, indata["name"]) self.cluster_unique_name_check(session, indata["name"]) + step = "validating input parameters" - cls_request = self._remove_envelop(indata) - self._update_input_with_kwargs(cls_request, kwargs) - cls_request = self._validate_input_new(cls_request, session["force"]) - operation_params = cls_request + self._update_input_with_kwargs(content, kwargs) + + content = self._validate_input_new(content, session, force=session["force"]) + + operation_params = indata.copy() + + self.check_conflict_on_new(session, content) + self.format_on_new( + content, project_id=session["project_id"], make_public=session["public"] + ) step = "filling cluster details from input data" - cls_create = self._create_cluster( - cls_request, rollback, session, indata, kwargs, headers + content = self._create_cluster( + content, rollback, session, indata, kwargs, headers ) step = "creating cluster at database" - self.format_on_new( - cls_create, session["project_id"], make_public=session["public"] - ) + _id = self.db.create(self.topic, content) + op_id = self.format_on_operation( - cls_create, + content, "create", operation_params, ) - _id = self.db.create(self.topic, cls_create) + pubkey, privkey = self._generate_age_key() - cls_create["age_pubkey"] = self.db.encrypt( + content["age_pubkey"] = self.db.encrypt( pubkey, schema_version="1.11", salt=_id ) - cls_create["age_privkey"] = self.db.encrypt( + content["age_privkey"] = self.db.encrypt( privkey, schema_version="1.11", salt=_id ) + # TODO: set age_pubkey and age_privkey in the default profiles rollback.append({"topic": self.topic, "_id": _id}) - self.db.set_one("clusters", {"_id": _id}, cls_create) + self.db.set_one("clusters", {"_id": _id}, content) self._send_msg("create", {"cluster_id": _id, "operation_id": op_id}) # To add the content in old collection "k8sclusters" - self.add_to_old_collection(cls_create, session) + self.add_to_old_collection(content, session) return _id, None except ( @@ -223,68 +234,115 @@ class ClusterTopic(ACMTopic): ) as e: raise type(e)("{} while '{}'".format(e, step), http_code=e.http_code) - def _create_cluster(self, cls_request, rollback, session, indata, kwargs, headers): + def _validate_input_new(self, content, session, force=False): + # validating vim and checking the mandatory parameters + vim_type = self.check_vim(session, content["vim_account"]) + + # for aws + if vim_type == "aws": + self._aws_check(content) + + # for azure and gcp + elif vim_type in ["azure", "gcp"]: + self._params_check(content) + + return super()._validate_input_new(content, force=session["force"]) + + def _aws_check(self, indata): + if "node_count" in indata or "node_size" in indata: + raise ValueError("node_count and node_size are not allowed for AWS") + return + + def _params_check(self, indata): + if "node_count" not in indata and "node_size" not in indata: + raise ValueError("node_count and node_size are mandatory parameter") + return + + def _create_cluster(self, content, rollback, session, indata, kwargs, headers): + private_subnet = indata.get("private_subnet") + public_subnet = indata.get("public_subnet") + + # Enforce: if private_subnet is provided, public_subnet must also be provided + if (private_subnet and not public_subnet) or ( + public_subnet and not private_subnet + ): + raise ValueError( + "'public_subnet' must be provided if 'private_subnet' is given and viceversa." + ) + + # private Subnet validation + if private_subnet: + count = len(private_subnet) + if count != 2: + raise ValueError( + f"private_subnet must contain exactly 2 items, got {count}" + ) + + # public Subnet validation + public_subnet = indata.get("public_subnet") + if public_subnet: + count = len(public_subnet) + if count != 1: + raise ValueError( + f"public_subnet must contain exactly 1 items, got {count}" + ) + + content["infra_controller_profiles"] = [ + self._create_default_profiles( + rollback, session, indata, kwargs, headers, self.infra_contr_topic + ) + ] + content["infra_config_profiles"] = [ + self._create_default_profiles( + rollback, session, indata, kwargs, headers, self.infra_conf_topic + ) + ] + content["resource_profiles"] = [ + self._create_default_profiles( + rollback, session, indata, kwargs, headers, self.resource_topic + ) + ] + content["app_profiles"] = [ + self._create_default_profiles( + rollback, session, indata, kwargs, headers, self.app_topic + ) + ] + content["created"] = "true" + content["state"] = "IN_CREATION" + content["operatingState"] = "PROCESSING" + content["git_name"] = self.create_gitname(content, session) + content["resourceState"] = "IN_PROGRESS.REQUEST_RECEIVED" + # Get the vim_account details vim_account_details = self.db.get_one( - "vim_accounts", {"name": cls_request["vim_account"]} + "vim_accounts", {"name": content["vim_account"]} ) - # Check whether the region name and resource group have been given - if "region_name" in indata: - region_name = cls_request["region_name"] - else: - region_name = vim_account_details["config"].get("region_name") - - cls_desc = { - "name": cls_request["name"], - "vim_account": self.check_vim(session, cls_request["vim_account"]), - "k8s_version": cls_request["k8s_version"], - "node_size": cls_request["node_size"], - "node_count": cls_request["node_count"], - "bootstrap": cls_request["bootstrap"], - "region_name": region_name, - "infra_controller_profiles": [ - self._create_default_profiles( - rollback, session, indata, kwargs, headers, self.infra_contr_topic - ) - ], - "infra_config_profiles": [ - self._create_default_profiles( - rollback, session, indata, kwargs, headers, self.infra_conf_topic - ) - ], - "resource_profiles": [ - self._create_default_profiles( - rollback, session, indata, kwargs, headers, self.resource_topic - ) - ], - "app_profiles": [ - self._create_default_profiles( - rollback, session, indata, kwargs, headers, self.app_topic - ) - ], - "created": "true", - "state": "IN_CREATION", - "operatingState": "PROCESSING", - "git_name": self.create_gitname(cls_request, session), - "resourceState": "IN_PROGRESS.REQUEST_RECEIVED", - } # Add optional fields if they exist in the request - if "resource_group" in indata: - resource_group = cls_request["resource_group"] - else: - resource_group = vim_account_details["config"].get("resource_group") - if resource_group: - cls_desc["resource_group"] = resource_group - if "description" in cls_request: - cls_desc["description"] = cls_request["description"] - return cls_desc + + if "region_name" not in indata: + region_name = vim_account_details.get("config", {}).get("region_name") + if region_name: + content["region_name"] = region_name + + if "resource_group" not in indata: + resource_group = vim_account_details.get("config", {}).get("resource_group") + if resource_group: + content["resource_group"] = resource_group + + version = "k8s_version" in content + if not version: + content["k8s_version"] = "1.28" + content["node_count"] = indata.get("node_count", 0) + content["ksu_count"] = "0" + self.logger.info(f"cotent is : {content}") + return content def check_vim(self, session, name): try: vim_account_details = self.db.get_one("vim_accounts", {"name": name}) if vim_account_details is not None: - return name + return vim_account_details["vim_type"] except ValidationError as e: raise EngineException( e, diff --git a/osm_nbi/validation.py b/osm_nbi/validation.py index 95556ff..1df72b4 100644 --- a/osm_nbi/validation.py +++ b/osm_nbi/validation.py @@ -1093,8 +1093,8 @@ vnfpkgop_new_schema = { } clustercreation_new_schema = { + "$schema": "http://json-schema.org/draft-07/schema#", "title": "cluster creation operation input schema", - "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "name": name_schema, @@ -1105,26 +1105,32 @@ clustercreation_new_schema = { "description": description_schema, "region_name": string_schema, "resource_group": string_schema, - "infra_controller_profiles": shortname_schema, - "infra_config_profiles": shortname_schema, - "resource_profiles": shortname_schema, - "app_profiles": shortname_schema, - "created": string_schema, - "state": string_schema, - "operatingState": string_schema, - "git_name": string_schema, - "resourceState": string_schema, "bootstrap": bool_schema, + # "vim_type": string_schema, + "private_subnet": { # Subnets validation + "type": "array", + "items": { # Each item in the array must be a string (subnet ID) + "type": "string", + "pattern": "^subnet-[a-f0-9]+$", # Optional: Add a regex pattern for basic subnet ID format + }, + # "minItems": 2, # Minimum 2 subnets + "uniqueItems": True, # Subnet IDs must be unique + }, + "public_subnet": { # Subnets validation + "type": "array", + "items": { # Each item in the array must be a string (subnet ID) + "type": "string", + "pattern": "^subnet-[a-f0-9]+$", # Optional: Add a regex pattern for basic subnet ID format + }, + # "minItems": 2, # Minimum 2 subnets + "uniqueItems": True, # Subnet IDs must be unique + }, + "iam_role": string_schema, }, - "required": [ - "name", - "vim_account", - "k8s_version", - "node_size", - "node_count", - ], + "required": ["vim_account", "name", "k8s_version"], "additionalProperties": False, } + clusterregistration_new_schema = { "title": "cluster registration input schema", "$schema": "http://json-schema.org/draft-04/schema#", -- 2.25.1