2 # Copyright 2020 Telefonica Investigacion y Desarrollo, S.A.U.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
25 from grpclib
.client
import Channel
27 from osm_lcm
.data_utils
.lcm_config
import VcaConfig
28 from osm_lcm
.frontend_pb2
import PrimitiveRequest
29 from osm_lcm
.frontend_pb2
import SshKeyRequest
, SshKeyReply
30 from osm_lcm
.frontend_grpc
import FrontendExecutorStub
31 from osm_lcm
.lcm_utils
import LcmBase
, get_ee_id_parts
33 from osm_lcm
.data_utils
.database
.database
import Database
34 from osm_lcm
.data_utils
.filesystem
.filesystem
import Filesystem
36 from n2vc
.n2vc_conn
import N2VCConnector
37 from n2vc
.k8s_helm3_conn
import K8sHelm3Connector
38 from n2vc
.exceptions
import (
39 N2VCBadArgumentsException
,
41 N2VCExecutionException
,
44 from osm_lcm
.lcm_utils
import deep_get
47 def retryer(max_wait_time_var
="_initial_retry_time", delay_time_var
="_retry_delay"):
49 retry_exceptions
= (ConnectionRefusedError
, TimeoutError
)
51 @functools.wraps(func
)
52 async def wrapped(*args
, **kwargs
):
53 # default values for wait time and delay_time
57 # obtain arguments from variable names
59 if self
.__dict
__.get(max_wait_time_var
):
60 max_wait_time
= self
.__dict
__.get(max_wait_time_var
)
61 if self
.__dict
__.get(delay_time_var
):
62 delay_time
= self
.__dict
__.get(delay_time_var
)
64 wait_time
= max_wait_time
67 return await func(*args
, **kwargs
)
68 except retry_exceptions
:
69 wait_time
= wait_time
- delay_time
70 await asyncio
.sleep(delay_time
)
73 return ConnectionRefusedError
80 def create_secure_context(
81 trusted
: str, client_cert_path
: str, client_key_path
: str
83 ctx
= ssl
.SSLContext(ssl
.PROTOCOL_TLS_CLIENT
)
84 ctx
.verify_mode
= ssl
.CERT_REQUIRED
85 ctx
.check_hostname
= True
86 ctx
.minimum_version
= ssl
.TLSVersion
.TLSv1_2
87 ctx
.load_cert_chain(client_cert_path
, client_key_path
)
88 ctx
.load_verify_locations(trusted
)
89 ctx
.set_ciphers("ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20")
90 ctx
.set_alpn_protocols(["h2"])
94 class LCMHelmConn(N2VCConnector
, LcmBase
):
98 vca_config
: VcaConfig
= None,
102 Initialize EE helm connector.
105 self
.db
= Database().instance
.db
106 self
.fs
= Filesystem().instance
.fs
108 # parent class constructor
109 N2VCConnector
.__init
__(
110 self
, log
=log
, on_update_db
=on_update_db
, db
=self
.db
, fs
=self
.fs
113 self
.vca_config
= vca_config
114 self
.log
.debug("Initialize helm N2VC connector")
115 self
.log
.debug("initial vca_config: {}".format(vca_config
.to_dict()))
117 self
._retry
_delay
= self
.vca_config
.helm_ee_retry_delay
119 self
._initial
_retry
_time
= self
.vca_config
.helm_max_initial_retry_time
120 self
.log
.debug("Initial retry time: {}".format(self
._initial
_retry
_time
))
122 self
._max
_retry
_time
= self
.vca_config
.helm_max_retry_time
123 self
.log
.debug("Retry time: {}".format(self
._max
_retry
_time
))
125 # initialize helm connector for helmv3
126 self
._k
8sclusterhelm
3 = K8sHelm3Connector(
127 kubectl_command
=self
.vca_config
.kubectlpath
,
128 helm_command
=self
.vca_config
.helm3path
,
135 self
._system
_cluster
_id
= None
136 self
.log
.info("Helm N2VC connector initialized")
138 # TODO - ¿reuse_ee_id?
139 async def create_execution_environment(
143 reuse_ee_id
: str = None,
144 progress_timeout
: float = None,
145 total_timeout
: float = None,
147 artifact_path
: str = None,
148 chart_model
: str = None,
149 vca_type
: str = None,
154 Creates a new helm execution environment deploying the helm-chat indicated in the
156 :param str namespace: This param is not used, all helm charts are deployed in the osm
158 :param dict db_dict: where to write to database when the status changes.
159 It contains a dictionary with {collection: str, filter: {}, path: str},
160 e.g. {collection: "nsrs", filter: {_id: <nsd-id>, path:
161 "_admin.deployed.VCA.3"}
162 :param str reuse_ee_id: ee id from an older execution. TODO - right now this param is not used
163 :param float progress_timeout:
164 :param float total_timeout:
165 :param dict config: General variables to instantiate KDU
166 :param str artifact_path: path of package content
167 :param str chart_model: helm chart/reference (string), which can be either
169 - a name of chart available via the repos known by OSM
170 (e.g. stable/openldap, stable/openldap:1.2.4)
171 - a path to a packaged chart (e.g. mychart.tgz)
172 - a path to an unpacked chart directory or a URL (e.g. mychart)
173 :param str vca_type: Type of vca, must be type helm-v3
174 :returns str, dict: id of the new execution environment including namespace.helm_id
175 and credentials object set to None as all credentials should be osm kubernetes .kubeconfig
179 namespace
= self
.vca_config
.kubectl_osm_namespace
182 "create_execution_environment: namespace: {}, artifact_path: {}, "
183 "chart_model: {}, db_dict: {}, reuse_ee_id: {}".format(
184 namespace
, artifact_path
, db_dict
, chart_model
, reuse_ee_id
188 # Validate artifact-path is provided
189 if artifact_path
is None or len(artifact_path
) == 0:
190 raise N2VCBadArgumentsException(
191 message
="artifact_path is mandatory", bad_args
=["artifact_path"]
194 # Validate artifact-path exists and sync path
195 from_path
= os
.path
.split(artifact_path
)[0]
196 self
.fs
.sync(from_path
)
198 # remove / in charm path
199 while artifact_path
.find("//") >= 0:
200 artifact_path
= artifact_path
.replace("//", "/")
203 if self
.fs
.file_exists(artifact_path
):
204 helm_chart_path
= artifact_path
206 msg
= "artifact path does not exist: {}".format(artifact_path
)
207 raise N2VCBadArgumentsException(message
=msg
, bad_args
=["artifact_path"])
209 if artifact_path
.startswith("/"):
210 full_path
= self
.fs
.path
+ helm_chart_path
212 full_path
= self
.fs
.path
+ "/" + helm_chart_path
214 while full_path
.find("//") >= 0:
215 full_path
= full_path
.replace("//", "/")
217 # By default, the KDU is expected to be a file
218 kdu_model
= full_path
219 # If the chart_model includes a "/", then it is a reference:
220 # e.g. (stable/openldap; stable/openldap:1.2.4)
221 if chart_model
.find("/") >= 0:
222 kdu_model
= chart_model
225 # Call helm conn install
226 # Obtain system cluster id from database
227 system_cluster_uuid
= await self
._get
_system
_cluster
_id
()
228 # Add parameter osm if exist to global
229 if config
and config
.get("osm"):
230 if not config
.get("global"):
231 config
["global"] = {}
232 config
["global"]["osm"] = config
.get("osm")
234 self
.log
.debug("install helm chart: {}".format(full_path
))
235 helm_id
= self
._k
8sclusterhelm
3.generate_kdu_instance_name(
239 await self
._k
8sclusterhelm
3.install(
242 kdu_instance
=helm_id
,
246 timeout
=progress_timeout
,
249 ee_id
= "{}:{}.{}".format(vca_type
, namespace
, helm_id
)
251 except N2VCException
:
253 except Exception as e
:
254 self
.log
.error("Error deploying chart ee: {}".format(e
), exc_info
=True)
255 raise N2VCException("Error deploying chart ee: {}".format(e
))
257 async def upgrade_execution_environment(
262 progress_timeout
: float = None,
263 total_timeout
: float = None,
265 artifact_path
: str = None,
266 vca_type
: str = None,
271 Creates a new helm execution environment deploying the helm-chat indicated in the
273 :param str namespace: This param is not used, all helm charts are deployed in the osm
275 :param dict db_dict: where to write to database when the status changes.
276 It contains a dictionary with {collection: str, filter: {}, path: str},
277 e.g. {collection: "nsrs", filter: {_id: <nsd-id>, path:
278 "_admin.deployed.VCA.3"}
279 :param helm_id: unique name of the Helm release to upgrade
280 :param float progress_timeout:
281 :param float total_timeout:
282 :param dict config: General variables to instantiate KDU
283 :param str artifact_path: path of package content
284 :param str vca_type: Type of vca, must be type helm-v3
285 :returns str, dict: id of the new execution environment including namespace.helm_id
286 and credentials object set to None as all credentials should be osm kubernetes .kubeconfig
290 "upgrade_execution_environment: namespace: {}, artifact_path: {}, db_dict: {}, "
293 # Validate helm_id is provided
294 if helm_id
is None or len(helm_id
) == 0:
295 raise N2VCBadArgumentsException(
296 message
="helm_id is mandatory", bad_args
=["helm_id"]
299 # Validate artifact-path is provided
300 if artifact_path
is None or len(artifact_path
) == 0:
301 raise N2VCBadArgumentsException(
302 message
="artifact_path is mandatory", bad_args
=["artifact_path"]
305 # Validate artifact-path exists and sync path
306 from_path
= os
.path
.split(artifact_path
)[0]
307 self
.fs
.sync(from_path
)
309 # remove / in charm path
310 while artifact_path
.find("//") >= 0:
311 artifact_path
= artifact_path
.replace("//", "/")
314 if self
.fs
.file_exists(artifact_path
):
315 helm_chart_path
= artifact_path
317 msg
= "artifact path does not exist: {}".format(artifact_path
)
318 raise N2VCBadArgumentsException(message
=msg
, bad_args
=["artifact_path"])
320 if artifact_path
.startswith("/"):
321 full_path
= self
.fs
.path
+ helm_chart_path
323 full_path
= self
.fs
.path
+ "/" + helm_chart_path
325 while full_path
.find("//") >= 0:
326 full_path
= full_path
.replace("//", "/")
329 # Call helm conn upgrade
330 # Obtain system cluster id from database
331 system_cluster_uuid
= await self
._get
_system
_cluster
_id
()
332 # Add parameter osm if exist to global
333 if config
and config
.get("osm"):
334 if not config
.get("global"):
335 config
["global"] = {}
336 config
["global"]["osm"] = config
.get("osm")
338 self
.log
.debug("Ugrade helm chart: {}".format(full_path
))
339 await self
._k
8sclusterhelm
3.upgrade(
342 kdu_instance
=helm_id
,
346 timeout
=progress_timeout
,
350 except N2VCException
:
352 except Exception as e
:
353 self
.log
.error("Error upgrading chart ee: {}".format(e
), exc_info
=True)
354 raise N2VCException("Error upgrading chart ee: {}".format(e
))
356 async def create_tls_certificate(
362 namespace
: str = None,
364 # Obtain system cluster id from database
365 system_cluster_uuid
= await self
._get
_system
_cluster
_id
()
366 # use helm-v3 as certificates don't depend on helm version
367 await self
._k
8sclusterhelm
3.create_certificate(
368 cluster_uuid
=system_cluster_uuid
,
369 namespace
=namespace
or self
.vca_config
.kubectl_osm_namespace
,
370 dns_prefix
=dns_prefix
,
372 secret_name
=secret_name
,
376 async def delete_tls_certificate(
378 certificate_name
: str = None,
379 namespace
: str = None,
381 # Obtain system cluster id from database
382 system_cluster_uuid
= await self
._get
_system
_cluster
_id
()
383 await self
._k
8sclusterhelm
3.delete_certificate(
384 cluster_uuid
=system_cluster_uuid
,
385 namespace
=namespace
or self
.vca_config
.kubectl_osm_namespace
,
386 certificate_name
=certificate_name
,
389 async def setup_ns_namespace(
393 # Obtain system cluster id from database
394 system_cluster_uuid
= await self
._get
_system
_cluster
_id
()
395 await self
._k
8sclusterhelm
3.create_namespace(
397 cluster_uuid
=system_cluster_uuid
,
399 "pod-security.kubernetes.io/enforce": self
.vca_config
.eegrpc_pod_admission_policy
402 await self
._k
8sclusterhelm
3.setup_default_rbac(
406 resources
=["secrets"],
408 service_account
="default",
409 cluster_uuid
=system_cluster_uuid
,
411 await self
._k
8sclusterhelm
3.copy_secret_data(
414 src_namespace
=self
.vca_config
.kubectl_osm_namespace
,
416 cluster_uuid
=system_cluster_uuid
,
420 async def register_execution_environment(
425 progress_timeout
: float = None,
426 total_timeout
: float = None,
433 async def install_configuration_sw(self
, *args
, **kwargs
):
437 async def add_relation(self
, *args
, **kwargs
):
441 async def remove_relation(self
):
445 async def get_status(self
, *args
, **kwargs
):
446 # not used for this connector
449 async def get_ee_ssh_public__key(
453 progress_timeout
: float = None,
454 total_timeout
: float = None,
458 Obtains ssh-public key from ee executing GetSShKey method from the ee.
460 :param str ee_id: the id of the execution environment returned by
461 create_execution_environment or register_execution_environment
463 :param float progress_timeout:
464 :param float total_timeout:
465 :returns: public key of the execution environment
469 "get_ee_ssh_public_key: ee_id: {}, db_dict: {}".format(ee_id
, db_dict
)
473 if ee_id
is None or len(ee_id
) == 0:
474 raise N2VCBadArgumentsException(
475 message
="ee_id is mandatory", bad_args
=["ee_id"]
479 # Obtain ip_addr for the ee service, it is resolved by dns from the ee name by kubernetes
480 version
, namespace
, helm_id
= get_ee_id_parts(ee_id
)
481 ip_addr
= "{}.{}.svc".format(helm_id
, namespace
)
482 # Obtain ssh_key from the ee, this method will implement retries to allow the ee
483 # install libraries and start successfully
484 ssh_key
= await self
._get
_ssh
_key
(ip_addr
)
486 except Exception as e
:
487 self
.log
.error("Error obtaining ee ssh_key: {}".format(e
), exc_info
=True)
488 raise N2VCException("Error obtaining ee ssh_ke: {}".format(e
))
490 async def upgrade_charm(
494 charm_id
: str = None,
495 charm_type
: str = None,
496 timeout
: float = None,
498 """This method upgrade charms in VNFs
500 This method does not support KDU's deployed with Helm.
503 ee_id: Execution environment id
504 path: Local path to the charm
506 charm_type: Charm type can be lxc-proxy-charm, native-charm or k8s-proxy-charm
507 timeout: (Float) Timeout for the ns update operation
510 the output of the update operation if status equals to "completed"
513 raise N2VCException("KDUs deployed with Helm do not support charm upgrade")
515 async def exec_primitive(
520 db_dict
: dict = None,
521 progress_timeout
: float = None,
522 total_timeout
: float = None,
526 Execute a primitive in the execution environment
528 :param str ee_id: the one returned by create_execution_environment or
529 register_execution_environment with the format namespace.helm_id
530 :param str primitive_name: must be one defined in the software. There is one
531 called 'config', where, for the proxy case, the 'credentials' of VM are
533 :param dict params_dict: parameters of the action
534 :param dict db_dict: where to write into database when the status changes.
535 It contains a dict with
536 {collection: <str>, filter: {}, path: <str>},
537 e.g. {collection: "nslcmops", filter:
538 {_id: <nslcmop_id>, path: "_admin.VCA"}
539 It will be used to store information about intermediate notifications
540 :param float progress_timeout:
541 :param float total_timeout:
542 :returns str: primitive result, if ok. It raises exceptions in case of fail
546 "exec primitive for ee_id : {}, primitive_name: {}, params_dict: {}, db_dict: {}".format(
547 ee_id
, primitive_name
, params_dict
, db_dict
552 if ee_id
is None or len(ee_id
) == 0:
553 raise N2VCBadArgumentsException(
554 message
="ee_id is mandatory", bad_args
=["ee_id"]
556 if primitive_name
is None or len(primitive_name
) == 0:
557 raise N2VCBadArgumentsException(
558 message
="action_name is mandatory", bad_args
=["action_name"]
560 if params_dict
is None:
564 version
, namespace
, helm_id
= get_ee_id_parts(ee_id
)
565 ip_addr
= "{}.{}.svc".format(helm_id
, namespace
)
566 except Exception as e
:
567 self
.log
.error("Error getting ee ip ee: {}".format(e
))
568 raise N2VCException("Error getting ee ip ee: {}".format(e
))
570 if primitive_name
== "config":
572 # Execute config primitive, higher timeout to check the case ee is starting
573 status
, detailed_message
= await self
._execute
_config
_primitive
(
574 ip_addr
, params_dict
, db_dict
=db_dict
577 "Executed config primitive ee_id_ {}, status: {}, message: {}".format(
578 ee_id
, status
, detailed_message
583 "Error configuring helm ee, status: {}, message: {}".format(
584 status
, detailed_message
587 raise N2VCExecutionException(
588 message
="Error configuring helm ee_id: {}, status: {}, message: {}: ".format(
589 ee_id
, status
, detailed_message
591 primitive_name
=primitive_name
,
593 except Exception as e
:
594 self
.log
.error("Error configuring helm ee: {}".format(e
))
595 raise N2VCExecutionException(
596 message
="Error configuring helm ee_id: {}, {}".format(ee_id
, e
),
597 primitive_name
=primitive_name
,
603 status
, detailed_message
= await self
._execute
_primitive
(
604 ip_addr
, primitive_name
, params_dict
, db_dict
=db_dict
607 "Executed primitive {} ee_id_ {}, status: {}, message: {}".format(
608 primitive_name
, ee_id
, status
, detailed_message
611 if status
!= "OK" and status
!= "PROCESSING":
613 "Execute primitive {} returned not ok status: {}, message: {}".format(
614 primitive_name
, status
, detailed_message
617 raise N2VCExecutionException(
618 message
="Execute primitive {} returned not ok status: {}, message: {}".format(
619 primitive_name
, status
, detailed_message
621 primitive_name
=primitive_name
,
623 except Exception as e
:
625 "Error executing primitive {}: {}".format(primitive_name
, e
)
627 raise N2VCExecutionException(
628 message
="Error executing primitive {} into ee={} : {}".format(
629 primitive_name
, ee_id
, e
631 primitive_name
=primitive_name
,
633 return detailed_message
635 async def deregister_execution_environments(self
):
639 async def delete_execution_environment(
642 db_dict
: dict = None,
643 total_timeout
: float = None,
647 Delete an execution environment
648 :param str ee_id: id of the execution environment to delete, included namespace.helm_id
649 :param dict db_dict: where to write into database when the status changes.
650 It contains a dict with
651 {collection: <str>, filter: {}, path: <str>},
652 e.g. {collection: "nsrs", filter:
653 {_id: <nsd-id>, path: "_admin.deployed.VCA.3"}
654 :param float total_timeout:
657 self
.log
.info("ee_id: {}".format(ee_id
))
661 raise N2VCBadArgumentsException(
662 message
="ee_id is mandatory", bad_args
=["ee_id"]
666 # Obtain cluster_uuid
667 system_cluster_uuid
= await self
._get
_system
_cluster
_id
()
670 version
, namespace
, helm_id
= get_ee_id_parts(ee_id
)
672 await self
._k
8sclusterhelm
3.uninstall(system_cluster_uuid
, helm_id
)
673 self
.log
.info("ee_id: {} deleted".format(ee_id
))
674 except N2VCException
:
676 except Exception as e
:
678 "Error deleting ee id: {}: {}".format(ee_id
, e
), exc_info
=True
680 raise N2VCException("Error deleting ee id {}: {}".format(ee_id
, e
))
682 async def delete_namespace(
683 self
, namespace
: str, db_dict
: dict = None, total_timeout
: float = None
685 # Obtain system cluster id from database
686 system_cluster_uuid
= await self
._get
_system
_cluster
_id
()
687 await self
._k
8sclusterhelm
3.delete_namespace(
689 cluster_uuid
=system_cluster_uuid
,
692 async def install_k8s_proxy_charm(
698 progress_timeout
: float = None,
699 total_timeout
: float = None,
706 @retryer(max_wait_time_var
="_initial_retry_time", delay_time_var
="_retry_delay")
707 async def _get_ssh_key(self
, ip_addr
):
708 return await self
._execute
_primitive
_internal
(
714 @retryer(max_wait_time_var
="_initial_retry_time", delay_time_var
="_retry_delay")
715 async def _execute_config_primitive(self
, ip_addr
, params
, db_dict
=None):
716 return await self
._execute
_primitive
_internal
(
717 ip_addr
, "config", params
, db_dict
=db_dict
720 @retryer(max_wait_time_var
="_max_retry_time", delay_time_var
="_retry_delay")
721 async def _execute_primitive(self
, ip_addr
, primitive_name
, params
, db_dict
=None):
722 return await self
._execute
_primitive
_internal
(
723 ip_addr
, primitive_name
, params
, db_dict
=db_dict
726 async def _execute_primitive_internal(
727 self
, ip_addr
, primitive_name
, params
, db_dict
=None
730 stub
= FrontendExecutorStub(channel
)
731 if primitive_name
== "_get_ssh_key":
732 self
.log
.debug("get ssh key, ip_addr: {}".format(ip_addr
))
733 reply
: SshKeyReply
= await stub
.GetSshKey(SshKeyRequest())
735 # For any other primitives
736 async with stub
.RunPrimitive
.open() as stream
:
737 primitive_id
= str(uuid
.uuid1())
740 "Execute primitive internal: id:{}, name:{}, params: {}".format(
741 primitive_id
, primitive_name
, params
744 await stream
.send_message(
746 id=primitive_id
, name
=primitive_name
, params
=yaml
.dump(params
)
750 async for reply
in stream
:
751 self
.log
.debug("Received reply: {}".format(reply
))
753 # If db_dict provided write notifs in database
755 self
._write
_op
_detailed
_status
(
756 db_dict
, reply
.status
, reply
.detailed_message
759 return reply
.status
, reply
.detailed_message
761 return "ERROR", "No result received"
763 ssl_context
= create_secure_context(
764 self
.vca_config
.ca_store
,
765 self
.vca_config
.client_cert_path
,
766 self
.vca_config
.client_key_path
,
769 ip_addr
, self
.vca_config
.helm_ee_service_port
, ssl
=ssl_context
772 return await execute()
773 except ssl
.SSLError
as ssl_error
: # fallback to insecure gRPC
775 ssl_error
.reason
== "WRONG_VERSION_NUMBER"
776 and not self
.vca_config
.eegrpc_tls_enforce
779 "Execution environment doesn't support TLS, falling back to unsecure gRPC"
781 channel
= Channel(ip_addr
, self
.vca_config
.helm_ee_service_port
)
782 return await execute()
783 elif ssl_error
.reason
== "WRONG_VERSION_NUMBER":
785 "Execution environment doesn't support TLS, primitives cannot be executed"
792 def _write_op_detailed_status(self
, db_dict
, status
, detailed_message
):
793 # write ee_id to database: _admin.deployed.VCA.x
795 the_table
= db_dict
["collection"]
796 the_filter
= db_dict
["filter"]
797 update_dict
= {"detailed-status": "{}: {}".format(status
, detailed_message
)}
798 # self.log.debug('Writing ee_id to database: {}'.format(the_path))
802 update_dict
=update_dict
,
805 except asyncio
.CancelledError
:
807 except Exception as e
:
808 self
.log
.error("Error writing detailedStatus to database: {}".format(e
))
810 async def _get_system_cluster_id(self
):
811 if not self
._system
_cluster
_id
:
812 db_k8cluster
= self
.db
.get_one(
813 "k8sclusters", {"name": self
.vca_config
.kubectl_osm_cluster_name
}
815 k8s_hc_id
= deep_get(db_k8cluster
, ("_admin", "helm-chart-v3", "id"))
818 # backward compatibility for existing clusters that have not been initialized for helm v3
819 cluster_id
= db_k8cluster
.get("_id")
820 k8s_credentials
= yaml
.safe_dump(db_k8cluster
.get("credentials"))
821 k8s_hc_id
, uninstall_sw
= await self
._k
8sclusterhelm
3.init_env(
822 k8s_credentials
, reuse_cluster_uuid
=cluster_id
824 db_k8scluster_update
= {
825 "_admin.helm-chart-v3.error_msg": None,
826 "_admin.helm-chart-v3.id": k8s_hc_id
,
827 "_admin.helm-chart-v3}.created": uninstall_sw
,
828 "_admin.helm-chart-v3.operationalState": "ENABLED",
830 self
.update_db_2("k8sclusters", cluster_id
, db_k8scluster_update
)
831 except Exception as e
:
833 "error initializing helm-v3 cluster: {}".format(str(e
))
836 "K8s system cluster '{}' has not been initialized for helm-chart-v3".format(
840 self
._system
_cluster
_id
= k8s_hc_id
841 return self
._system
_cluster
_id