a4b98db7c937377e455c85051f37415fae78aebb
2 # Copyright 2019 Telefonica Investigacion y Desarrollo, S.A.U.
3 # This file is part of OSM
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
10 # http://www.apache.org/licenses/LICENSE-2.0
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
16 # See the License for the specific language governing permissions and
17 # limitations under the License.
19 # For those usages not covered by the Apache License, Version 2.0 please
20 # contact with: nfvlabs@tid.es
27 from n2vc
.loggable
import Loggable
30 class K8sConnector(abc
.ABC
, Loggable
):
32 ####################################################################################
33 ################################### P U B L I C ####################################
34 ####################################################################################
38 def generate_kdu_instance_name(**kwargs
):
39 raise NotImplementedError("Method not implemented")
41 def __init__(self
, db
: object, log
: object = None, on_update_db
=None):
44 :param db: database object to write current operation status
45 :param log: logger for tracing
46 :param on_update_db: callback called when k8s connector updates database
50 Loggable
.__init
__(self
, log
=log
, log_to_console
=True, prefix
="\nK8S")
52 # self.log.info('Initializing generic K8S connector')
54 # the database and update callback
56 self
.on_update_db
= on_update_db
58 # self.log.info('K8S generic connector initialized')
62 self
, k8s_creds
: str, namespace
: str = "kube-system", reuse_cluster_uuid
=None
65 It prepares a given K8s cluster environment to run Charts or juju Bundles on
70 :param k8s_creds: credentials to access a given K8s cluster, i.e. a valid
72 :param namespace: optional namespace to be used for the K8s engine (helm
73 tiller, juju). By default, 'kube-system' will be used
74 :param reuse_cluster_uuid: existing cluster uuid for reuse
75 :return: uuid of the K8s cluster and True if connector has installed some
76 software in the cluster (on error, an exception will be raised)
85 repo_type
: str = "chart",
91 Add a new repository to OSM database
93 :param cluster_uuid: the cluster
94 :param name: name for the repo in OSM
95 :param url: URL of the repo
96 :param repo_type: either "chart" or "bundle"
97 :return: True if successful
101 async def repo_list(self
, cluster_uuid
: str):
103 Get the list of registered repositories
105 :param cluster_uuid: the cluster
106 :return: list of registered repositories: [ (name, url) .... ]
110 async def repo_remove(self
, cluster_uuid
: str, name
: str):
112 Remove a repository from OSM
114 :param name: repo name in OSM
115 :param cluster_uuid: the cluster
116 :return: True if successful
120 async def synchronize_repos(self
, cluster_uuid
: str, name
: str):
122 Synchronizes the list of repositories created in the cluster with
123 the repositories added by the NBI
125 :param cluster_uuid: the cluster
126 :return: List of repositories deleted from the cluster and dictionary with
132 self
, cluster_uuid
: str, force
: bool = False, uninstall_sw
: bool = False
135 Uninstalls Tiller/Charm from a known K8s cluster and removes it from the list
136 of known K8s clusters. Intended to be used e.g. when the NS instance is deleted.
138 :param cluster_uuid: UUID of a K8s cluster known by OSM.
139 :param force: force deletion, even in case there are deployed releases
140 :param uninstall_sw: flag to indicate that sw uninstallation from software is
142 :return: str: kdu_instance generated by helm
152 timeout
: float = 300,
154 db_dict
: dict = None,
155 kdu_name
: str = None,
156 namespace
: str = None,
159 Deploys of a new KDU instance. It would implicitly rely on the `install` call
160 to deploy the Chart/Bundle properly parametrized (in practice, this call would
161 happen before any _initial-config-primitive_of the VNF is called).
163 :param cluster_uuid: UUID of a K8s cluster known by OSM
164 :param kdu_model: chart/bundle:version reference (string), which can be either
166 - a name of chart/bundle available via the repos known by OSM
167 - a path to a packaged chart/bundle
168 - a path to an unpacked chart/bundle directory or a URL
169 :param kdu_instance: Kdu instance name
170 :param atomic: If set, installation process purges chart/bundle on fail, also
171 will wait until all the K8s objects are active
172 :param timeout: Time in seconds to wait for the install of the chart/bundle
173 (defaults to Helm default timeout: 300s)
174 :param params: dictionary of key-value pairs for instantiation parameters
175 (overriding default values)
176 :param dict db_dict: where to write into database when the status changes.
177 It contains a dict with {collection: <str>, filter: {},
179 e.g. {collection: "nsrs", filter:
180 {_id: <nsd-id>, path: "_admin.deployed.K8S.3"}
181 :param kdu_name: Name of the KDU instance to be installed
182 :param namespace: K8s namespace to use for the KDU instance
183 :return: True if successful
191 kdu_model
: str = None,
193 timeout
: float = 300,
195 db_dict
: dict = None,
198 Upgrades an existing KDU instance. It would implicitly use the `upgrade` call
199 over an existing Chart/Bundle. It can be used both to upgrade the chart or to
200 reconfigure it. This would be exposed as Day-2 primitive.
202 :param cluster_uuid: UUID of a K8s cluster known by OSM
203 :param kdu_instance: unique name for the KDU instance to be updated
204 :param kdu_model: new chart/bundle:version reference
205 :param atomic: rollback in case of fail and wait for pods and services are
207 :param timeout: Time in seconds to wait for the install of the chart/bundle
208 (defaults to Helm default timeout: 300s)
209 :param params: new dictionary of key-value pairs for instantiation parameters
210 :param dict db_dict: where to write into database when the status changes.
211 It contains a dict with {collection: <str>, filter: {},
213 e.g. {collection: "nsrs", filter:
214 {_id: <nsd-id>, path: "_admin.deployed.K8S.3"}
215 :return: reference to the new revision number of the KDU instance
224 total_timeout
: float = 1800,
225 cluster_uuid
: str = None,
226 kdu_model
: str = None,
228 db_dict
: dict = None,
231 """Scale a resource in a KDU instance.
234 kdu_instance: KDU instance name
235 scale: Scale to which to set the resource
236 resource_name: Resource name
237 total_timeout: The time, in seconds, to wait for the install
239 cluster_uuid: The UUID of the cluster
240 kdu_model: The chart/bundle reference
241 atomic: if set, upgrade process rolls back changes made in case of failed upgrade.
242 The --wait flag will be set automatically if --atomic is used
243 db_dict: Dictionary for any additional data
244 kwargs: Additional parameters
248 True if successful, False otherwise
252 async def get_scale_count(
258 timeout
: float = 300,
261 """Get a resource scale count in a KDU instance.
264 resource_name: Resource name
265 kdu_instance: KDU instance name
266 cluster_uuid: The UUID of the cluster
267 kdu_model: chart/bundle reference
268 timeout: The time, in seconds, to wait
269 kwargs: Additional parameters
272 Resource instance count
277 self
, cluster_uuid
: str, kdu_instance
: str, revision
=0, db_dict
: dict = None
280 Rolls back a previous update of a KDU instance. It would implicitly use the
281 `rollback` call. It can be used both to rollback from a Chart/Bundle version
282 update or from a reconfiguration. This would be exposed as Day-2 primitive.
284 :param cluster_uuid: UUID of a K8s cluster known by OSM
285 :param kdu_instance: unique name for the KDU instance
286 :param revision: revision to which revert changes. If omitted, it will revert
288 :param dict db_dict: where to write into database when the status changes.
289 It contains a dict with {collection: <str>, filter: {},
291 e.g. {collection: "nsrs", filter:
292 {_id: <nsd-id>, path: "_admin.deployed.K8S.3"}
293 :return:If successful, reference to the current active revision of the KDU
294 instance after the rollback
298 async def uninstall(self
, cluster_uuid
: str, kdu_instance
: str):
300 Removes an existing KDU instance. It would implicitly use the `delete` call
301 (this call would happen after all _terminate-config-primitive_ of the VNF are
304 :param cluster_uuid: UUID of a K8s cluster known by OSM
305 :param kdu_instance: unique name for the KDU instance to be deleted
306 :return: True if successful
310 async def exec_primitive(
312 cluster_uuid
: str = None,
313 kdu_instance
: str = None,
314 primitive_name
: str = None,
315 timeout
: float = 300,
317 db_dict
: dict = None,
319 """Exec primitive (Juju action)
321 :param cluster_uuid str: The UUID of the cluster
322 :param kdu_instance str: The unique name of the KDU instance
323 :param primitive_name: Name of action that will be executed
324 :param timeout: Timeout for action execution
325 :param params: Dictionary of all the parameters needed for the action
326 :db_dict: Dictionary for any additional data
328 :return: Returns the output of the action
332 async def inspect_kdu(self
, kdu_model
: str, repo_url
: str = None) -> str:
334 These calls will retrieve from the Chart/Bundle:
336 - The list of configurable values and their defaults (e.g. in Charts,
337 it would retrieve the contents of `values.yaml`).
338 - If available, any embedded help file (e.g. `readme.md`) embedded in the
341 :param kdu_model: chart/bundle reference
342 :param repo_url: optional, reposotory URL (None if tar.gz, URl in other cases,
346 If successful, it will return the available parameters and their default values
347 as provided by the backend.
351 async def help_kdu(self
, kdu_model
: str, repo_url
: str = None) -> str:
354 :param kdu_model: chart/bundle reference
355 :param repo_url: optional, reposotory URL (None if tar.gz, URl in other cases,
357 :return: If successful, it will return the contents of the 'readme.md'
361 async def status_kdu(self
, cluster_uuid
: str, kdu_instance
: str) -> str:
363 This call would retrieve tha current state of a given KDU instance. It would be
364 would allow to retrieve the _composition_ (i.e. K8s objects) and _specific
365 values_ of the configuration parameters applied to a given instance. This call
366 would be based on the `status` call.
368 :param cluster_uuid: UUID of a K8s cluster known by OSM
369 :param kdu_instance: unique name for the KDU instance
370 :return: If successful, it will return the following vector of arguments:
371 - K8s `namespace` in the cluster where the KDU lives
372 - `state` of the KDU instance. It can be:
379 - List of `resources` (objects) that this release consists of, sorted by kind,
380 and the status of those resources
381 - Last `deployment_time`.
386 async def get_services(
387 self
, cluster_uuid
: str, kdu_instance
: str, namespace
: str
390 Returns a list of services defined for the specified kdu instance.
392 :param cluster_uuid: UUID of a K8s cluster known by OSM
393 :param kdu_instance: unique name for the KDU instance
394 :param namespace: K8s namespace used by the KDU instance
395 :return: If successful, it will return a list of services, Each service
396 can have the following data:
397 - `name` of the service
398 - `type` type of service in the k8 cluster
399 - `ports` List of ports offered by the service, for each port includes at least
401 - `cluster_ip` Internal ip to be used inside k8s cluster
402 - `external_ip` List of external ips (in case they are available)
406 async def get_service(
407 self
, cluster_uuid
: str, service_name
: str, namespace
: str = None
410 Obtains the data of the specified service in the k8cluster.
412 :param cluster_uuid: UUID of a K8s cluster known by OSM
413 :param service_name: name of the K8s service in the specified namespace
414 :param namespace: K8s namespace used by the KDU instance
415 :return: If successful, it will return a list of services, Each service can have
417 - `name` of the service
418 - `type` type of service in the k8 cluster
419 - `ports` List of ports offered by the service, for each port includes at least
421 - `cluster_ip` Internal ip to be used inside k8s cluster
422 - `external_ip` List of external ips (in case they are available)
426 ####################################################################################
427 ################################### P R I V A T E ##################################
428 ####################################################################################
431 async def write_app_status_to_db(
432 self
, db_dict
: dict, status
: str, detailed_status
: str, operation
: str
436 self
.warning("No db => No database write")
440 self
.warning("No db_dict => No database write")
443 self
.log
.debug("status={}".format(status
))
447 the_table
= db_dict
["collection"]
448 the_filter
= db_dict
["filter"]
449 the_path
= db_dict
["path"]
450 if not the_path
[-1] == ".":
451 the_path
= the_path
+ "."
453 the_path
+ "operation": operation
,
454 the_path
+ "status": status
,
455 the_path
+ "detailed-status": detailed_status
,
456 the_path
+ "status-time": str(time
.time()),
462 update_dict
=update_dict
,
467 if self
.on_update_db
:
468 if asyncio
.iscoroutinefunction(self
.on_update_db
):
469 await self
.on_update_db(
470 the_table
, the_filter
, the_path
, update_dict
473 self
.on_update_db(the_table
, the_filter
, the_path
, update_dict
)
477 except Exception as e
:
478 self
.log
.info("Exception writing status to database: {}".format(e
))