blob: 0c51b2d8cab00ea52718f50168e5e9bc8f73c18f [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,
garciadeblas61a4c692025-07-17 13:04:13 +020024 app as odu_app,
garciadeblasc8d217d2025-05-26 15:14:47 +020025 ksu as odu_ksu,
26 oka as odu_oka,
27 profiles as odu_profiles,
28 workflows,
29 render as odu_render,
30 common as odu_common,
31)
garciadeblas96b94f52024-07-08 16:18:21 +020032
rshri932105f2024-07-05 15:11:55 +000033
34class OduWorkflow(LcmBase):
garciadeblasc8d217d2025-05-26 15:14:47 +020035 """
36 Class to manage the workflows for the OSM Deployment Unit (ODU).
37 This class is responsible for executing various workflows related to
38 cluster management, profile management, and other operations.
39 """
40
rshri932105f2024-07-05 15:11:55 +000041 def __init__(self, msg, lcm_tasks, config):
42 """
43 Init, Connect to database, filesystem storage, and messaging
44 :param config: two level dictionary with configuration. Top level should contain 'database', 'storage',
45 :return: None
46 """
47
garciadeblas40539872024-09-11 14:28:38 +020048 self.logger = logging.getLogger("lcm.gitops")
rshri932105f2024-07-05 15:11:55 +000049 self.lcm_tasks = lcm_tasks
50 self.logger.info("Msg: {} lcm_tasks: {} ".format(msg, lcm_tasks))
51
garciadeblas96b94f52024-07-08 16:18:21 +020052 # self._kubeconfig = kubeconfig # TODO: get it from config
garciadeblas3364c472024-09-11 14:30:26 +020053 self.gitops_config = config["gitops"]
garciadeblase98a9182025-07-08 13:10:21 +020054 self.logger.debug(f"Gitops Config: {self.gitops_config}")
garciadeblasb8976952024-10-18 11:36:15 +020055 self._odu_checkloop_retry_time = 15
garciadeblas121a3432025-07-08 10:44:07 +020056 self._kubeconfig = self.gitops_config.get("mgmtcluster_kubeconfig")
garciadeblas96b94f52024-07-08 16:18:21 +020057 self._kubectl = kubectl.Kubectl(config_file=self._kubeconfig)
garciadeblas121a3432025-07-08 10:44:07 +020058 self._repo_base_url = self.gitops_config.get("git_base_url")
59 self._repo_user = self.gitops_config.get("user")
garciadeblas56c3aa82025-05-26 15:29:46 +020060 self._repo_fleet_url = self.gitops_config.get(
61 "fleet_repo_url", f"{self._repo_base_url}/{self._repo_user}/fleet-osm.git"
62 )
63 self._repo_sw_catalogs_url = self.gitops_config.get(
64 "sw_catalogs_repo_url",
65 f"{self._repo_base_url}/{self._repo_user}/sw-catalogs-osm.git",
66 )
garciadeblas3364c472024-09-11 14:30:26 +020067 self._pubkey = self.gitops_config["pubkey"]
garciadeblas326144e2025-01-27 11:16:27 +010068 self._workflow_debug = str(self.gitops_config["workflow_debug"]).lower()
69 self._workflow_dry_run = str(self.gitops_config["workflow_dry_run"]).lower()
garciadeblas96b94f52024-07-08 16:18:21 +020070 self._workflows = {
71 "create_cluster": {
72 "workflow_function": self.create_cluster,
garciadeblas28bff0f2024-09-16 12:53:07 +020073 "clean_function": self.clean_items_cluster_create,
garciadeblas96b94f52024-07-08 16:18:21 +020074 },
75 "update_cluster": {
76 "workflow_function": self.update_cluster,
garciadeblas28bff0f2024-09-16 12:53:07 +020077 "clean_function": self.clean_items_cluster_update,
garciadeblas96b94f52024-07-08 16:18:21 +020078 },
79 "delete_cluster": {
80 "workflow_function": self.delete_cluster,
garciadeblas96b94f52024-07-08 16:18:21 +020081 },
82 "register_cluster": {
83 "workflow_function": self.register_cluster,
garciadeblasdde3a312024-09-17 13:25:06 +020084 "clean_function": self.clean_items_cluster_register,
garciadeblas96b94f52024-07-08 16:18:21 +020085 },
86 "deregister_cluster": {
87 "workflow_function": self.deregister_cluster,
garciadeblas91bb2c42024-11-12 11:17:12 +010088 "clean_function": self.clean_items_cluster_deregister,
garciadeblas96b94f52024-07-08 16:18:21 +020089 },
90 "create_profile": {
91 "workflow_function": self.create_profile,
garciadeblas96b94f52024-07-08 16:18:21 +020092 },
93 "delete_profile": {
94 "workflow_function": self.delete_profile,
garciadeblas96b94f52024-07-08 16:18:21 +020095 },
96 "attach_profile_to_cluster": {
97 "workflow_function": self.attach_profile_to_cluster,
garciadeblas96b94f52024-07-08 16:18:21 +020098 },
99 "detach_profile_from_cluster": {
100 "workflow_function": self.detach_profile_from_cluster,
garciadeblas96b94f52024-07-08 16:18:21 +0200101 },
102 "create_oka": {
103 "workflow_function": self.create_oka,
garciadeblasb23d2dc2025-02-21 10:15:49 +0100104 "clean_function": self.clean_items_oka_create,
garciadeblas96b94f52024-07-08 16:18:21 +0200105 },
106 "update_oka": {
107 "workflow_function": self.update_oka,
garciadeblasb23d2dc2025-02-21 10:15:49 +0100108 "clean_function": self.clean_items_oka_update,
garciadeblas96b94f52024-07-08 16:18:21 +0200109 },
110 "delete_oka": {
111 "workflow_function": self.delete_oka,
garciadeblasb23d2dc2025-02-21 10:15:49 +0100112 "clean_function": self.clean_items_oka_delete,
garciadeblas96b94f52024-07-08 16:18:21 +0200113 },
114 "create_ksus": {
115 "workflow_function": self.create_ksus,
garciadeblasd8429852024-10-17 15:30:30 +0200116 "clean_function": self.clean_items_ksu_create,
garciadeblas96b94f52024-07-08 16:18:21 +0200117 },
118 "update_ksus": {
119 "workflow_function": self.update_ksus,
garciadeblasd8429852024-10-17 15:30:30 +0200120 "clean_function": self.clean_items_ksu_update,
garciadeblas96b94f52024-07-08 16:18:21 +0200121 },
122 "delete_ksus": {
123 "workflow_function": self.delete_ksus,
garciadeblas96b94f52024-07-08 16:18:21 +0200124 },
125 "clone_ksu": {
126 "workflow_function": self.clone_ksu,
garciadeblas96b94f52024-07-08 16:18:21 +0200127 },
128 "move_ksu": {
129 "workflow_function": self.move_ksu,
garciadeblas96b94f52024-07-08 16:18:21 +0200130 },
garciadeblas61a4c692025-07-17 13:04:13 +0200131 "create_app": {
132 "workflow_function": self.create_app,
133 "clean_function": self.clean_items_app_launch,
134 },
135 "update_app": {
136 "workflow_function": self.update_app,
137 "clean_function": self.clean_items_app_launch,
138 },
139 "delete_app": {
140 "workflow_function": self.delete_app,
141 "clean_function": self.clean_items_app_launch,
142 },
garciadeblas96b94f52024-07-08 16:18:21 +0200143 "create_cloud_credentials": {
144 "workflow_function": self.create_cloud_credentials,
garciadeblas28bff0f2024-09-16 12:53:07 +0200145 "clean_function": self.clean_items_cloud_credentials_create,
garciadeblas96b94f52024-07-08 16:18:21 +0200146 },
147 "update_cloud_credentials": {
148 "workflow_function": self.update_cloud_credentials,
garciadeblas28bff0f2024-09-16 12:53:07 +0200149 "clean_function": self.clean_items_cloud_credentials_update,
garciadeblas96b94f52024-07-08 16:18:21 +0200150 },
151 "delete_cloud_credentials": {
152 "workflow_function": self.delete_cloud_credentials,
garciadeblas96b94f52024-07-08 16:18:21 +0200153 },
154 "dummy_operation": {
155 "workflow_function": self.dummy_operation,
garciadeblas96b94f52024-07-08 16:18:21 +0200156 },
yshah83a30572025-06-13 08:38:49 +0000157 "add_nodegroup": {
158 "workflow_function": self.add_nodegroup,
159 "clean_function": self.clean_items_nodegroup_add,
160 },
161 "scale_nodegroup": {
162 "workflow_function": self.scale_nodegroup,
163 },
164 "delete_nodegroup": {
165 "workflow_function": self.delete_nodegroup,
166 "clean_function": self.clean_items_nodegroup_delete,
167 },
garciadeblas96b94f52024-07-08 16:18:21 +0200168 }
169
rshri932105f2024-07-05 15:11:55 +0000170 super().__init__(msg, self.logger)
171
garciadeblas96b94f52024-07-08 16:18:21 +0200172 @property
173 def kubeconfig(self):
174 return self._kubeconfig
175
176 # Imported methods
garciadeblasc8d217d2025-05-26 15:14:47 +0200177 create_cloud_credentials = odu_vim_mgmt.create_cloud_credentials
178 update_cloud_credentials = odu_vim_mgmt.update_cloud_credentials
179 delete_cloud_credentials = odu_vim_mgmt.delete_cloud_credentials
180 clean_items_cloud_credentials_create = (
181 odu_vim_mgmt.clean_items_cloud_credentials_create
garciadeblas96b94f52024-07-08 16:18:21 +0200182 )
garciadeblasc8d217d2025-05-26 15:14:47 +0200183 clean_items_cloud_credentials_update = (
184 odu_vim_mgmt.clean_items_cloud_credentials_update
garciadeblas96b94f52024-07-08 16:18:21 +0200185 )
garciadeblasc8d217d2025-05-26 15:14:47 +0200186 create_cluster = odu_cluster_mgmt.create_cluster
187 update_cluster = odu_cluster_mgmt.update_cluster
188 delete_cluster = odu_cluster_mgmt.delete_cluster
189 register_cluster = odu_cluster_mgmt.register_cluster
190 deregister_cluster = odu_cluster_mgmt.deregister_cluster
191 clean_items_cluster_create = odu_cluster_mgmt.clean_items_cluster_create
192 clean_items_cluster_update = odu_cluster_mgmt.clean_items_cluster_update
193 clean_items_cluster_register = odu_cluster_mgmt.clean_items_cluster_register
194 clean_items_cluster_deregister = odu_cluster_mgmt.clean_items_cluster_deregister
195 get_cluster_credentials = odu_cluster_mgmt.get_cluster_credentials
yshah83a30572025-06-13 08:38:49 +0000196 add_nodegroup = odu_nodegroup.add_nodegroup
197 scale_nodegroup = odu_nodegroup.scale_nodegroup
198 delete_nodegroup = odu_nodegroup.delete_nodegroup
199 clean_items_nodegroup_add = odu_nodegroup.clean_items_nodegroup_add
200 clean_items_nodegroup_delete = odu_nodegroup.clean_items_nodegroup_delete
garciadeblasc8d217d2025-05-26 15:14:47 +0200201 create_ksus = odu_ksu.create_ksus
202 update_ksus = odu_ksu.update_ksus
203 delete_ksus = odu_ksu.delete_ksus
204 clone_ksu = odu_ksu.clone_ksu
205 move_ksu = odu_ksu.move_ksu
206 clean_items_ksu_create = odu_ksu.clean_items_ksu_create
207 clean_items_ksu_update = odu_ksu.clean_items_ksu_update
208 clean_items_ksu_delete = odu_ksu.clean_items_ksu_delete
209 create_oka = odu_oka.create_oka
210 update_oka = odu_oka.update_oka
211 delete_oka = odu_oka.delete_oka
212 clean_items_oka_create = odu_oka.clean_items_oka_create
213 clean_items_oka_update = odu_oka.clean_items_oka_update
214 clean_items_oka_delete = odu_oka.clean_items_oka_delete
215 create_profile = odu_profiles.create_profile
216 delete_profile = odu_profiles.delete_profile
217 attach_profile_to_cluster = odu_profiles.attach_profile_to_cluster
218 detach_profile_from_cluster = odu_profiles.detach_profile_from_cluster
219 check_workflow_status = workflows.check_workflow_status
220 readiness_loop = workflows.readiness_loop
221 render_jinja_template = odu_render.render_jinja_template
222 render_yaml_template = odu_render.render_yaml_template
223 create_secret = odu_common.create_secret
224 delete_secret = odu_common.delete_secret
rshrif8911b92025-06-11 18:19:07 +0000225 create_configmap = odu_common.create_configmap
226 delete_configmap = odu_common.delete_configmap
garciadeblas61a4c692025-07-17 13:04:13 +0200227 create_app = odu_app.create_app
228 update_app = odu_app.update_app
229 delete_app = odu_app.delete_app
230 launch_app = odu_app.launch_app
231 clean_items_app_launch = odu_app.clean_items_app_launch
garciadeblas96b94f52024-07-08 16:18:21 +0200232
233 async def launch_workflow(self, key, op_id, op_params, content):
rshri932105f2024-07-05 15:11:55 +0000234 self.logger.info(
garciadeblas61a4c692025-07-17 13:04:13 +0200235 f"Workflow is getting into launch. Key: {key}. Operation: {op_id}"
rshri932105f2024-07-05 15:11:55 +0000236 )
garciadeblas61a4c692025-07-17 13:04:13 +0200237 # self.logger.debug(f"Operation Params: {op_params}")
238 # self.logger.debug(f"Content: {content}")
garciadeblas96b94f52024-07-08 16:18:21 +0200239 workflow_function = self._workflows[key]["workflow_function"]
240 self.logger.info("workflow function : {}".format(workflow_function))
garciadeblas41859ce2025-02-04 16:08:51 +0100241 try:
garciadeblas61a4c692025-07-17 13:04:13 +0200242 result, workflow_name, workflow_resources = await workflow_function(
243 op_id, op_params, content
244 )
245 return result, workflow_name, workflow_resources
garciadeblas41859ce2025-02-04 16:08:51 +0100246 except Exception as e:
247 self.logger.error(f"Error launching workflow: {e}")
garciadeblas61a4c692025-07-17 13:04:13 +0200248 return False, str(e), None
rshri932105f2024-07-05 15:11:55 +0000249
garciadeblas5359e992024-12-13 11:09:04 +0100250 async def dummy_clean_items(self, op_id, op_params, content):
garciadeblas98f9a3d2024-12-10 13:42:47 +0100251 self.logger.info(
garciadeblas5359e992024-12-13 11:09:04 +0100252 f"dummy_clean_items Enter. Operation {op_id}. Params: {op_params}"
garciadeblas98f9a3d2024-12-10 13:42:47 +0100253 )
garciadeblas5359e992024-12-13 11:09:04 +0100254 self.logger.debug(f"Content: {content}")
garciadeblas98f9a3d2024-12-10 13:42:47 +0100255 return True, "OK"
256
garciadeblas28bff0f2024-09-16 12:53:07 +0200257 async def clean_items_workflow(self, key, op_id, op_params, content):
258 self.logger.info(
259 f"Cleaning items created during workflow launch. Key: {key}. Operation: {op_id}. Params: {op_params}. Content: {content}"
260 )
garciadeblas98f9a3d2024-12-10 13:42:47 +0100261 clean_items_function = self._workflows[key].get(
262 "clean_function", self.dummy_clean_items
263 )
garciadeblas28bff0f2024-09-16 12:53:07 +0200264 self.logger.info("clean items function : {}".format(clean_items_function))
265 return await clean_items_function(op_id, op_params, content)
266
garciadeblas96b94f52024-07-08 16:18:21 +0200267 async def dummy_operation(self, op_id, op_params, content):
268 self.logger.info("Empty operation status Enter")
269 self.logger.info(f"Operation {op_id}. Params: {op_params}. Content: {content}")
garciadeblas61a4c692025-07-17 13:04:13 +0200270 return True, content["workflow_name"], None
rshri932105f2024-07-05 15:11:55 +0000271
garciadeblas28bff0f2024-09-16 12:53:07 +0200272 async def clean_items(self, items):
garciadeblasb23d2dc2025-02-21 10:15:49 +0100273 # Delete pods
274 for pod in items.get("pods", []):
275 name = pod["name"]
276 namespace = pod["namespace"]
277 self.logger.info(f"Deleting pod {name} in namespace {namespace}")
278 self.logger.debug(f"Testing kubectl: {self._kubectl}")
279 self.logger.debug(
280 f"Testing kubectl configuration: {self._kubectl.configuration}"
281 )
282 self.logger.debug(
283 f"Testing kubectl configuration Host: {self._kubectl.configuration.host}"
284 )
285 await self._kubectl.delete_pod(name, namespace)
garciadeblas28bff0f2024-09-16 12:53:07 +0200286 # Delete secrets
287 for secret in items.get("secrets", []):
288 name = secret["name"]
289 namespace = secret["namespace"]
290 self.logger.info(f"Deleting secret {name} in namespace {namespace}")
garciadeblas6d8acf32025-02-06 13:34:37 +0100291 self.logger.debug(f"Testing kubectl: {self._kubectl}")
292 self.logger.debug(
293 f"Testing kubectl configuration: {self._kubectl.configuration}"
294 )
295 self.logger.debug(
296 f"Testing kubectl configuration Host: {self._kubectl.configuration.host}"
297 )
garciadeblas28bff0f2024-09-16 12:53:07 +0200298 self.delete_secret(name, namespace)
299 # Delete pvcs
300 for pvc in items.get("pvcs", []):
301 name = pvc["name"]
302 namespace = pvc["namespace"]
303 self.logger.info(f"Deleting pvc {name} in namespace {namespace}")
garciadeblas6d8acf32025-02-06 13:34:37 +0100304 self.logger.debug(f"Testing kubectl: {self._kubectl}")
305 self.logger.debug(
306 f"Testing kubectl configuration: {self._kubectl.configuration}"
307 )
308 self.logger.debug(
309 f"Testing kubectl configuration Host: {self._kubectl.configuration.host}"
310 )
garciadeblas28bff0f2024-09-16 12:53:07 +0200311 await self._kubectl.delete_pvc(name, namespace)
rshrif8911b92025-06-11 18:19:07 +0000312 # Delete configmaps
313 for configmap in items.get("configmaps", []):
314 name = configmap["name"]
315 namespace = configmap["namespace"]
316 self.logger.info(f"Deleting configmap {name} in namespace {namespace}")
317 self.logger.debug(f"Testing kubectl: {self._kubectl}")
318 self.logger.debug(
319 f"Testing kubectl configuration: {self._kubectl.configuration}"
320 )
321 self.logger.debug(
322 f"Testing kubectl configuration Host: {self._kubectl.configuration.host}"
323 )
324 self.delete_configmap(name, namespace)
325
326 async def list_object(self, api_group, api_plural, api_version):
327 self.logger.info(
328 f"Api group: {api_group} Api plural: {api_plural} Api version: {api_version}"
329 )
330 generic_object = await self._kubectl.list_generic_object(
331 api_group=api_group,
332 api_plural=api_plural,
333 api_version=api_version,
334 namespace="",
335 )
336 return generic_object