a1776d11da74e3138f53255c1166f933b67e5a59
[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.CloudAccount()
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.CloudConnectionStatus(
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.VimResources()
227 for image in self.resources[account.name].images.values():
228 image_entry = RwcalYang.ImageInfoItem()
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.VimResources()
330 for flavor in self.resources[account.name].flavors.values():
331 f = RwcalYang.FlavorInfoItem()
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.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.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.FlavorInfoItem()
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.ImageInfoItem()
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.ImageInfoItem()
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.ImageInfoItem()
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.ImageInfoItem()
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.VirtualLinkInfoParams()
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=[""])
487 def do_get_virtual_link_list(self, account):
488 vnf_resources = RwcalYang.VNFResources()
489 for r in self.resources[account.name].vlinks.values():
490 vlink = RwcalYang.VirtualLinkInfoParams()
491 vlink.copy_from(r)
492 vnf_resources.virtual_link_info_list.append(vlink)
493 logger.debug("Returning list of virtual-link-info of size: %d", len(vnf_resources.virtual_link_info_list))
494 return vnf_resources
495
496 @rwcalstatus(ret_on_failure=[""])
497 def do_create_vdu(self, account, vdu_init):
498 vdu_id = self.get_uuid("%s_%s" % (vdu_init.name, len(self.resources[account.name].vdus)))
499 vdu = RwcalYang.VDUInfoParams()
500 vdu.vdu_id = vdu_id
501 vdu.name = vdu_init.name
502 vdu.node_id = vdu_init.node_id
503 vdu.image_id = vdu_init.image_id
504 if vdu_init.has_field('flavor_id'):
505 vdu.flavor_id = vdu_init.flavor_id
506
507 if vdu_init.has_field('vm_flavor'):
508 xx = vdu.vm_flavor.new()
509 xx.from_pbuf(vdu_init.vm_flavor.to_pbuf())
510 vdu.vm_flavor = xx
511
512 if vdu_init.has_field('guest_epa'):
513 xx = vdu.guest_epa.new()
514 xx.from_pbuf(vdu_init.guest_epa.to_pbuf())
515 vdu.guest_epa = xx
516
517 if vdu_init.has_field('vswitch_epa'):
518 xx = vdu.vswitch_epa.new()
519 xx.from_pbuf(vdu_init.vswitch_epa.to_pbuf())
520 vdu.vswitch_epa = xx
521
522 if vdu_init.has_field('hypervisor_epa'):
523 xx = vdu.hypervisor_epa.new()
524 xx.from_pbuf(vdu_init.hypervisor_epa.to_pbuf())
525 vdu.hypervisor_epa = xx
526
527 if vdu_init.has_field('host_epa'):
528 xx = vdu.host_epa.new()
529 xx.from_pbuf(vdu_init.host_epa.to_pbuf())
530 vdu.host_epa = xx
531
532 vdu.state = 'active'
533 vdu.management_ip = socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff)))
534 vdu.public_ip = vdu.management_ip
535
536 for c in vdu_init.connection_points:
537 p = vdu.connection_points.add()
538 p.connection_point_id = self.get_uuid(c.name)
539 p.name = c.name
540 p.vdu_id = vdu_id
541 p.state = 'active'
542 p.ip_address = socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff)))
543 p.virtual_link_id = c.virtual_link_id
544 # Need to add this connection_point to virtual link
545 vlink = self.resources[account.name].vlinks[c.virtual_link_id]
546 v = vlink.connection_points.add()
547 for field in p.fields:
548 if p.has_field(field):
549 setattr(v, field, getattr(p, field))
550
551 self.resources[account.name].vdus[vdu_id] = vdu
552 logger.debug('Created vdu: {}'.format(vdu_id))
553 return vdu_id
554
555
556 @rwstatus
557 def do_modify_vdu(self, account, vdu_modify):
558 vdu = self.resources[account.name].vdus[vdu_modify.vdu_id]
559 for c in vdu_modify.connection_points_add:
560 p = vdu.connection_points.add()
561 p.connection_point_id = self.get_uuid(c.name)
562 p.name = c.name
563 p.vdu_id = vdu.vdu_id
564 p.state = 'active'
565 p.ip_address = socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff)))
566 p.virtual_link_id = c.virtual_link_id
567 # Need to add this connection_point to virtual link
568 vlink = self.resources[account.name].vlinks[c.virtual_link_id]
569 aa = RwcalYang.VirtualLinkInfoParams_ConnectionPoints()
570 aa.connection_point_id = p.connection_point_id
571 aa.name = p.name
572 aa.virtual_link_id = vlink.virtual_link_id
573 aa.state = 'active'
574 aa.ip_address = p.ip_address
575 aa.vdu_id = p.vdu_id
576 vlink.connection_points.append(aa)
577
578 for c in vdu_modify.connection_points_remove:
579 for d in vdu.connection_points:
580 if c.connection_point_id == d.connection_point_id:
581 vdu.connection_points.remove(d)
582 break
583 for k, vlink in self.resources[account.name].vlinks.items():
584 for z in vlink.connection_points:
585 if z.connection_point_id == c.connection_point_id:
586 vlink.connection_points.remove(z)
587 break
588 logger.debug('modified vdu: {}'.format(vdu_modify.vdu_id))
589
590 @rwstatus
591 def do_delete_vdu(self, account, vdu_id):
592 vdu = self.resources[account.name].vdus.pop(vdu_id)
593 for c in vdu.connection_points:
594 vlink = self.resources[account.name].vlinks[c.virtual_link_id]
595 z = [p for p in vlink.connection_points if p.connection_point_id == c.connection_point_id]
596 assert len(z) == 1
597 vlink.connection_points.remove(z[0])
598
599 logger.debug('deleted vdu: {}'.format(vdu_id))
600
601 @rwstatus(ret_on_failure=[None])
602 def do_get_vdu(self, account, vdu_id):
603 vdu = self.resources[account.name].vdus[vdu_id]
604 logger.debug('Returning vdu-info for : {}'.format(vdu_id))
605 return vdu.copy()
606
607 @rwstatus(ret_on_failure=[""])
608 def do_get_vdu_list(self, account):
609 vnf_resources = RwcalYang.VNFResources()
610 for r in self.resources[account.name].vdus.values():
611 vdu = RwcalYang.VDUInfoParams()
612 vdu.copy_from(r)
613 vnf_resources.vdu_info_list.append(vdu)
614 logger.debug("Returning list of vdu-info of size: %d", len(vnf_resources.vdu_info_list))
615 return vnf_resources
616