blob: e352883c35067fa377bc107c130eee2ffe331895 [file] [log] [blame]
garciadeblas96b94f52024-07-08 16:18:21 +02001#######################################################################################
2# Licensed under the Apache License, Version 2.0 (the "License");
3# you may not use this file except in compliance with the License.
4# You may obtain a copy of the License at
rshri932105f2024-07-05 15:11:55 +00005#
garciadeblas96b94f52024-07-08 16:18:21 +02006# http://www.apache.org/licenses/LICENSE-2.0
rshri932105f2024-07-05 15:11:55 +00007#
8# Unless required by applicable law or agreed to in writing, software
garciadeblas96b94f52024-07-08 16:18:21 +02009# distributed under the License is distributed on an "AS IS" BASIS,
10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
11# implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14#######################################################################################
rshri932105f2024-07-05 15:11:55 +000015
16
17import logging
18from osm_lcm.lcm_utils import LcmBase
almagiacdd20ae2024-12-13 09:45:45 +010019from osm_lcm.n2vc import kubectl
garciadeblasc8d217d2025-05-26 15:14:47 +020020from osm_lcm.odu_libs import (
21 vim_mgmt as odu_vim_mgmt,
22 cluster_mgmt as odu_cluster_mgmt,
yshah83a30572025-06-13 08:38:49 +000023 nodegroup as odu_nodegroup,
garciadeblasc8d217d2025-05-26 15:14:47 +020024 ksu as odu_ksu,
25 oka as odu_oka,
26 profiles as odu_profiles,
27 workflows,
28 render as odu_render,
29 common as odu_common,
30)
garciadeblas96b94f52024-07-08 16:18:21 +020031
rshri932105f2024-07-05 15:11:55 +000032
33class OduWorkflow(LcmBase):
garciadeblasc8d217d2025-05-26 15:14:47 +020034 """
35 Class to manage the workflows for the OSM Deployment Unit (ODU).
36 This class is responsible for executing various workflows related to
37 cluster management, profile management, and other operations.
38 """
39
rshri932105f2024-07-05 15:11:55 +000040 def __init__(self, msg, lcm_tasks, config):
41 """
42 Init, Connect to database, filesystem storage, and messaging
43 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
44 :return: None
45 """
46
garciadeblas40539872024-09-11 14:28:38 +020047 self.logger = logging.getLogger("lcm.gitops")
rshri932105f2024-07-05 15:11:55 +000048 self.lcm_tasks = lcm_tasks
49 self.logger.info("Msg: {} lcm_tasks: {} ".format(msg, lcm_tasks))
50
garciadeblas96b94f52024-07-08 16:18:21 +020051 # self._kubeconfig = kubeconfig # TODO: get it from config
garciadeblas3364c472024-09-11 14:30:26 +020052 self.gitops_config = config["gitops"]
garciadeblase98a9182025-07-08 13:10:21 +020053 self.logger.debug(f"Gitops Config: {self.gitops_config}")
garciadeblasb8976952024-10-18 11:36:15 +020054 self._odu_checkloop_retry_time = 15
garciadeblas121a3432025-07-08 10:44:07 +020055 self._kubeconfig = self.gitops_config.get("mgmtcluster_kubeconfig")
garciadeblas96b94f52024-07-08 16:18:21 +020056 self._kubectl = kubectl.Kubectl(config_file=self._kubeconfig)
garciadeblas121a3432025-07-08 10:44:07 +020057 self._repo_base_url = self.gitops_config.get("git_base_url")
58 self._repo_user = self.gitops_config.get("user")
garciadeblas56c3aa82025-05-26 15:29:46 +020059 self._repo_fleet_url = self.gitops_config.get(
60 "fleet_repo_url", f"{self._repo_base_url}/{self._repo_user}/fleet-osm.git"
61 )
62 self._repo_sw_catalogs_url = self.gitops_config.get(
63 "sw_catalogs_repo_url",
64 f"{self._repo_base_url}/{self._repo_user}/sw-catalogs-osm.git",
65 )
garciadeblas3364c472024-09-11 14:30:26 +020066 self._pubkey = self.gitops_config["pubkey"]
garciadeblas326144e2025-01-27 11:16:27 +010067 self._workflow_debug = str(self.gitops_config["workflow_debug"]).lower()
68 self._workflow_dry_run = str(self.gitops_config["workflow_dry_run"]).lower()
garciadeblas96b94f52024-07-08 16:18:21 +020069 self._workflows = {
70 "create_cluster": {
71 "workflow_function": self.create_cluster,
garciadeblas28bff0f2024-09-16 12:53:07 +020072 "clean_function": self.clean_items_cluster_create,
garciadeblas96b94f52024-07-08 16:18:21 +020073 },
74 "update_cluster": {
75 "workflow_function": self.update_cluster,
garciadeblas28bff0f2024-09-16 12:53:07 +020076 "clean_function": self.clean_items_cluster_update,
garciadeblas96b94f52024-07-08 16:18:21 +020077 },
78 "delete_cluster": {
79 "workflow_function": self.delete_cluster,
garciadeblas96b94f52024-07-08 16:18:21 +020080 },
81 "register_cluster": {
82 "workflow_function": self.register_cluster,
garciadeblasdde3a312024-09-17 13:25:06 +020083 "clean_function": self.clean_items_cluster_register,
garciadeblas96b94f52024-07-08 16:18:21 +020084 },
85 "deregister_cluster": {
86 "workflow_function": self.deregister_cluster,
garciadeblas91bb2c42024-11-12 11:17:12 +010087 "clean_function": self.clean_items_cluster_deregister,
garciadeblas96b94f52024-07-08 16:18:21 +020088 },
89 "create_profile": {
90 "workflow_function": self.create_profile,
garciadeblas96b94f52024-07-08 16:18:21 +020091 },
92 "delete_profile": {
93 "workflow_function": self.delete_profile,
garciadeblas96b94f52024-07-08 16:18:21 +020094 },
95 "attach_profile_to_cluster": {
96 "workflow_function": self.attach_profile_to_cluster,
garciadeblas96b94f52024-07-08 16:18:21 +020097 },
98 "detach_profile_from_cluster": {
99 "workflow_function": self.detach_profile_from_cluster,
garciadeblas96b94f52024-07-08 16:18:21 +0200100 },
101 "create_oka": {
102 "workflow_function": self.create_oka,
garciadeblasb23d2dc2025-02-21 10:15:49 +0100103 "clean_function": self.clean_items_oka_create,
garciadeblas96b94f52024-07-08 16:18:21 +0200104 },
105 "update_oka": {
106 "workflow_function": self.update_oka,
garciadeblasb23d2dc2025-02-21 10:15:49 +0100107 "clean_function": self.clean_items_oka_update,
garciadeblas96b94f52024-07-08 16:18:21 +0200108 },
109 "delete_oka": {
110 "workflow_function": self.delete_oka,
garciadeblasb23d2dc2025-02-21 10:15:49 +0100111 "clean_function": self.clean_items_oka_delete,
garciadeblas96b94f52024-07-08 16:18:21 +0200112 },
113 "create_ksus": {
114 "workflow_function": self.create_ksus,
garciadeblasd8429852024-10-17 15:30:30 +0200115 "clean_function": self.clean_items_ksu_create,
garciadeblas96b94f52024-07-08 16:18:21 +0200116 },
117 "update_ksus": {
118 "workflow_function": self.update_ksus,
garciadeblasd8429852024-10-17 15:30:30 +0200119 "clean_function": self.clean_items_ksu_update,
garciadeblas96b94f52024-07-08 16:18:21 +0200120 },
121 "delete_ksus": {
122 "workflow_function": self.delete_ksus,
garciadeblas96b94f52024-07-08 16:18:21 +0200123 },
124 "clone_ksu": {
125 "workflow_function": self.clone_ksu,
garciadeblas96b94f52024-07-08 16:18:21 +0200126 },
127 "move_ksu": {
128 "workflow_function": self.move_ksu,
garciadeblas96b94f52024-07-08 16:18:21 +0200129 },
130 "create_cloud_credentials": {
131 "workflow_function": self.create_cloud_credentials,
garciadeblas28bff0f2024-09-16 12:53:07 +0200132 "clean_function": self.clean_items_cloud_credentials_create,
garciadeblas96b94f52024-07-08 16:18:21 +0200133 },
134 "update_cloud_credentials": {
135 "workflow_function": self.update_cloud_credentials,
garciadeblas28bff0f2024-09-16 12:53:07 +0200136 "clean_function": self.clean_items_cloud_credentials_update,
garciadeblas96b94f52024-07-08 16:18:21 +0200137 },
138 "delete_cloud_credentials": {
139 "workflow_function": self.delete_cloud_credentials,
garciadeblas96b94f52024-07-08 16:18:21 +0200140 },
141 "dummy_operation": {
142 "workflow_function": self.dummy_operation,
garciadeblas96b94f52024-07-08 16:18:21 +0200143 },
yshah83a30572025-06-13 08:38:49 +0000144 "add_nodegroup": {
145 "workflow_function": self.add_nodegroup,
146 "clean_function": self.clean_items_nodegroup_add,
147 },
148 "scale_nodegroup": {
149 "workflow_function": self.scale_nodegroup,
150 },
151 "delete_nodegroup": {
152 "workflow_function": self.delete_nodegroup,
153 "clean_function": self.clean_items_nodegroup_delete,
154 },
garciadeblas96b94f52024-07-08 16:18:21 +0200155 }
156
rshri932105f2024-07-05 15:11:55 +0000157 super().__init__(msg, self.logger)
158
garciadeblas96b94f52024-07-08 16:18:21 +0200159 @property
160 def kubeconfig(self):
161 return self._kubeconfig
162
163 # Imported methods
garciadeblasc8d217d2025-05-26 15:14:47 +0200164 create_cloud_credentials = odu_vim_mgmt.create_cloud_credentials
165 update_cloud_credentials = odu_vim_mgmt.update_cloud_credentials
166 delete_cloud_credentials = odu_vim_mgmt.delete_cloud_credentials
167 clean_items_cloud_credentials_create = (
168 odu_vim_mgmt.clean_items_cloud_credentials_create
garciadeblas96b94f52024-07-08 16:18:21 +0200169 )
garciadeblasc8d217d2025-05-26 15:14:47 +0200170 clean_items_cloud_credentials_update = (
171 odu_vim_mgmt.clean_items_cloud_credentials_update
garciadeblas96b94f52024-07-08 16:18:21 +0200172 )
garciadeblasc8d217d2025-05-26 15:14:47 +0200173 create_cluster = odu_cluster_mgmt.create_cluster
174 update_cluster = odu_cluster_mgmt.update_cluster
175 delete_cluster = odu_cluster_mgmt.delete_cluster
176 register_cluster = odu_cluster_mgmt.register_cluster
177 deregister_cluster = odu_cluster_mgmt.deregister_cluster
178 clean_items_cluster_create = odu_cluster_mgmt.clean_items_cluster_create
179 clean_items_cluster_update = odu_cluster_mgmt.clean_items_cluster_update
180 clean_items_cluster_register = odu_cluster_mgmt.clean_items_cluster_register
181 clean_items_cluster_deregister = odu_cluster_mgmt.clean_items_cluster_deregister
182 get_cluster_credentials = odu_cluster_mgmt.get_cluster_credentials
yshah83a30572025-06-13 08:38:49 +0000183 add_nodegroup = odu_nodegroup.add_nodegroup
184 scale_nodegroup = odu_nodegroup.scale_nodegroup
185 delete_nodegroup = odu_nodegroup.delete_nodegroup
186 clean_items_nodegroup_add = odu_nodegroup.clean_items_nodegroup_add
187 clean_items_nodegroup_delete = odu_nodegroup.clean_items_nodegroup_delete
garciadeblasc8d217d2025-05-26 15:14:47 +0200188 create_ksus = odu_ksu.create_ksus
189 update_ksus = odu_ksu.update_ksus
190 delete_ksus = odu_ksu.delete_ksus
191 clone_ksu = odu_ksu.clone_ksu
192 move_ksu = odu_ksu.move_ksu
193 clean_items_ksu_create = odu_ksu.clean_items_ksu_create
194 clean_items_ksu_update = odu_ksu.clean_items_ksu_update
195 clean_items_ksu_delete = odu_ksu.clean_items_ksu_delete
196 create_oka = odu_oka.create_oka
197 update_oka = odu_oka.update_oka
198 delete_oka = odu_oka.delete_oka
199 clean_items_oka_create = odu_oka.clean_items_oka_create
200 clean_items_oka_update = odu_oka.clean_items_oka_update
201 clean_items_oka_delete = odu_oka.clean_items_oka_delete
202 create_profile = odu_profiles.create_profile
203 delete_profile = odu_profiles.delete_profile
204 attach_profile_to_cluster = odu_profiles.attach_profile_to_cluster
205 detach_profile_from_cluster = odu_profiles.detach_profile_from_cluster
206 check_workflow_status = workflows.check_workflow_status
207 readiness_loop = workflows.readiness_loop
208 render_jinja_template = odu_render.render_jinja_template
209 render_yaml_template = odu_render.render_yaml_template
210 create_secret = odu_common.create_secret
211 delete_secret = odu_common.delete_secret
rshrif8911b92025-06-11 18:19:07 +0000212 create_configmap = odu_common.create_configmap
213 delete_configmap = odu_common.delete_configmap
garciadeblas96b94f52024-07-08 16:18:21 +0200214
215 async def launch_workflow(self, key, op_id, op_params, content):
rshri932105f2024-07-05 15:11:55 +0000216 self.logger.info(
garciadeblas96b94f52024-07-08 16:18:21 +0200217 f"Workflow is getting into launch. Key: {key}. Operation: {op_id}. Params: {op_params}. Content: {content}"
rshri932105f2024-07-05 15:11:55 +0000218 )
garciadeblas96b94f52024-07-08 16:18:21 +0200219 workflow_function = self._workflows[key]["workflow_function"]
220 self.logger.info("workflow function : {}".format(workflow_function))
garciadeblas41859ce2025-02-04 16:08:51 +0100221 try:
222 result, workflow_name = await workflow_function(op_id, op_params, content)
223 return result, workflow_name
224 except Exception as e:
225 self.logger.error(f"Error launching workflow: {e}")
226 return False, str(e)
rshri932105f2024-07-05 15:11:55 +0000227
garciadeblas5359e992024-12-13 11:09:04 +0100228 async def dummy_clean_items(self, op_id, op_params, content):
garciadeblas98f9a3d2024-12-10 13:42:47 +0100229 self.logger.info(
garciadeblas5359e992024-12-13 11:09:04 +0100230 f"dummy_clean_items Enter. Operation {op_id}. Params: {op_params}"
garciadeblas98f9a3d2024-12-10 13:42:47 +0100231 )
garciadeblas5359e992024-12-13 11:09:04 +0100232 self.logger.debug(f"Content: {content}")
garciadeblas98f9a3d2024-12-10 13:42:47 +0100233 return True, "OK"
234
garciadeblas28bff0f2024-09-16 12:53:07 +0200235 async def clean_items_workflow(self, key, op_id, op_params, content):
236 self.logger.info(
237 f"Cleaning items created during workflow launch. Key: {key}. Operation: {op_id}. Params: {op_params}. Content: {content}"
238 )
garciadeblas98f9a3d2024-12-10 13:42:47 +0100239 clean_items_function = self._workflows[key].get(
240 "clean_function", self.dummy_clean_items
241 )
garciadeblas28bff0f2024-09-16 12:53:07 +0200242 self.logger.info("clean items function : {}".format(clean_items_function))
243 return await clean_items_function(op_id, op_params, content)
244
garciadeblas96b94f52024-07-08 16:18:21 +0200245 async def dummy_operation(self, op_id, op_params, content):
246 self.logger.info("Empty operation status Enter")
247 self.logger.info(f"Operation {op_id}. Params: {op_params}. Content: {content}")
248 return content["workflow_name"]
rshri932105f2024-07-05 15:11:55 +0000249
garciadeblas28bff0f2024-09-16 12:53:07 +0200250 async def clean_items(self, items):
garciadeblasb23d2dc2025-02-21 10:15:49 +0100251 # Delete pods
252 for pod in items.get("pods", []):
253 name = pod["name"]
254 namespace = pod["namespace"]
255 self.logger.info(f"Deleting pod {name} in namespace {namespace}")
256 self.logger.debug(f"Testing kubectl: {self._kubectl}")
257 self.logger.debug(
258 f"Testing kubectl configuration: {self._kubectl.configuration}"
259 )
260 self.logger.debug(
261 f"Testing kubectl configuration Host: {self._kubectl.configuration.host}"
262 )
263 await self._kubectl.delete_pod(name, namespace)
garciadeblas28bff0f2024-09-16 12:53:07 +0200264 # Delete secrets
265 for secret in items.get("secrets", []):
266 name = secret["name"]
267 namespace = secret["namespace"]
268 self.logger.info(f"Deleting secret {name} in namespace {namespace}")
garciadeblas6d8acf32025-02-06 13:34:37 +0100269 self.logger.debug(f"Testing kubectl: {self._kubectl}")
270 self.logger.debug(
271 f"Testing kubectl configuration: {self._kubectl.configuration}"
272 )
273 self.logger.debug(
274 f"Testing kubectl configuration Host: {self._kubectl.configuration.host}"
275 )
garciadeblas28bff0f2024-09-16 12:53:07 +0200276 self.delete_secret(name, namespace)
277 # Delete pvcs
278 for pvc in items.get("pvcs", []):
279 name = pvc["name"]
280 namespace = pvc["namespace"]
281 self.logger.info(f"Deleting pvc {name} in namespace {namespace}")
garciadeblas6d8acf32025-02-06 13:34:37 +0100282 self.logger.debug(f"Testing kubectl: {self._kubectl}")
283 self.logger.debug(
284 f"Testing kubectl configuration: {self._kubectl.configuration}"
285 )
286 self.logger.debug(
287 f"Testing kubectl configuration Host: {self._kubectl.configuration.host}"
288 )
garciadeblas28bff0f2024-09-16 12:53:07 +0200289 await self._kubectl.delete_pvc(name, namespace)
rshrif8911b92025-06-11 18:19:07 +0000290 # Delete configmaps
291 for configmap in items.get("configmaps", []):
292 name = configmap["name"]
293 namespace = configmap["namespace"]
294 self.logger.info(f"Deleting configmap {name} in namespace {namespace}")
295 self.logger.debug(f"Testing kubectl: {self._kubectl}")
296 self.logger.debug(
297 f"Testing kubectl configuration: {self._kubectl.configuration}"
298 )
299 self.logger.debug(
300 f"Testing kubectl configuration Host: {self._kubectl.configuration.host}"
301 )
302 self.delete_configmap(name, namespace)
303
304 async def list_object(self, api_group, api_plural, api_version):
305 self.logger.info(
306 f"Api group: {api_group} Api plural: {api_plural} Api version: {api_version}"
307 )
308 generic_object = await self._kubectl.list_generic_object(
309 api_group=api_group,
310 api_plural=api_plural,
311 api_version=api_version,
312 namespace="",
313 )
314 return generic_object