55b340ac60d8fd853ab152509f6a8d919e3dd9ae
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)
81 self
, cluster_uuid
: str, name
: str, url
: str, repo_type
: str = "chart"
84 Add a new repository to OSM database
86 :param cluster_uuid: the cluster
87 :param name: name for the repo in OSM
88 :param url: URL of the repo
89 :param repo_type: either "chart" or "bundle"
90 :return: True if successful
94 async def repo_list(self
, cluster_uuid
: str):
96 Get the list of registered repositories
98 :param cluster_uuid: the cluster
99 :return: list of registered repositories: [ (name, url) .... ]
103 async def repo_remove(self
, cluster_uuid
: str, name
: str):
105 Remove a repository from OSM
107 :param name: repo name in OSM
108 :param cluster_uuid: the cluster
109 :return: True if successful
113 async def synchronize_repos(self
, cluster_uuid
: str, name
: str):
115 Synchronizes the list of repositories created in the cluster with
116 the repositories added by the NBI
118 :param cluster_uuid: the cluster
119 :return: List of repositories deleted from the cluster and dictionary with
125 self
, cluster_uuid
: str, force
: bool = False, uninstall_sw
: bool = False
128 Uninstalls Tiller/Charm from a known K8s cluster and removes it from the list
129 of known K8s clusters. Intended to be used e.g. when the NS instance is deleted.
131 :param cluster_uuid: UUID of a K8s cluster known by OSM.
132 :param force: force deletion, even in case there are deployed releases
133 :param uninstall_sw: flag to indicate that sw uninstallation from software is
135 :return: str: kdu_instance generated by helm
145 timeout
: float = 300,
147 db_dict
: dict = None,
148 kdu_name
: str = None,
149 namespace
: str = None,
152 Deploys of a new KDU instance. It would implicitly rely on the `install` call
153 to deploy the Chart/Bundle properly parametrized (in practice, this call would
154 happen before any _initial-config-primitive_of the VNF is called).
156 :param cluster_uuid: UUID of a K8s cluster known by OSM
157 :param kdu_model: chart/bundle:version reference (string), which can be either
159 - a name of chart/bundle available via the repos known by OSM
160 - a path to a packaged chart/bundle
161 - a path to an unpacked chart/bundle directory or a URL
162 :param kdu_instance: Kdu instance name
163 :param atomic: If set, installation process purges chart/bundle on fail, also
164 will wait until all the K8s objects are active
165 :param timeout: Time in seconds to wait for the install of the chart/bundle
166 (defaults to Helm default timeout: 300s)
167 :param params: dictionary of key-value pairs for instantiation parameters
168 (overriding default values)
169 :param dict db_dict: where to write into database when the status changes.
170 It contains a dict with {collection: <str>, filter: {},
172 e.g. {collection: "nsrs", filter:
173 {_id: <nsd-id>, path: "_admin.deployed.K8S.3"}
174 :param kdu_name: Name of the KDU instance to be installed
175 :param namespace: K8s namespace to use for the KDU instance
176 :return: True if successful
184 kdu_model
: str = None,
186 timeout
: float = 300,
188 db_dict
: dict = None,
191 Upgrades an existing KDU instance. It would implicitly use the `upgrade` call
192 over an existing Chart/Bundle. It can be used both to upgrade the chart or to
193 reconfigure it. This would be exposed as Day-2 primitive.
195 :param cluster_uuid: UUID of a K8s cluster known by OSM
196 :param kdu_instance: unique name for the KDU instance to be updated
197 :param kdu_model: new chart/bundle:version reference
198 :param atomic: rollback in case of fail and wait for pods and services are
200 :param timeout: Time in seconds to wait for the install of the chart/bundle
201 (defaults to Helm default timeout: 300s)
202 :param params: new dictionary of key-value pairs for instantiation parameters
203 :param dict db_dict: where to write into database when the status changes.
204 It contains a dict with {collection: <str>, filter: {},
206 e.g. {collection: "nsrs", filter:
207 {_id: <nsd-id>, path: "_admin.deployed.K8S.3"}
208 :return: reference to the new revision number of the KDU instance
217 total_timeout
: float = 1800,
218 cluster_uuid
: str = None,
219 kdu_model
: str = None,
221 db_dict
: dict = None,
224 """Scale a resource in a KDU instance.
227 kdu_instance: KDU instance name
228 scale: Scale to which to set the resource
229 resource_name: Resource name
230 total_timeout: The time, in seconds, to wait for the install
232 cluster_uuid: The UUID of the cluster
233 kdu_model: The chart/bundle reference
234 atomic: if set, upgrade process rolls back changes made in case of failed upgrade.
235 The --wait flag will be set automatically if --atomic is used
236 db_dict: Dictionary for any additional data
237 kwargs: Additional parameters
241 True if successful, False otherwise
245 async def get_scale_count(
251 timeout
: float = 300,
254 """Get a resource scale count in a KDU instance.
257 resource_name: Resource name
258 kdu_instance: KDU instance name
259 cluster_uuid: The UUID of the cluster
260 kdu_model: chart/bundle reference
261 timeout: The time, in seconds, to wait
262 kwargs: Additional parameters
265 Resource instance count
270 self
, cluster_uuid
: str, kdu_instance
: str, revision
=0, db_dict
: dict = None
273 Rolls back a previous update of a KDU instance. It would implicitly use the
274 `rollback` call. It can be used both to rollback from a Chart/Bundle version
275 update or from a reconfiguration. This would be exposed as Day-2 primitive.
277 :param cluster_uuid: UUID of a K8s cluster known by OSM
278 :param kdu_instance: unique name for the KDU instance
279 :param revision: revision to which revert changes. If omitted, it will revert
281 :param dict db_dict: where to write into database when the status changes.
282 It contains a dict with {collection: <str>, filter: {},
284 e.g. {collection: "nsrs", filter:
285 {_id: <nsd-id>, path: "_admin.deployed.K8S.3"}
286 :return:If successful, reference to the current active revision of the KDU
287 instance after the rollback
291 async def uninstall(self
, cluster_uuid
: str, kdu_instance
: str):
293 Removes an existing KDU instance. It would implicitly use the `delete` call
294 (this call would happen after all _terminate-config-primitive_ of the VNF are
297 :param cluster_uuid: UUID of a K8s cluster known by OSM
298 :param kdu_instance: unique name for the KDU instance to be deleted
299 :return: True if successful
303 async def exec_primitive(
305 cluster_uuid
: str = None,
306 kdu_instance
: str = None,
307 primitive_name
: str = None,
308 timeout
: float = 300,
310 db_dict
: dict = None,
312 """Exec primitive (Juju action)
314 :param cluster_uuid str: The UUID of the cluster
315 :param kdu_instance str: The unique name of the KDU instance
316 :param primitive_name: Name of action that will be executed
317 :param timeout: Timeout for action execution
318 :param params: Dictionary of all the parameters needed for the action
319 :db_dict: Dictionary for any additional data
321 :return: Returns the output of the action
325 async def inspect_kdu(self
, kdu_model
: str, repo_url
: str = None) -> str:
327 These calls will retrieve from the Chart/Bundle:
329 - The list of configurable values and their defaults (e.g. in Charts,
330 it would retrieve the contents of `values.yaml`).
331 - If available, any embedded help file (e.g. `readme.md`) embedded in the
334 :param kdu_model: chart/bundle reference
335 :param repo_url: optional, reposotory URL (None if tar.gz, URl in other cases,
339 If successful, it will return the available parameters and their default values
340 as provided by the backend.
344 async def help_kdu(self
, kdu_model
: str, repo_url
: str = None) -> str:
347 :param kdu_model: chart/bundle reference
348 :param repo_url: optional, reposotory URL (None if tar.gz, URl in other cases,
350 :return: If successful, it will return the contents of the 'readme.md'
354 async def status_kdu(self
, cluster_uuid
: str, kdu_instance
: str) -> str:
356 This call would retrieve tha current state of a given KDU instance. It would be
357 would allow to retrieve the _composition_ (i.e. K8s objects) and _specific
358 values_ of the configuration parameters applied to a given instance. This call
359 would be based on the `status` call.
361 :param cluster_uuid: UUID of a K8s cluster known by OSM
362 :param kdu_instance: unique name for the KDU instance
363 :return: If successful, it will return the following vector of arguments:
364 - K8s `namespace` in the cluster where the KDU lives
365 - `state` of the KDU instance. It can be:
372 - List of `resources` (objects) that this release consists of, sorted by kind,
373 and the status of those resources
374 - Last `deployment_time`.
379 async def get_services(
380 self
, cluster_uuid
: str, kdu_instance
: str, namespace
: str
383 Returns a list of services defined for the specified kdu instance.
385 :param cluster_uuid: UUID of a K8s cluster known by OSM
386 :param kdu_instance: unique name for the KDU instance
387 :param namespace: K8s namespace used by the KDU instance
388 :return: If successful, it will return a list of services, Each service
389 can have the following data:
390 - `name` of the service
391 - `type` type of service in the k8 cluster
392 - `ports` List of ports offered by the service, for each port includes at least
394 - `cluster_ip` Internal ip to be used inside k8s cluster
395 - `external_ip` List of external ips (in case they are available)
399 async def get_service(
400 self
, cluster_uuid
: str, service_name
: str, namespace
: str = None
403 Obtains the data of the specified service in the k8cluster.
405 :param cluster_uuid: UUID of a K8s cluster known by OSM
406 :param service_name: name of the K8s service in the specified namespace
407 :param namespace: K8s namespace used by the KDU instance
408 :return: If successful, it will return a list of services, Each service can have
410 - `name` of the service
411 - `type` type of service in the k8 cluster
412 - `ports` List of ports offered by the service, for each port includes at least
414 - `cluster_ip` Internal ip to be used inside k8s cluster
415 - `external_ip` List of external ips (in case they are available)
419 ####################################################################################
420 ################################### P R I V A T E ##################################
421 ####################################################################################
424 async def write_app_status_to_db(
425 self
, db_dict
: dict, status
: str, detailed_status
: str, operation
: str
429 self
.warning("No db => No database write")
433 self
.warning("No db_dict => No database write")
436 self
.log
.debug("status={}".format(status
))
440 the_table
= db_dict
["collection"]
441 the_filter
= db_dict
["filter"]
442 the_path
= db_dict
["path"]
443 if not the_path
[-1] == ".":
444 the_path
= the_path
+ "."
446 the_path
+ "operation": operation
,
447 the_path
+ "status": status
,
448 the_path
+ "detailed-status": detailed_status
,
449 the_path
+ "status-time": str(time
.time()),
455 update_dict
=update_dict
,
460 if self
.on_update_db
:
461 if asyncio
.iscoroutinefunction(self
.on_update_db
):
462 await self
.on_update_db(
463 the_table
, the_filter
, the_path
, update_dict
466 self
.on_update_db(the_table
, the_filter
, the_path
, update_dict
)
470 except Exception as e
:
471 self
.log
.info("Exception writing status to database: {}".format(e
))