Merge commit 'refs/changes/29/5829/2' of https://osm.etsi.org/gerrit/osm/RO into lcm
[osm/RO.git] / lcm / lcm.py
1 #!/usr/bin/python3
2 # -*- coding: utf-8 -*-
3
4 import asyncio
5 import aiohttp
6 import yaml
7 import ROclient
8 import time
9 import dbmemory
10 import logging
11
12 from copy import deepcopy
13 from uuid import uuid4
14
15 #streamformat = "%(asctime)s %(name)s %(levelname)s: %(message)s"
16 streamformat = "%(name)s %(levelname)s: %(message)s"
17 logging.basicConfig(format=streamformat, level=logging.DEBUG)
18 logger = logging.getLogger('lcm')
19
20 ro_account = {
21 "url": "http://localhost:9090/openmano",
22 "tenant": "osm"
23 }
24
25 vca_account = {
26 # TODO
27 }
28
29 # conains created tasks/futures to be able to cancel
30 lcm_tasks = {}
31
32 headers_req = {'Accept': 'application/yaml', 'content-type': 'application/yaml'}
33 ns_status = ("CREATION-SCHEDULED", "DEPLOYING", "CONFIGURING", "DELETION-SCHEDULED", "UN-CONFIGURING", "UNDEPLOYING")
34
35 # TODO replace with database calls
36 db = dbmemory.dbmemory()
37
38
39 class RO_Exception(Exception):
40 pass
41
42
43 async def CreateNS(loop, nsr_id):
44 logger.debug("CreateNS task nsr_id={} Enter".format(nsr_id))
45 nsr_lcm = {
46 "id": nsr_id,
47 "RO": {"vnfd_id": {}, "nsd_id": None, "nsr_id": None, "nsr_status": "SCHEDULED"},
48 "nsr_ip": {},
49 "VCA": {"TODO"},
50 "status": "BUILD",
51 "status_detailed": "",
52 }
53
54 deloyment_timeout = 120
55 try:
56 ns_request = db.get_one("ns_request", {"id": nsr_id})
57 nsd = db.get_one("nsd", {"id": ns_request["nsd_id"]})
58 RO = ROclient.ROClient(loop, endpoint_url=ro_account["url"], tenant=ro_account["tenant"],
59 datacenter=ns_request["vim"])
60 nsr_lcm["status_detailed"] = "Creating vnfd at RO"
61 # ns_request["constituent-vnfr-ref"] = []
62
63 db.create("nsr_lcm", nsr_lcm)
64
65 # get vnfds, instantiate at RO
66 logger.debug("CreateNS task nsr_id={} RO VNFD".format(nsr_id))
67 for c_vnf in nsd["constituent-vnfd"]:
68 vnfd_id = c_vnf["vnfd-id-ref"]
69 vnfd = db.get_one("vnfd", {"id": vnfd_id})
70 vnfd.pop("_admin", None)
71 vnfd.pop("_id", None)
72 # vnfr = deepcopy(vnfd)
73 # vnfr["member-vnf-index"] = c_vnf["member-vnf-index"]
74 # vnfr["nsr-id"] = nsr_id
75 # vnfr["id"] = uuid4()
76 # vnfr["vnf-id"] = vnfd["id"]
77 # ns_request["constituent-vnfr-ref"],append(vnfd_id)
78
79 # TODO change id for RO in case it is present
80 try:
81 desc = await RO.create("vnfd", descriptor=vnfd)
82 nsr_lcm["RO"]["vnfd_id"][vnfd_id] = desc["uuid"]
83 db.replace("nsr_lcm", {"id": nsr_id}, nsr_lcm)
84 except ROclient.ROClientException as e:
85 if e.http_code == 409: # conflict, vnfd already present
86 print("debug", e)
87 else:
88 raise
89
90 # db_new("vnfr", vnfr)
91 # db_update("ns_request", nsr_id, ns_request)
92
93 # create nsd at RO
94 logger.debug("CreateNS task nsr_id={} RO NSD".format(nsr_id))
95 nsr_lcm["status_detailed"] = "Creating nsd at RO"
96 nsd_id = ns_request["nsd_id"]
97 nsd = db.get_one("nsd", {"id": nsd_id})
98 nsd.pop("_admin", None)
99 nsd.pop("_id", None)
100 try:
101 desc = await RO.create("nsd", descriptor=nsd)
102 nsr_lcm["RO"]["nsd_id"] = desc["uuid"]
103 db.replace("nsr_lcm", {"id": nsr_id}, nsr_lcm)
104 except ROclient.ROClientException as e:
105 if e.http_code == 409: # conflict, nsd already present
106 print("debug", e)
107 else:
108 raise
109
110 # Crate ns at RO
111 logger.debug("CreateNS task nsr_id={} RO NS".format(nsr_id))
112 nsr_lcm["status_detailed"] = "Creating ns at RO"
113 desc = await RO.create("ns", name=ns_request["name"], datacenter=ns_request["vim"], scenario=nsr_lcm["RO"]["nsd_id"])
114 RO_nsr_id = desc["uuid"]
115 nsr_lcm["RO"]["nsr_id"] = RO_nsr_id
116 nsr_lcm["RO"]["nsr_status"] = "BUILD"
117 db.replace("nsr_lcm", {"id": nsr_id}, nsr_lcm)
118
119 # wait until NS is ready
120 deloyment_timeout = 600
121 while deloyment_timeout > 0:
122 ns_status_detailed = "Waiting ns ready at RO"
123 nsr_lcm["status_detailed"] = ns_status_detailed
124 desc = await RO.show("ns", RO_nsr_id)
125 ns_status, ns_status_info = RO.check_ns_status(desc)
126 nsr_lcm["RO"]["nsr_status"] = ns_status
127 if ns_status == "ERROR":
128 raise ROclient.ROClientException(ns_status_info)
129 elif ns_status == "BUILD":
130 nsr_lcm["status_detailed"] = ns_status_detailed + "; nsr_id: '{}', {}".format(nsr_id, ns_status_info)
131 elif ns_status == "ACTIVE":
132 nsr_lcm["nsr_ip"] = RO.get_ns_vnf_ip(desc)
133 break
134 else:
135 assert False, "ROclient.check_ns_status returns unknown {}".format(ns_status)
136
137 await asyncio.sleep(5, loop=loop)
138 deloyment_timeout -= 5
139 if deloyment_timeout <= 0:
140 raise ROclient.ROClientException("Timeot wating ns to be ready")
141 nsr_lcm["status_detailed"] = "Configuring vnfr"
142 db.replace("nsr_lcm", {"id": nsr_id}, nsr_lcm)
143
144 #for nsd in nsr_lcm["descriptors"]["nsd"]:
145
146 logger.debug("CreateNS task nsr_id={} VCA look for".format(nsr_id))
147 for c_vnf in nsd["constituent-vnfd"]:
148 vnfd_id = c_vnf["vnfd-id-ref"]
149 vnfd_index = int(c_vnf["member-vnf-index"])
150 vnfd = db.get_one("vnfd", {"id": vnfd_id})
151 if vnfd.get("vnf-configuration") and vnfd["vnf-configuration"].get("juju"):
152 proxy_charm = vnfd["vnf-configuration"]["juju"]["charm"]
153 config_primitive = vnfd["vnf-configuration"].get("config-primitive")
154 # get parameters for juju charm
155 base_folder = vnfd["_admin"]["storage"]
156 path = base_folder + "/charms/" + proxy_charm
157 mgmt_ip = nsr_lcm['nsr_ip'][vnfd_index]
158 <<<<<<< HEAD
159 # task = asyncio.ensure_future(DeployCharm(loop, path, mgmt_ip, config_primitive))
160 pass
161 # TODO launch VCA charm
162 =======
163 # TODO launch VCA charm
164 # task = asyncio.ensure_future(DeployCharm(loop, path, mgmt_ip, config_primitive))
165 >>>>>>> 6ce7cc879dda3b729b10d563bd26df613dc9f70f
166 nsr_lcm["status"] = "DONE"
167 db.replace("nsr_lcm", {"id": nsr_id}, nsr_lcm)
168
169 return nsr_lcm
170
171 except (ROclient.ROClientException, Exception) as e:
172 logger.debug("CreateNS nsr_id={} Exception {}".format(nsr_id, e), exc_info=True)
173 nsr_lcm["status"] = "ERROR"
174 nsr_lcm["status_detailed"] += ": ERROR {}".format(e)
175 finally:
176 logger.debug("CreateNS task nsr_id={} Exit".format(nsr_id))
177
178
179 async def DestroyNS(loop, nsr_id):
180 logger.debug("DestroyNS task nsr_id={} Enter".format(nsr_id))
181 nsr_lcm = db.get_one("nsr_lcm", {"id": nsr_id})
182 ns_request = db.get_one("ns_request", {"id": nsr_id})
183
184 nsr_lcm["status"] = "DELETING"
185 nsr_lcm["status_detailed"] = "Deleting charms"
186 db.replace("nsr_lcm", {"id": nsr_id}, nsr_lcm)
187 <<<<<<< HEAD
188 # TODO destroy charms
189 =======
190 # TODO destroy VCA charm
191 >>>>>>> 6ce7cc879dda3b729b10d563bd26df613dc9f70f
192
193 # remove from RO
194 RO = ROclient.ROClient(loop, endpoint_url=ro_account["url"], tenant=ro_account["tenant"],
195 datacenter=ns_request["vim"])
196 # Delete ns
197 try:
198 RO_nsr_id = nsr_lcm["RO"]["nsr_id"]
199 if RO_nsr_id:
200 nsr_lcm["status_detailed"] = "Deleting ns at RO"
201 desc = await RO.delete("ns", RO_nsr_id)
202 print("debug", "deleted RO ns {}".format(RO_nsr_id))
203 nsr_lcm["RO"]["nsr_id"] = None
204 nsr_lcm["RO"]["nsr_status"] = "DELETED"
205 db.replace("nsr_lcm", {"id": nsr_id}, nsr_lcm)
206 except ROclient.ROClientException as e:
207 if e.http_code == 404:
208 nsr_lcm["RO"]["nsr_id"] = None
209 nsr_lcm["RO"]["nsr_status"] = "DELETED"
210 db.replace("nsr_lcm", {"id": nsr_id}, nsr_lcm)
211 print("warning", e)
212 else:
213 print("error", e)
214
215 # Delete nsd
216 try:
217 RO_nsd_id = nsr_lcm["RO"]["nsd_id"]
218 if RO_nsd_id:
219 nsr_lcm["status_detailed"] = "Deleting nsd at RO"
220 desc = await RO.delete("nsd", RO_nsd_id)
221 print("debug", "deleted RO nsd {}".format(RO_nsd_id))
222 nsr_lcm["RO"]["nsd_id"] = None
223 db.replace("nsr_lcm", {"id": nsr_id}, nsr_lcm)
224 except ROclient.ROClientException as e:
225 if e.http_code == 404:
226 nsr_lcm["RO"]["nsd_id"] = None
227 print("warning", e)
228 else:
229 print("error", e)
230
231 for vnf_id, RO_vnfd_id in nsr_lcm["RO"]["vnfd_id"].items():
232 try:
233 if RO_vnfd_id:
234 nsr_lcm["status_detailed"] = "Deleting vnfd at RO"
235 desc = await RO.delete("vnfd", RO_vnfd_id)
236 print("debug", "deleted RO vnfd {}".format(RO_vnfd_id))
237 nsr_lcm["RO"]["vnfd_id"][vnf_id] = None
238 db.replace("nsr_lcm", {"id": nsr_id}, nsr_lcm)
239 except ROclient.ROClientException as e:
240 if e.http_code == 404:
241 nsr_lcm["RO"]["vnfd_id"][vnf_id] = None
242 print("warning", e)
243 else:
244 print("error", e)
245 logger.debug("DestroyNS task nsr_id={} Exit".format(nsr_id))
246
247
248 async def test(loop, param=None):
249 logger.debug("Starting/Ending test task: {}".format(param))
250
251
252 def cancel_tasks(loop, nsr_id):
253 """
254 Cancel all active tasks of a concrete nsr identified for nsr_id
255 :param loop: loop
256 :param nsr_id: nsr identity
257 :return: None, or raises an exception if not possible
258 """
259 global lcm_tasks
260 if not lcm_tasks.get(nsr_id):
261 return
262 for order_id, tasks_set in lcm_tasks[nsr_id].items():
263 for task_name, task in tasks_set.items():
264 result = task.cancel()
265 if result:
266 logger.debug("nsr_id={} order_id={} task={} cancelled".format(nsr_id, order_id, task_name))
267 lcm_tasks[nsr_id] = {}
268
269
270
271 async def read_kafka(loop, bus_info):
272 global lcm_tasks
273 logger.debug("kafka task Enter")
274 order_id = 1
275 # future = asyncio.Future()
276 with open(bus_info["file"]) as f:
277
278 # ignore old orders. Read file
279 command = "fake"
280 while command:
281 command = f.read()
282
283 while True:
284 command = f.read()
285 if not command:
286 await asyncio.sleep(2, loop=loop)
287 continue
288 order_id += 1
289 command = command.strip()
290 command, _, params = command.partition(" ")
291 if command == "exit":
292 print("Bye!")
293 break
294 elif command.startswith("#"):
295 continue
296 elif command == "echo":
297 print(params)
298 elif command == "test":
299 asyncio.Task(test(loop, params), loop=loop)
300 elif command == "break":
301 print("put a break in this line of code")
302 elif command == "new-ns":
303 nsr_id = params.strip()
304 logger.debug("Deploying NS {}".format(nsr_id))
305 task = asyncio.ensure_future(CreateNS(loop, nsr_id))
306 if nsr_id not in lcm_tasks:
307 lcm_tasks[nsr_id] = {}
308 lcm_tasks[nsr_id][order_id] = {"CreateNS": task}
309 elif command == "del-ns":
310 nsr_id = params.strip()
311 logger.debug("Deleting NS {}".format(nsr_id))
312 cancel_tasks(loop, nsr_id)
313 task = asyncio.ensure_future(DestroyNS(loop, nsr_id))
314 if nsr_id not in lcm_tasks:
315 lcm_tasks[nsr_id] = {}
316 lcm_tasks[nsr_id][order_id] = {"DestroyNS": task}
317 elif command == "get-ns":
318 nsr_id = params.strip()
319 nsr_lcm = db.get_one("nsr_lcm", {"id": nsr_id})
320 print("nsr_lcm", nsr_lcm)
321 print("lcm_tasks", lcm_tasks.get(nsr_id))
322 else:
323 logger.debug("unknown command '{}'".format(command))
324 print("Usage:\n echo <>\n new-ns <ns1|ns2>\n del-ns <ns1|ns2>\n get-ns <ns1|ns2>")
325 logger.debug("kafka task Exit")
326
327
328 def lcm():
329 loop = asyncio.get_event_loop()
330 loop.run_until_complete(read_kafka(loop, {"file": "/home/atierno/OSM/osm/NBI/kafka"}))
331 return
332
333
334 def lcm2():
335 loop = asyncio.get_event_loop()
336 # asyncio.ensure_future(CreateNS, loop)
337 try:
338 content = loop.run_until_complete(CreateNS(loop, "ns1"))
339 print("Done: {}".format(content))
340 except ROclient.ROClientException as e:
341 print("Error {}".format(e))
342
343 time.sleep(10)
344
345 content = loop.run_until_complete(DestroyNS(loop, "ns1"))
346 print(content)
347
348 loop.close()
349
350
351 if __name__ == '__main__':
352
353 # FOR TEST
354 RO_VIM = "OST2_MRT"
355
356 #FILL DATABASE
357 with open("/home/atierno/OSM/osm/devops/descriptor-packages/vnfd/ping_vnf/src/ping_vnfd.yaml") as f:
358 vnfd = yaml.load(f)
359 vnfd_clean, _ = ROclient.remove_envelop("vnfd", vnfd)
360 vnfd_clean["_admin"] = {"storage": "/home/atierno/OSM/osm/devops/descriptor-packages/vnfd/ping_vnf"}
361 db.create("vnfd", vnfd_clean)
362 with open("/home/atierno/OSM/osm/devops/descriptor-packages/vnfd/pong_vnf/src/pong_vnfd.yaml") as f:
363 vnfd = yaml.load(f)
364 vnfd_clean, _ = ROclient.remove_envelop("vnfd", vnfd)
365 vnfd_clean["_admin"] = {"storage": "/home/atierno/OSM/osm/devops/descriptor-packages/vnfd/pong_vnf"}
366 db.create("vnfd", vnfd_clean)
367 with open("/home/atierno/OSM/osm/devops/descriptor-packages/nsd/ping_pong_ns/src/ping_pong_nsd.yaml") as f:
368 nsd = yaml.load(f)
369 nsd_clean, _ = ROclient.remove_envelop("nsd", nsd)
370 nsd_clean["_admin"] = {"storage": "/home/atierno/OSM/osm/devops/descriptor-packages/nsd/ping_pong_ns"}
371 db.create("nsd", nsd_clean)
372
373 ns_request = {
374 "id": "ns1",
375 "nsr_id": "ns1",
376 "name": "pingpongOne",
377 "vim": RO_VIM,
378 "nsd_id": nsd_clean["id"], # nsd_ping_pong
379 }
380 db.create("ns_request", ns_request)
381 ns_request = {
382 "id": "ns2",
383 "nsr_id": "ns2",
384 "name": "pingpongTwo",
385 "vim": RO_VIM,
386 "nsd_id": nsd_clean["id"], # nsd_ping_pong
387 }
388 db.create("ns_request", ns_request)
389 # lcm2()
390 lcm()