update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b second try
[osm/SO.git] / rwcal / plugins / vala / rwcal_mock / rwcal_mock.py
1
2 #
3 # Copyright 2016 RIFT.IO Inc
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #
17
18 import random
19 import socket
20 import struct
21 import collections
22 import hashlib
23 import logging
24 import os
25 import uuid
26
27 from gi import require_version
28 require_version('RwCal', '1.0')
29
30 from gi.repository import (
31 GObject,
32 RwCal,
33 RwTypes,
34 RwcalYang)
35
36 import rw_status
37 import rift.cal.rwcal_status as rwcal_status
38 import rwlogger
39
40 logger = logging.getLogger('rwcal.mock')
41
42
43 class UnknownAccountError(Exception):
44 pass
45
46
47 class MissingFileError(Exception):
48 pass
49
50
51 class ImageLocationError(Exception):
52 pass
53
54
55 rwstatus_exception_map = { IndexError: RwTypes.RwStatus.NOTFOUND,
56 KeyError: RwTypes.RwStatus.NOTFOUND,
57 NotImplementedError: RwTypes.RwStatus.NOT_IMPLEMENTED,
58 UnknownAccountError: RwTypes.RwStatus.NOTFOUND,
59 MissingFileError: RwTypes.RwStatus.NOTFOUND,
60 }
61
62 rwstatus = rw_status.rwstatus_from_exc_map(rwstatus_exception_map)
63 rwcalstatus = rwcal_status.rwcalstatus_from_exc_map(rwstatus_exception_map)
64
65 class Resources(object):
66 def __init__(self):
67 self.images = dict()
68 self.vlinks = dict()
69 self.vdus = dict()
70 self.flavors = dict()
71
72 class MockPlugin(GObject.Object, RwCal.Cloud):
73 """This class implements the abstract methods in the Cloud class.
74 Mock is used for unit testing."""
75
76 def __init__(self):
77 GObject.Object.__init__(self)
78 self.resources = collections.defaultdict(Resources)
79
80 @staticmethod
81 def get_uuid(name):
82 if name == None:
83 raise ValueError("Name can not be None")
84 return str(uuid.uuid3(uuid.NAMESPACE_DNS, name))
85
86 @rwstatus
87 def do_init(self, rwlog_ctx):
88 if not any(isinstance(h, rwlogger.RwLogger) for h in logger.handlers):
89 logger.addHandler(
90 rwlogger.RwLogger(
91 category="rw-cal-log",
92 subcategory="rwcal.mock",
93 log_hdl=rwlog_ctx,
94 )
95 )
96
97 account = RwcalYang.YangData_RwProject_Project_CloudAccounts_CloudAccountList()
98 account.name = 'mock_account'
99 account.account_type = 'mock'
100 account.mock.username = 'mock_user'
101 self.create_default_resources(account)
102 account.name = 'mock_account1'
103 self.create_default_resources(account)
104
105 @rwstatus(ret_on_failure=[None])
106 def do_validate_cloud_creds(self, account):
107 """
108 Validates the cloud account credentials for the specified account.
109 If creds are not valid, returns an error code & reason string
110 Arguments:
111 account - a cloud account to validate
112
113 Returns:
114 Validation Code and Details String
115 """
116 status = RwcalYang.YangData_Rwcal_ConnectionStatus(
117 status="success",
118 details=""
119 )
120
121 return status
122
123 @rwstatus(ret_on_failure=[None])
124 def do_get_management_network(self, account):
125 """
126 Returns the management network
127
128 @param account - a cloud account
129
130 """
131 raise NotImplementedError()
132
133 @rwstatus
134 def do_create_tenant(self, account, name):
135 """
136 Create a new tenant.
137
138 @param name - name to assign to the tenant.
139 """
140 raise NotImplementedError()
141
142 @rwstatus
143 def do_delete_tenant(self, account, tenant_id):
144 """
145 delete a tenant.
146
147 @param tenant_id - id of tenant to be deleted.
148 """
149 raise NotImplementedError()
150
151 @rwstatus(ret_on_failure=[[]])
152 def do_get_tenant_list(self, account):
153 """
154 List tenants.
155
156 """
157 raise NotImplementedError()
158
159 @rwstatus
160 def do_create_role(self, account, name):
161 """
162 Create a new role.
163
164 @param name - name to assign to the role.
165 """
166 raise NotImplementedError()
167
168 @rwstatus
169 def do_delete_role(self, account, role_id):
170 """
171 delete a role.
172
173 @param role_id - id of role to be deleted.
174 """
175 raise NotImplementedError()
176
177 @rwstatus(ret_on_failure=[[]])
178 def do_get_role_list(self, account):
179 """
180 List roles.
181
182 """
183 raise NotImplementedError()
184
185 @rwstatus(ret_on_failure=[None])
186 def do_create_image(self, account, image):
187 """
188 Create a VM image
189
190 @param account - cloud account information
191 @param image - information about the image
192 """
193 if image.location is None:
194 raise ImageLocationError("uninitialized image location")
195
196 if not os.path.exists(image.location):
197 raise MissingFileError("{} does not exist".format(image.location))
198
199 image.id = self.get_uuid(image.name)
200
201 self.resources[account.name].images[image.id] = image
202 logger.debug('created image: {}'.format(image.id))
203 return image.id
204
205 @rwstatus
206 def do_delete_image(self, account, image_id):
207 """
208 delete a vm image.
209
210 @param image_id - Instance id of VM image to be deleted.
211 """
212 if account.name not in self.resources:
213 raise UnknownAccountError()
214
215 del self.resources[account.name].images[image_id]
216
217 @rwstatus(ret_on_failure=[None])
218 def do_get_image(self, account, image_id):
219 return self.resources[account.name].images[image_id]
220
221 @rwstatus(ret_on_failure=[[]])
222 def do_get_image_list(self, account):
223 """
224 Return a list of the names of all available images.
225 """
226 boxed_image_list = RwcalYang.YangData_RwProject_Project_VimResources()
227 for image in self.resources[account.name].images.values():
228 image_entry = RwcalYang.YangData_RwProject_Project_VimResources_ImageinfoList()
229 image_entry.id = image.id
230 image_entry.name = image.name
231 if image.has_field('checksum'):
232
233 image_entry.checksum = image.checksum
234 boxed_image_list.imageinfo_list.append(image_entry)
235
236 logger.debug("Image list for {}: {}".format(account.name, boxed_image_list.imageinfo_list))
237 return boxed_image_list
238
239 @rwstatus
240 def do_create_vm(self, account, vm):
241 """
242 Create a new virtual machine.
243
244 @param name - name to assign to the VM. This does not have to be unique.
245 @param image - name of image to load on the VM.
246 @param size - name of the size of the VM to create.
247 @param location - name of the location to launch the VM in.
248 """
249 raise NotImplementedError()
250
251 @rwstatus
252 def do_start_vm(self, account, vm_id):
253 """
254 Start a virtual machine.
255
256 @param vm_id - id of VM to start
257 """
258 raise NotImplementedError()
259
260 @rwstatus
261 def do_stop_vm(self, account, vm_id):
262 """
263 Stop a virtual machine.
264
265 @param vm_id - id of VM to stop
266 """
267 raise NotImplementedError()
268
269 @rwstatus
270 def do_delete_vm(self, account, vm_id):
271 """
272 delete a virtual machine.
273
274 @param vm_id - Instance id of VM to be deleted.
275 """
276 raise NotImplementedError()
277
278 @rwstatus
279 def do_reboot_vm(self, account, vm_id):
280 """
281 reboot a virtual machine.
282
283 @param vm_id - Instance id of VM to be deleted.
284 """
285 raise NotImplementedError()
286
287 @rwstatus(ret_on_failure=[[]])
288 def do_get_vm_list(self, account):
289 raise NotImplementedError()
290
291 @rwstatus
292 def do_create_flavor(self, account, flavor):
293 """
294 create new flavor.
295
296 @param flavor - Flavor object
297 """
298 flavor_id = self.get_uuid(flavor.name)
299 self.resources[account.name].flavors[flavor_id] = flavor
300 logger.debug('Created flavor: {}'.format(flavor_id))
301 return flavor_id
302
303 @rwstatus
304 def do_delete_flavor(self, account, flavor_id):
305 """
306 Delete flavor.
307
308 @param flavor_id - Flavor id to be deleted.
309 """
310 logger.debug('Deleted flavor: {}'.format(flavor_id))
311 self.resources[account.name].flavors.pop(flavor_id)
312
313 @rwstatus(ret_on_failure=[None])
314 def do_get_flavor(self, account, flavor_id):
315 """
316 Return the specified flavor
317
318 @param flavor_id - the id of the flavor to return
319 """
320 flavor = self.resources[account.name].flavors[flavor_id]
321 logger.debug('Returning flavor-info for : {}'.format(flavor_id))
322 return flavor
323
324 @rwstatus(ret_on_failure=[[]])
325 def do_get_flavor_list(self, account):
326 """
327 Return a list of flavors
328 """
329 vim_resources = RwcalYang.YangData_RwProject_Project_VimResources()
330 for flavor in self.resources[account.name].flavors.values():
331 f = RwcalYang.YangData_RwProject_Project_VimResources_FlavorinfoList()
332 f.copy_from(flavor)
333 vim_resources.flavorinfo_list.append(f)
334 logger.debug("Returning list of flavor-info of size: %d", len(vim_resources.flavorinfo_list))
335 return vim_resources
336
337
338 @rwstatus
339 def do_add_host(self, account, host):
340 raise NotImplementedError()
341
342 @rwstatus
343 def do_remove_host(self, account, host_id):
344 raise NotImplementedError()
345
346 @rwstatus(ret_on_failure=[None])
347 def do_get_host(self, account, host_id):
348 raise NotImplementedError()
349
350 @rwstatus(ret_on_failure=[[]])
351 def do_get_host_list(self, account):
352 raise NotImplementedError()
353
354 @rwstatus
355 def do_create_port(self, account, port):
356 raise NotImplementedError()
357
358 @rwstatus
359 def do_delete_port(self, account, port_id):
360 raise NotImplementedError()
361
362 @rwstatus(ret_on_failure=[None])
363 def do_get_port(self, account, port_id):
364 raise NotImplementedError()
365
366 @rwstatus(ret_on_failure=[[]])
367 def do_get_port_list(self, account):
368 raise NotImplementedError()
369
370 @rwstatus
371 def do_create_network(self, account, network):
372 raise NotImplementedError()
373
374 @rwstatus
375 def do_delete_network(self, account, network_id):
376 raise NotImplementedError()
377
378 @rwstatus(ret_on_failure=[None])
379 def do_get_network(self, account, network_id):
380 raise NotImplementedError()
381
382 @rwstatus(ret_on_failure=[[]])
383 def do_get_network_list(self, account):
384 raise NotImplementedError()
385
386 def create_default_resources(self, account):
387 """
388 Create default resources
389 """
390 link_list = []
391 ### Add virtual links
392 #for i in range(1):
393 # vlink = RwcalYang.YangData_RwProject_Project_VirtualLinkReqParams()
394 # vlink.name = 'link-'+str(i)
395 # vlink.subnet = '10.0.0.0/24'
396 # rs, vlink_id = self.do_create_virtual_link(account, vlink)
397 # assert vlink_id != ''
398 # logger.debug("Creating static virtual-link with name: %s", vlink.name)
399 # link_list.append(vlink_id)
400
401 #### Add VDUs
402 #for i in range(8):
403 # vdu = RwcalYang.YangData_RwProject_Project_VduInitParams()
404 # vdu.name = 'vdu-'+str(i)
405 # vdu.node_id = str(i)
406 # vdu.image_id = self.get_uuid('image-'+str(i))
407 # vdu.flavor_id = self.get_uuid('flavor'+str(i))
408 # vdu.vm_flavor.vcpu_count = 4
409 # vdu.vm_flavor.memory_mb = 4096*2
410 # vdu.vm_flavor.storage_gb = 40
411 # for j in range(2):
412 # c = vdu.connection_points.add()
413 # c.name = vdu.name+'-port-'+str(j)
414 # c.virtual_link_id = link_list[j]
415 # rs, vdu_id = self.do_create_vdu(account, vdu)
416 # assert vdu_id != ''
417 # logger.debug("Creating static VDU with name: %s", vdu.name)
418
419 for i in range(2):
420 flavor = RwcalYang.YangData_RwProject_Project_VimResources_FlavorinfoList()
421 flavor.name = 'flavor-'+str(i)
422 flavor.vm_flavor.vcpu_count = 4
423 flavor.vm_flavor.memory_mb = 4096*2
424 flavor.vm_flavor.storage_gb = 40
425 rc, flavor_id = self.do_create_flavor(account, flavor)
426
427 for i in range(2):
428 image = RwcalYang.YangData_RwProject_Project_VimResources_ImageinfoList()
429 image.name = "rwimage"
430 image.id = self.get_uuid('image-'+str(i))
431 image.checksum = self.get_uuid('rwimage'+str(i))
432 image.location = "/dev/null"
433 rc, image_id = self.do_create_image(account, image)
434
435 image = RwcalYang.YangData_RwProject_Project_VimResources_ImageinfoList()
436 image.name = "Fedora-x86_64-20-20131211.1-sda.qcow2"
437 image.id = self.get_uuid(image.name)
438 image.checksum = self.get_uuid(image.name)
439 image.location = "/dev/null"
440 rc, image_id = self.do_create_image(account, image)
441
442 image = RwcalYang.YangData_RwProject_Project_VimResources_ImageinfoList()
443 image.name = "Fedora-x86_64-20-20131211.1-sda-ping.qcow2"
444 image.id = self.get_uuid(image.name)
445 image.checksum = "a6ffaa77f949a9e4ebb082c6147187cf"#self.get_uuid(image.name)
446 image.location = "/dev/null"
447 rc, image_id = self.do_create_image(account, image)
448
449 image = RwcalYang.YangData_RwProject_Project_VimResources_ImageinfoList()
450 image.name = "Fedora-x86_64-20-20131211.1-sda-pong.qcow2"
451 image.id = self.get_uuid(image.name)
452 image.checksum = "977484d95575f80ef8399c9cf1d45ebd"#self.get_uuid(image.name)
453 image.location = "/dev/null"
454 rc, image_id = self.do_create_image(account, image)
455
456
457 @rwcalstatus(ret_on_failure=[""])
458 def do_create_virtual_link(self, account, link_params):
459 vlink_id = self.get_uuid("%s_%s" % (link_params.name, len(self.resources[account.name].vlinks)))
460 vlink = RwcalYang.YangData_RwProject_Project_VnfResources_VirtualLinkInfoList()
461 vlink.name = link_params.name
462 vlink.state = 'active'
463 vlink.virtual_link_id = vlink_id
464 vlink.subnet = link_params.subnet
465 vlink.connection_points = []
466 for field in link_params.provider_network.fields:
467 if link_params.provider_network.has_field(field):
468 setattr(vlink.provider_network, field, getattr(link_params.provider_network, field))
469
470 self.resources[account.name].vlinks[vlink_id] = vlink
471 logger.debug('created virtual-link: {}'.format(vlink_id))
472 return vlink_id
473
474 @rwstatus
475 def do_delete_virtual_link(self, account, link_id):
476 self.resources[account.name].vlinks.pop(link_id)
477 logger.debug('deleted virtual-link: {}'.format(link_id))
478
479
480 @rwstatus(ret_on_failure=[None])
481 def do_get_virtual_link(self, account, link_id):
482 vlink = self.resources[account.name].vlinks[link_id]
483 logger.debug('Returning virtual-link-info for : {}'.format(link_id))
484 return vlink
485
486 @rwstatus(ret_on_failure=[None])
487 def do_get_virtual_link_by_name(self, account, link_name):
488 raise NotImplementedError()
489
490 @rwstatus(ret_on_failure=[""])
491 def do_get_virtual_link_list(self, account):
492 vnf_resources = RwcalYang.YangData_RwProject_Project_VnfResources()
493 for r in self.resources[account.name].vlinks.values():
494 vlink = RwcalYang.YangData_RwProject_Project_VnfResources_VirtualLinkInfoList()
495 vlink.copy_from(r)
496 vnf_resources.virtual_link_info_list.append(vlink)
497 logger.debug("Returning list of virtual-link-info of size: %d", len(vnf_resources.virtual_link_info_list))
498 return vnf_resources
499
500 @rwcalstatus(ret_on_failure=[""])
501 def do_create_vdu(self, account, vdu_init):
502 vdu_id = self.get_uuid("%s_%s" % (vdu_init.name, len(self.resources[account.name].vdus)))
503 vdu = RwcalYang.YangData_RwProject_Project_VnfResources_VduInfoList()
504 vdu.vdu_id = vdu_id
505 vdu.name = vdu_init.name
506 vdu.node_id = vdu_init.node_id
507 vdu.image_id = vdu_init.image_id
508 if vdu_init.has_field('flavor_id'):
509 vdu.flavor_id = vdu_init.flavor_id
510
511 if vdu_init.has_field('vm_flavor'):
512 xx = vdu.vm_flavor.new()
513 xx.from_pbuf(vdu_init.vm_flavor.to_pbuf())
514 vdu.vm_flavor = xx
515
516 if vdu_init.has_field('guest_epa'):
517 xx = vdu.guest_epa.new()
518 xx.from_pbuf(vdu_init.guest_epa.to_pbuf())
519 vdu.guest_epa = xx
520
521 if vdu_init.has_field('vswitch_epa'):
522 xx = vdu.vswitch_epa.new()
523 xx.from_pbuf(vdu_init.vswitch_epa.to_pbuf())
524 vdu.vswitch_epa = xx
525
526 if vdu_init.has_field('hypervisor_epa'):
527 xx = vdu.hypervisor_epa.new()
528 xx.from_pbuf(vdu_init.hypervisor_epa.to_pbuf())
529 vdu.hypervisor_epa = xx
530
531 if vdu_init.has_field('host_epa'):
532 xx = vdu.host_epa.new()
533 xx.from_pbuf(vdu_init.host_epa.to_pbuf())
534 vdu.host_epa = xx
535
536 vdu.state = 'active'
537 vdu.management_ip = socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff)))
538 vdu.public_ip = vdu.management_ip
539
540 for c in vdu_init.connection_points:
541 p = vdu.connection_points.add()
542 p.connection_point_id = self.get_uuid(c.name)
543 p.name = c.name
544 p.vdu_id = vdu_id
545 p.state = 'active'
546 p.ip_address = socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff)))
547 p.virtual_link_id = c.virtual_link_id
548 # Need to add this connection_point to virtual link
549 vlink = self.resources[account.name].vlinks[c.virtual_link_id]
550 v = vlink.connection_points.add()
551 for field in p.fields:
552 if p.has_field(field):
553 setattr(v, field, getattr(p, field))
554
555 self.resources[account.name].vdus[vdu_id] = vdu
556 logger.debug('Created vdu: {}'.format(vdu_id))
557 return vdu_id
558
559
560 @rwstatus
561 def do_modify_vdu(self, account, vdu_modify):
562 vdu = self.resources[account.name].vdus[vdu_modify.vdu_id]
563 for c in vdu_modify.connection_points_add:
564 p = vdu.connection_points.add()
565 p.connection_point_id = self.get_uuid(c.name)
566 p.name = c.name
567 p.vdu_id = vdu.vdu_id
568 p.state = 'active'
569 p.ip_address = socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff)))
570 p.virtual_link_id = c.virtual_link_id
571 # Need to add this connection_point to virtual link
572 vlink = self.resources[account.name].vlinks[c.virtual_link_id]
573 aa = RwcalYang.YangData_RwProject_Project_VnfResources_VirtualLinkInfoList_ConnectionPoints()
574 aa.connection_point_id = p.connection_point_id
575 aa.name = p.name
576 aa.virtual_link_id = vlink.virtual_link_id
577 aa.state = 'active'
578 aa.ip_address = p.ip_address
579 aa.vdu_id = p.vdu_id
580 vlink.connection_points.append(aa)
581
582 for c in vdu_modify.connection_points_remove:
583 for d in vdu.connection_points:
584 if c.connection_point_id == d.connection_point_id:
585 vdu.connection_points.remove(d)
586 break
587 for k, vlink in self.resources[account.name].vlinks.items():
588 for z in vlink.connection_points:
589 if z.connection_point_id == c.connection_point_id:
590 vlink.connection_points.remove(z)
591 break
592 logger.debug('modified vdu: {}'.format(vdu_modify.vdu_id))
593
594 @rwstatus
595 def do_delete_vdu(self, account, vdu_id):
596 vdu = self.resources[account.name].vdus.pop(vdu_id)
597 for c in vdu.connection_points:
598 vlink = self.resources[account.name].vlinks[c.virtual_link_id]
599 z = [p for p in vlink.connection_points if p.connection_point_id == c.connection_point_id]
600 assert len(z) == 1
601 vlink.connection_points.remove(z[0])
602
603 logger.debug('deleted vdu: {}'.format(vdu_id))
604
605 @rwcalstatus(ret_on_failure=[None])
606 def do_get_vdu(self, account, vdu_id, mgmt_network):
607 # mgmt_network - Added due to need for mgmt network.
608 # TO DO: Investigate the need here.
609 vdu = self.resources[account.name].vdus[vdu_id]
610 logger.debug('Returning vdu-info for : {}'.format(vdu_id))
611 return vdu.copy()
612
613 @rwcalstatus(ret_on_failure=[None])
614 def do_get_vdu_list(self, account):
615 vnf_resources = RwcalYang.YangData_RwProject_Project_VnfResources()
616 for r in self.resources[account.name].vdus.values():
617 vdu = RwcalYang.YangData_RwProject_Project_VnfResources_VduInfoList()
618 vdu.copy_from(r)
619 vnf_resources.vdu_info_list.append(vdu)
620 logger.debug("Returning list of vdu-info of size: %d", len(vnf_resources.vdu_info_list))
621 return vnf_resources
622