3 # Copyright 2016 RIFT.IO Inc
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
27 from gi
import require_version
28 require_version('RwCal', '1.0')
30 from gi
.repository
import (
37 import rift
.cal
.rwcal_status
as rwcal_status
40 logger
= logging
.getLogger('rwcal.mock')
43 class UnknownAccountError(Exception):
47 class MissingFileError(Exception):
51 class ImageLocationError(Exception):
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
,
62 rwstatus
= rw_status
.rwstatus_from_exc_map(rwstatus_exception_map
)
63 rwcalstatus
= rwcal_status
.rwcalstatus_from_exc_map(rwstatus_exception_map
)
65 class Resources(object):
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."""
77 GObject
.Object
.__init
__(self
)
78 self
.resources
= collections
.defaultdict(Resources
)
83 raise ValueError("Name can not be None")
84 return str(uuid
.uuid3(uuid
.NAMESPACE_DNS
, name
))
87 def do_init(self
, rwlog_ctx
):
88 if not any(isinstance(h
, rwlogger
.RwLogger
) for h
in logger
.handlers
):
91 category
="rw-cal-log",
92 subcategory
="rwcal.mock",
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
)
105 @rwstatus(ret_on_failure
=[None])
106 def do_validate_cloud_creds(self
, account
):
108 Validates the cloud account credentials for the specified account.
109 If creds are not valid, returns an error code & reason string
111 account - a cloud account to validate
114 Validation Code and Details String
116 status
= RwcalYang
.CloudConnectionStatus(
123 @rwstatus(ret_on_failure
=[None])
124 def do_get_management_network(self
, account
):
126 Returns the management network
128 @param account - a cloud account
131 raise NotImplementedError()
134 def do_create_tenant(self
, account
, name
):
138 @param name - name to assign to the tenant.
140 raise NotImplementedError()
143 def do_delete_tenant(self
, account
, tenant_id
):
147 @param tenant_id - id of tenant to be deleted.
149 raise NotImplementedError()
151 @rwstatus(ret_on_failure
=[[]])
152 def do_get_tenant_list(self
, account
):
157 raise NotImplementedError()
160 def do_create_role(self
, account
, name
):
164 @param name - name to assign to the role.
166 raise NotImplementedError()
169 def do_delete_role(self
, account
, role_id
):
173 @param role_id - id of role to be deleted.
175 raise NotImplementedError()
177 @rwstatus(ret_on_failure
=[[]])
178 def do_get_role_list(self
, account
):
183 raise NotImplementedError()
185 @rwstatus(ret_on_failure
=[None])
186 def do_create_image(self
, account
, image
):
190 @param account - cloud account information
191 @param image - information about the image
193 if image
.location
is None:
194 raise ImageLocationError("uninitialized image location")
196 if not os
.path
.exists(image
.location
):
197 raise MissingFileError("{} does not exist".format(image
.location
))
199 image
.id = self
.get_uuid(image
.name
)
201 self
.resources
[account
.name
].images
[image
.id] = image
202 logger
.debug('created image: {}'.format(image
.id))
206 def do_delete_image(self
, account
, image_id
):
210 @param image_id - Instance id of VM image to be deleted.
212 if account
.name
not in self
.resources
:
213 raise UnknownAccountError()
215 del self
.resources
[account
.name
].images
[image_id
]
217 @rwstatus(ret_on_failure
=[None])
218 def do_get_image(self
, account
, image_id
):
219 return self
.resources
[account
.name
].images
[image_id
]
221 @rwstatus(ret_on_failure
=[[]])
222 def do_get_image_list(self
, account
):
224 Return a list of the names of all available images.
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'):
233 image_entry
.checksum
= image
.checksum
234 boxed_image_list
.imageinfo_list
.append(image_entry
)
236 logger
.debug("Image list for {}: {}".format(account
.name
, boxed_image_list
.imageinfo_list
))
237 return boxed_image_list
240 def do_create_vm(self
, account
, vm
):
242 Create a new virtual machine.
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.
249 raise NotImplementedError()
252 def do_start_vm(self
, account
, vm_id
):
254 Start a virtual machine.
256 @param vm_id - id of VM to start
258 raise NotImplementedError()
261 def do_stop_vm(self
, account
, vm_id
):
263 Stop a virtual machine.
265 @param vm_id - id of VM to stop
267 raise NotImplementedError()
270 def do_delete_vm(self
, account
, vm_id
):
272 delete a virtual machine.
274 @param vm_id - Instance id of VM to be deleted.
276 raise NotImplementedError()
279 def do_reboot_vm(self
, account
, vm_id
):
281 reboot a virtual machine.
283 @param vm_id - Instance id of VM to be deleted.
285 raise NotImplementedError()
287 @rwstatus(ret_on_failure
=[[]])
288 def do_get_vm_list(self
, account
):
289 raise NotImplementedError()
292 def do_create_flavor(self
, account
, flavor
):
296 @param flavor - Flavor object
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
))
304 def do_delete_flavor(self
, account
, flavor_id
):
308 @param flavor_id - Flavor id to be deleted.
310 logger
.debug('Deleted flavor: {}'.format(flavor_id
))
311 self
.resources
[account
.name
].flavors
.pop(flavor_id
)
313 @rwstatus(ret_on_failure
=[None])
314 def do_get_flavor(self
, account
, flavor_id
):
316 Return the specified flavor
318 @param flavor_id - the id of the flavor to return
320 flavor
= self
.resources
[account
.name
].flavors
[flavor_id
]
321 logger
.debug('Returning flavor-info for : {}'.format(flavor_id
))
324 @rwstatus(ret_on_failure
=[[]])
325 def do_get_flavor_list(self
, account
):
327 Return a list of flavors
329 vim_resources
= RwcalYang
.VimResources()
330 for flavor
in self
.resources
[account
.name
].flavors
.values():
331 f
= RwcalYang
.FlavorInfoItem()
333 vim_resources
.flavorinfo_list
.append(f
)
334 logger
.debug("Returning list of flavor-info of size: %d", len(vim_resources
.flavorinfo_list
))
339 def do_add_host(self
, account
, host
):
340 raise NotImplementedError()
343 def do_remove_host(self
, account
, host_id
):
344 raise NotImplementedError()
346 @rwstatus(ret_on_failure
=[None])
347 def do_get_host(self
, account
, host_id
):
348 raise NotImplementedError()
350 @rwstatus(ret_on_failure
=[[]])
351 def do_get_host_list(self
, account
):
352 raise NotImplementedError()
355 def do_create_port(self
, account
, port
):
356 raise NotImplementedError()
359 def do_delete_port(self
, account
, port_id
):
360 raise NotImplementedError()
362 @rwstatus(ret_on_failure
=[None])
363 def do_get_port(self
, account
, port_id
):
364 raise NotImplementedError()
366 @rwstatus(ret_on_failure
=[[]])
367 def do_get_port_list(self
, account
):
368 raise NotImplementedError()
371 def do_create_network(self
, account
, network
):
372 raise NotImplementedError()
375 def do_delete_network(self
, account
, network_id
):
376 raise NotImplementedError()
378 @rwstatus(ret_on_failure
=[None])
379 def do_get_network(self
, account
, network_id
):
380 raise NotImplementedError()
382 @rwstatus(ret_on_failure
=[[]])
383 def do_get_network_list(self
, account
):
384 raise NotImplementedError()
386 def create_default_resources(self
, account
):
388 Create default resources
391 ### Add virtual links
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)
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
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)
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
)
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
)
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
)
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
)
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
)
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
))
470 self
.resources
[account
.name
].vlinks
[vlink_id
] = vlink
471 logger
.debug('created virtual-link: {}'.format(vlink_id
))
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
))
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
))
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()
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
))
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()
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
507 if vdu_init
.has_field('vm_flavor'):
508 xx
= vdu
.vm_flavor
.new()
509 xx
.from_pbuf(vdu_init
.vm_flavor
.to_pbuf())
512 if vdu_init
.has_field('guest_epa'):
513 xx
= vdu
.guest_epa
.new()
514 xx
.from_pbuf(vdu_init
.guest_epa
.to_pbuf())
517 if vdu_init
.has_field('vswitch_epa'):
518 xx
= vdu
.vswitch_epa
.new()
519 xx
.from_pbuf(vdu_init
.vswitch_epa
.to_pbuf())
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
527 if vdu_init
.has_field('host_epa'):
528 xx
= vdu
.host_epa
.new()
529 xx
.from_pbuf(vdu_init
.host_epa
.to_pbuf())
533 vdu
.management_ip
= socket
.inet_ntoa(struct
.pack('>I', random
.randint(1, 0xffffffff)))
534 vdu
.public_ip
= vdu
.management_ip
536 for c
in vdu_init
.connection_points
:
537 p
= vdu
.connection_points
.add()
538 p
.connection_point_id
= self
.get_uuid(c
.name
)
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
))
551 self
.resources
[account
.name
].vdus
[vdu_id
] = vdu
552 logger
.debug('Created vdu: {}'.format(vdu_id
))
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
)
563 p
.vdu_id
= vdu
.vdu_id
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
572 aa
.virtual_link_id
= vlink
.virtual_link_id
574 aa
.ip_address
= p
.ip_address
576 vlink
.connection_points
.append(aa
)
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
)
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
)
588 logger
.debug('modified vdu: {}'.format(vdu_modify
.vdu_id
))
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
]
597 vlink
.connection_points
.remove(z
[0])
599 logger
.debug('deleted vdu: {}'.format(vdu_id
))
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
))
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()
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
))