blob: 93ba14b6464e66002d2f3271f7a724b85a74da5d [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,
garciadeblasf6dc6042026-02-04 17:40:30 +010088 },
89 "purge_cluster": {
90 "workflow_function": self.purge_cluster,
91 "clean_function": self.clean_items_cluster_purge,
garciadeblas96b94f52024-07-08 16:18:21 +020092 },
93 "create_profile": {
94 "workflow_function": self.create_profile,
garciadeblas96b94f52024-07-08 16:18:21 +020095 },
96 "delete_profile": {
97 "workflow_function": self.delete_profile,
garciadeblas96b94f52024-07-08 16:18:21 +020098 },
99 "attach_profile_to_cluster": {
100 "workflow_function": self.attach_profile_to_cluster,
garciadeblas96b94f52024-07-08 16:18:21 +0200101 },
102 "detach_profile_from_cluster": {
103 "workflow_function": self.detach_profile_from_cluster,
garciadeblas96b94f52024-07-08 16:18:21 +0200104 },
105 "create_oka": {
106 "workflow_function": self.create_oka,
garciadeblasb23d2dc2025-02-21 10:15:49 +0100107 "clean_function": self.clean_items_oka_create,
garciadeblas96b94f52024-07-08 16:18:21 +0200108 },
109 "update_oka": {
110 "workflow_function": self.update_oka,
garciadeblasb23d2dc2025-02-21 10:15:49 +0100111 "clean_function": self.clean_items_oka_update,
garciadeblas96b94f52024-07-08 16:18:21 +0200112 },
113 "delete_oka": {
114 "workflow_function": self.delete_oka,
garciadeblasb23d2dc2025-02-21 10:15:49 +0100115 "clean_function": self.clean_items_oka_delete,
garciadeblas96b94f52024-07-08 16:18:21 +0200116 },
117 "create_ksus": {
118 "workflow_function": self.create_ksus,
garciadeblasd8429852024-10-17 15:30:30 +0200119 "clean_function": self.clean_items_ksu_create,
garciadeblas96b94f52024-07-08 16:18:21 +0200120 },
121 "update_ksus": {
122 "workflow_function": self.update_ksus,
garciadeblasd8429852024-10-17 15:30:30 +0200123 "clean_function": self.clean_items_ksu_update,
garciadeblas96b94f52024-07-08 16:18:21 +0200124 },
125 "delete_ksus": {
126 "workflow_function": self.delete_ksus,
garciadeblas96b94f52024-07-08 16:18:21 +0200127 },
128 "clone_ksu": {
129 "workflow_function": self.clone_ksu,
garciadeblas96b94f52024-07-08 16:18:21 +0200130 },
131 "move_ksu": {
132 "workflow_function": self.move_ksu,
garciadeblas96b94f52024-07-08 16:18:21 +0200133 },
garciadeblas61a4c692025-07-17 13:04:13 +0200134 "create_app": {
135 "workflow_function": self.create_app,
136 "clean_function": self.clean_items_app_launch,
137 },
138 "update_app": {
139 "workflow_function": self.update_app,
140 "clean_function": self.clean_items_app_launch,
141 },
142 "delete_app": {
143 "workflow_function": self.delete_app,
144 "clean_function": self.clean_items_app_launch,
145 },
garciadeblas96b94f52024-07-08 16:18:21 +0200146 "create_cloud_credentials": {
147 "workflow_function": self.create_cloud_credentials,
garciadeblas28bff0f2024-09-16 12:53:07 +0200148 "clean_function": self.clean_items_cloud_credentials_create,
garciadeblas96b94f52024-07-08 16:18:21 +0200149 },
150 "update_cloud_credentials": {
151 "workflow_function": self.update_cloud_credentials,
garciadeblas28bff0f2024-09-16 12:53:07 +0200152 "clean_function": self.clean_items_cloud_credentials_update,
garciadeblas96b94f52024-07-08 16:18:21 +0200153 },
154 "delete_cloud_credentials": {
155 "workflow_function": self.delete_cloud_credentials,
garciadeblas96b94f52024-07-08 16:18:21 +0200156 },
157 "dummy_operation": {
158 "workflow_function": self.dummy_operation,
garciadeblas96b94f52024-07-08 16:18:21 +0200159 },
yshah83a30572025-06-13 08:38:49 +0000160 "add_nodegroup": {
161 "workflow_function": self.add_nodegroup,
162 "clean_function": self.clean_items_nodegroup_add,
163 },
164 "scale_nodegroup": {
165 "workflow_function": self.scale_nodegroup,
166 },
167 "delete_nodegroup": {
168 "workflow_function": self.delete_nodegroup,
169 "clean_function": self.clean_items_nodegroup_delete,
170 },
garciadeblas96b94f52024-07-08 16:18:21 +0200171 }
172
rshri932105f2024-07-05 15:11:55 +0000173 super().__init__(msg, self.logger)
174
garciadeblas96b94f52024-07-08 16:18:21 +0200175 @property
176 def kubeconfig(self):
177 return self._kubeconfig
178
179 # Imported methods
garciadeblasc8d217d2025-05-26 15:14:47 +0200180 create_cloud_credentials = odu_vim_mgmt.create_cloud_credentials
181 update_cloud_credentials = odu_vim_mgmt.update_cloud_credentials
182 delete_cloud_credentials = odu_vim_mgmt.delete_cloud_credentials
183 clean_items_cloud_credentials_create = (
184 odu_vim_mgmt.clean_items_cloud_credentials_create
garciadeblas96b94f52024-07-08 16:18:21 +0200185 )
garciadeblasc8d217d2025-05-26 15:14:47 +0200186 clean_items_cloud_credentials_update = (
187 odu_vim_mgmt.clean_items_cloud_credentials_update
garciadeblas96b94f52024-07-08 16:18:21 +0200188 )
garciadeblasc8d217d2025-05-26 15:14:47 +0200189 create_cluster = odu_cluster_mgmt.create_cluster
190 update_cluster = odu_cluster_mgmt.update_cluster
191 delete_cluster = odu_cluster_mgmt.delete_cluster
192 register_cluster = odu_cluster_mgmt.register_cluster
193 deregister_cluster = odu_cluster_mgmt.deregister_cluster
garciadeblasf6dc6042026-02-04 17:40:30 +0100194 purge_cluster = odu_cluster_mgmt.purge_cluster
garciadeblasc8d217d2025-05-26 15:14:47 +0200195 clean_items_cluster_create = odu_cluster_mgmt.clean_items_cluster_create
196 clean_items_cluster_update = odu_cluster_mgmt.clean_items_cluster_update
197 clean_items_cluster_register = odu_cluster_mgmt.clean_items_cluster_register
garciadeblasf6dc6042026-02-04 17:40:30 +0100198 clean_items_cluster_purge = odu_cluster_mgmt.clean_items_cluster_purge
garciadeblasc8d217d2025-05-26 15:14:47 +0200199 get_cluster_credentials = odu_cluster_mgmt.get_cluster_credentials
yshah83a30572025-06-13 08:38:49 +0000200 add_nodegroup = odu_nodegroup.add_nodegroup
201 scale_nodegroup = odu_nodegroup.scale_nodegroup
202 delete_nodegroup = odu_nodegroup.delete_nodegroup
203 clean_items_nodegroup_add = odu_nodegroup.clean_items_nodegroup_add
204 clean_items_nodegroup_delete = odu_nodegroup.clean_items_nodegroup_delete
garciadeblasc8d217d2025-05-26 15:14:47 +0200205 create_ksus = odu_ksu.create_ksus
206 update_ksus = odu_ksu.update_ksus
207 delete_ksus = odu_ksu.delete_ksus
208 clone_ksu = odu_ksu.clone_ksu
209 move_ksu = odu_ksu.move_ksu
210 clean_items_ksu_create = odu_ksu.clean_items_ksu_create
211 clean_items_ksu_update = odu_ksu.clean_items_ksu_update
212 clean_items_ksu_delete = odu_ksu.clean_items_ksu_delete
213 create_oka = odu_oka.create_oka
214 update_oka = odu_oka.update_oka
215 delete_oka = odu_oka.delete_oka
216 clean_items_oka_create = odu_oka.clean_items_oka_create
217 clean_items_oka_update = odu_oka.clean_items_oka_update
218 clean_items_oka_delete = odu_oka.clean_items_oka_delete
219 create_profile = odu_profiles.create_profile
220 delete_profile = odu_profiles.delete_profile
221 attach_profile_to_cluster = odu_profiles.attach_profile_to_cluster
222 detach_profile_from_cluster = odu_profiles.detach_profile_from_cluster
223 check_workflow_status = workflows.check_workflow_status
224 readiness_loop = workflows.readiness_loop
225 render_jinja_template = odu_render.render_jinja_template
226 render_yaml_template = odu_render.render_yaml_template
227 create_secret = odu_common.create_secret
228 delete_secret = odu_common.delete_secret
rshrif8911b92025-06-11 18:19:07 +0000229 create_configmap = odu_common.create_configmap
230 delete_configmap = odu_common.delete_configmap
garciadeblas61a4c692025-07-17 13:04:13 +0200231 create_app = odu_app.create_app
232 update_app = odu_app.update_app
233 delete_app = odu_app.delete_app
234 launch_app = odu_app.launch_app
235 clean_items_app_launch = odu_app.clean_items_app_launch
garciadeblas96b94f52024-07-08 16:18:21 +0200236
237 async def launch_workflow(self, key, op_id, op_params, content):
rshri932105f2024-07-05 15:11:55 +0000238 self.logger.info(
garciadeblas61a4c692025-07-17 13:04:13 +0200239 f"Workflow is getting into launch. Key: {key}. Operation: {op_id}"
rshri932105f2024-07-05 15:11:55 +0000240 )
garciadeblas61a4c692025-07-17 13:04:13 +0200241 # self.logger.debug(f"Operation Params: {op_params}")
242 # self.logger.debug(f"Content: {content}")
garciadeblas96b94f52024-07-08 16:18:21 +0200243 workflow_function = self._workflows[key]["workflow_function"]
244 self.logger.info("workflow function : {}".format(workflow_function))
garciadeblas41859ce2025-02-04 16:08:51 +0100245 try:
garciadeblas61a4c692025-07-17 13:04:13 +0200246 result, workflow_name, workflow_resources = await workflow_function(
247 op_id, op_params, content
248 )
249 return result, workflow_name, workflow_resources
garciadeblas41859ce2025-02-04 16:08:51 +0100250 except Exception as e:
251 self.logger.error(f"Error launching workflow: {e}")
garciadeblas61a4c692025-07-17 13:04:13 +0200252 return False, str(e), None
rshri932105f2024-07-05 15:11:55 +0000253
garciadeblas5359e992024-12-13 11:09:04 +0100254 async def dummy_clean_items(self, op_id, op_params, content):
garciadeblas98f9a3d2024-12-10 13:42:47 +0100255 self.logger.info(
garciadeblas5359e992024-12-13 11:09:04 +0100256 f"dummy_clean_items Enter. Operation {op_id}. Params: {op_params}"
garciadeblas98f9a3d2024-12-10 13:42:47 +0100257 )
garciadeblas5359e992024-12-13 11:09:04 +0100258 self.logger.debug(f"Content: {content}")
garciadeblas98f9a3d2024-12-10 13:42:47 +0100259 return True, "OK"
260
garciadeblas28bff0f2024-09-16 12:53:07 +0200261 async def clean_items_workflow(self, key, op_id, op_params, content):
262 self.logger.info(
263 f"Cleaning items created during workflow launch. Key: {key}. Operation: {op_id}. Params: {op_params}. Content: {content}"
264 )
garciadeblas98f9a3d2024-12-10 13:42:47 +0100265 clean_items_function = self._workflows[key].get(
266 "clean_function", self.dummy_clean_items
267 )
garciadeblas28bff0f2024-09-16 12:53:07 +0200268 self.logger.info("clean items function : {}".format(clean_items_function))
269 return await clean_items_function(op_id, op_params, content)
270
garciadeblas96b94f52024-07-08 16:18:21 +0200271 async def dummy_operation(self, op_id, op_params, content):
272 self.logger.info("Empty operation status Enter")
273 self.logger.info(f"Operation {op_id}. Params: {op_params}. Content: {content}")
garciadeblas61a4c692025-07-17 13:04:13 +0200274 return True, content["workflow_name"], None
rshri932105f2024-07-05 15:11:55 +0000275
garciadeblas28bff0f2024-09-16 12:53:07 +0200276 async def clean_items(self, items):
garciadeblasb23d2dc2025-02-21 10:15:49 +0100277 # Delete pods
278 for pod in items.get("pods", []):
279 name = pod["name"]
280 namespace = pod["namespace"]
281 self.logger.info(f"Deleting pod {name} in namespace {namespace}")
282 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 )
289 await self._kubectl.delete_pod(name, namespace)
garciadeblas28bff0f2024-09-16 12:53:07 +0200290 # Delete secrets
291 for secret in items.get("secrets", []):
292 name = secret["name"]
293 namespace = secret["namespace"]
294 self.logger.info(f"Deleting secret {name} in namespace {namespace}")
garciadeblas6d8acf32025-02-06 13:34:37 +0100295 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 )
garciadeblas28bff0f2024-09-16 12:53:07 +0200302 self.delete_secret(name, namespace)
303 # Delete pvcs
304 for pvc in items.get("pvcs", []):
305 name = pvc["name"]
306 namespace = pvc["namespace"]
307 self.logger.info(f"Deleting pvc {name} in namespace {namespace}")
garciadeblas6d8acf32025-02-06 13:34:37 +0100308 self.logger.debug(f"Testing kubectl: {self._kubectl}")
309 self.logger.debug(
310 f"Testing kubectl configuration: {self._kubectl.configuration}"
311 )
312 self.logger.debug(
313 f"Testing kubectl configuration Host: {self._kubectl.configuration.host}"
314 )
garciadeblas28bff0f2024-09-16 12:53:07 +0200315 await self._kubectl.delete_pvc(name, namespace)
rshrif8911b92025-06-11 18:19:07 +0000316 # Delete configmaps
317 for configmap in items.get("configmaps", []):
318 name = configmap["name"]
319 namespace = configmap["namespace"]
320 self.logger.info(f"Deleting configmap {name} in namespace {namespace}")
321 self.logger.debug(f"Testing kubectl: {self._kubectl}")
322 self.logger.debug(
323 f"Testing kubectl configuration: {self._kubectl.configuration}"
324 )
325 self.logger.debug(
326 f"Testing kubectl configuration Host: {self._kubectl.configuration.host}"
327 )
328 self.delete_configmap(name, namespace)
329
330 async def list_object(self, api_group, api_plural, api_version):
331 self.logger.info(
332 f"Api group: {api_group} Api plural: {api_plural} Api version: {api_version}"
333 )
334 generic_object = await self._kubectl.list_generic_object(
335 api_group=api_group,
336 api_plural=api_plural,
337 api_version=api_version,
338 namespace="",
339 )
340 return generic_object