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.
19 @author Varun Prasad (varun.prasad@riftio.com)
27 import multiprocessing
35 from gi
import require_version
36 require_version('RwCal', '1.0')
38 from gi
.repository
import RwcalYang
39 from gi
.repository
.RwTypes
import RwStatus
40 # import rift.cal.server as cal_server
45 logger
= logging
.getLogger('rwcal')
46 logging
.basicConfig(level
=logging
.INFO
)
49 class CloudConfig(object):
50 def __init__(self
, cal
, account
):
52 self
.account
= account
54 def check_state(self
, object_id
, object_api
, expected_state
, state_attr_name
="state"):
55 """For a given object (Vm, port etc) checks if the object has
56 reached the expected state.
58 get_object
= getattr(self
.cal
, object_api
)
59 for i
in range(100): # 100 poll iterations...
60 rc
, rs
= get_object(self
.account
, object_id
)
62 curr_state
= getattr(rs
, state_attr_name
)
63 if curr_state
== expected_state
:
68 rc
, rs
= get_object(self
.account
, object_id
)
69 assert rc
== RwStatus
.SUCCESS
70 assert getattr(rs
, state_attr_name
) == expected_state
72 def start_server(self
):
75 def stop_server(self
):
83 def _account(self
, option
):
99 def virtual_link(self
):
103 class Aws(CloudConfig
):
104 def __init__(self
, option
):
107 option (OptionParser): OptionParser instance.
109 self
.image_id
= 'ami-7070231a'
110 self
.virtual_link_id
= None
111 self
.flavor_id
= None
114 super().__init
__(self
._cal
(), self
._account
(option
))
118 Loads rw.cal plugin via libpeas
120 plugin
= rw_peas
.PeasPlugin('rwcal_aws', 'RwCal-1.0')
122 engine
, info
, extension
= plugin()
124 # Get the RwLogger context
125 rwloggerctx
= rwlogger
.RwLog
.Ctx
.new("Cal-Log")
127 cal
= plugin
.get_interface("Cloud")
129 rc
= cal
.init(rwloggerctx
)
130 assert rc
== RwStatus
.SUCCESS
132 logger
.error("ERROR:Cal plugin instantiation failed. Aborting tests")
134 logger
.info("AWS Cal plugin successfully instantiated")
137 def _account(self
, option
):
140 option (OptionParser): OptionParser instance.
145 account
= RwcalYang
.CloudAccount
.from_dict({
146 "account_type": "aws",
148 "key": option
.aws_user
,
149 "secret": option
.aws_password
,
150 "region": option
.aws_region
,
151 "availability_zone": option
.aws_zone
,
152 "ssh_key": option
.aws_ssh_key
163 flavor
= RwcalYang
.FlavorInfoItem
.from_dict({
164 "name": str(uuid
.uuid4()),
175 """Provide AWS specific VDU config.
180 vdu
= RwcalYang
.VDUInitParams
.from_dict({
181 "name": str(uuid
.uuid4()),
182 "node_id": "123456789012345",
183 "image_id": self
.image_id
,
184 "flavor_id": "t2.micro"
187 c1
= vdu
.connection_points
.add()
188 c1
.name
= str(uuid
.uuid4())
189 c1
.virtual_link_id
= self
.virtual_link_id
194 raise NotImplementedError("Image create APIs are not implemented for AWS")
196 def virtual_link(self
):
197 """Provide Vlink config
202 vlink
= RwcalYang
.VirtualLinkReqParams
.from_dict({
203 "name": str(uuid
.uuid4()),
204 "subnet": '172.31.64.0/20',
210 class Cloudsim(CloudConfig
):
211 def __init__(self
, option
):
213 self
.virtual_link_id
= None
214 self
.flavor_id
= None
217 self
.server_process
= None
220 super().__init
__(self
._cal
(), self
._account
(option
))
222 def _md5(fname
, blksize
=1048576):
223 hash_md5
= hashlib
.md5()
224 with
open(fname
, "rb") as f
:
225 for chunk
in iter(lambda: f
.read(blksize
), b
""):
226 hash_md5
.update(chunk
)
227 return hash_md5
.hexdigest()
229 def start_server(self
):
230 logger
= logging
.getLogger(__name__
)
231 server
= cal_server
.CloudsimServerOperations(logger
)
232 self
.server_process
= multiprocessing
.Process(
233 target
=server
.start_server
,
235 self
.server_process
.start()
237 # Sleep till the backup store is set up
240 def stop_server(self
):
241 self
.server_process
.terminate()
243 # If the process is not killed within the timeout, send a SIGKILL.
245 if self
.server_process
.is_alive():
246 os
.kill(self
.server_process
.pid
, signal
.SIGKILL
)
250 Loads rw.cal plugin via libpeas
252 plugin
= rw_peas
.PeasPlugin('rwcal_cloudsimproxy', 'RwCal-1.0')
253 engine
, info
, extension
= plugin()
255 # Get the RwLogger context
256 rwloggerctx
= rwlogger
.RwLog
.Ctx
.new("Cal-Log")
258 cal
= plugin
.get_interface("Cloud")
260 rc
= cal
.init(rwloggerctx
)
261 assert rc
== RwStatus
.SUCCESS
263 logger
.error("ERROR:Cal plugin instantiation failed. Aborting tests")
265 logger
.info("Cloudsim Cal plugin successfully instantiated")
268 def _account(self
, option
):
271 option (OptionParser): OptionParser instance.
276 account
= RwcalYang
.CloudAccount
.from_dict({
278 'account_type':'cloudsim_proxy'})
283 """Provides Image config for openstack.
288 image
= RwcalYang
.ImageInfoItem
.from_dict({
289 "name": str(uuid
.uuid4()),
290 "location": os
.path
.join(os
.getenv("RIFT_ROOT"), "images/rift-root-latest.qcow2"),
291 "disk_format": "qcow2",
292 "container_format": "bare",
293 "checksum": self
._md
5(os
.path
.join(os
.getenv("RIFT_ROOT"), "images/rift-root-latest.qcow2")),
298 """Flavor config for openstack
303 flavor
= RwcalYang
.FlavorInfoItem
.from_dict({
304 "name": str(uuid
.uuid4()),
314 """Returns VDU config
319 vdu
= RwcalYang
.VDUInitParams
.from_dict({
320 "name": str(uuid
.uuid4()),
321 "node_id": "123456789012345",
322 "image_id": self
.image_id
,
323 "flavor_id": self
.flavor_id
,
326 c1
= vdu
.connection_points
.add()
327 c1
.name
= str(uuid
.uuid4())
328 c1
.virtual_link_id
= self
.virtual_link_id
332 def virtual_link(self
):
333 """vlink config for Openstack
338 vlink
= RwcalYang
.VirtualLinkReqParams
.from_dict({
339 "name": str(uuid
.uuid4()),
340 "subnet": '192.168.1.0/24',
346 class Openstack(CloudConfig
):
347 def __init__(self
, option
):
350 option (OptionParser)
353 self
.virtual_link_id
= None
354 self
.flavor_id
= None
357 super().__init
__(self
._cal
(), self
._account
(option
))
361 Loads rw.cal plugin via libpeas
363 plugin
= rw_peas
.PeasPlugin('rwcal_openstack', 'RwCal-1.0')
364 engine
, info
, extension
= plugin()
366 # Get the RwLogger context
367 rwloggerctx
= rwlogger
.RwLog
.Ctx
.new("Cal-Log")
369 cal
= plugin
.get_interface("Cloud")
371 rc
= cal
.init(rwloggerctx
)
372 assert rc
== RwStatus
.SUCCESS
374 logger
.error("ERROR:Cal plugin instantiation failed. Aborting tests")
376 logger
.info("Openstack Cal plugin successfully instantiated")
379 def _account(self
, option
):
380 """Cloud account information for Account
385 acct
= RwcalYang
.CloudAccount
.from_dict({
386 "account_type": "openstack",
388 "key": option
.os_user
,
389 "secret": option
.os_password
,
390 "auth_url": 'http://{}:5000/v3/'.format(option
.os_host
),
391 "tenant": option
.os_tenant
,
392 "mgmt_network": option
.os_network
398 def _md5(self
, fname
, blksize
=1048576):
399 hash_md5
= hashlib
.md5()
400 with
open(fname
, "rb") as f
:
401 for chunk
in iter(lambda: f
.read(blksize
), b
""):
402 hash_md5
.update(chunk
)
403 return hash_md5
.hexdigest()
406 """Provides Image config for openstack.
411 image
= RwcalYang
.ImageInfoItem
.from_dict({
412 "name": str(uuid
.uuid4()),
413 "location": os
.path
.join(os
.getenv("RIFT_ROOT"), "images/rift-root-latest.qcow2"),
414 "disk_format": "qcow2",
415 "container_format": "bare",
416 "checksum": self
._md
5(os
.path
.join(os
.getenv("RIFT_ROOT"), "images/rift-root-latest.qcow2")),
421 """Flavor config for openstack
426 flavor
= RwcalYang
.FlavorInfoItem
.from_dict({
427 "name": str(uuid
.uuid4()),
434 "cpu_pinning_policy": "DEDICATED",
435 "cpu_thread_pinning_policy": "SEPARATE",
439 flavor
.guest_epa
.numa_node_policy
.node_cnt
= numa_node_count
440 for i
in range(numa_node_count
):
441 node
= flavor
.guest_epa
.numa_node_policy
.node
.add()
447 node
.memory_mb
= 8196
449 dev
= flavor
.guest_epa
.pcie_device
.add()
450 dev
.device_id
= "PCI_10G_ALIAS"
456 """Returns VDU config
461 vdu
= RwcalYang
.VDUInitParams
.from_dict({
462 "name": str(uuid
.uuid4()),
463 "node_id": "123456789012345",
464 "image_id": self
.image_id
,
465 "flavor_id": self
.flavor_id
,
468 c1
= vdu
.connection_points
.add()
469 c1
.name
= str(uuid
.uuid4())
470 c1
.virtual_link_id
= self
.virtual_link_id
474 def virtual_link(self
):
475 """vlink config for Openstack
480 vlink
= RwcalYang
.VirtualLinkReqParams
.from_dict({
481 "name": str(uuid
.uuid4()),
482 "subnet": '192.168.1.0/24',
488 @pytest.fixture(scope
="module", params
=[Openstack
], ids
=lambda val
: val
.__name
__)
489 def cloud_config(request
):
490 return request
.param(request
.config
.option
)
493 @pytest.mark
.incremental
496 def test_start_server(self
, cloud_config
):
497 cloud_config
.start_server()
499 def test_flavor_apis(self
, cloud_config
):
502 1. If the new flavor is created and available via read APIs
503 2. Verifies the READ APIs
505 account
= cloud_config
.account
506 cal
= cloud_config
.cal
508 status
, new_flavor_id
= cal
.create_flavor(account
, cloud_config
.flavor())
509 cloud_config
.flavor_id
= new_flavor_id
510 assert status
== RwStatus
.SUCCESS
512 status
, flavors
= cal
.get_flavor_list(account
)
513 assert status
== RwStatus
.SUCCESS
516 for flavor
in flavors
.flavorinfo_list
:
517 status
, flavor_single
= cal
.get_flavor(account
, flavor
.id)
518 assert status
== RwStatus
.SUCCESS
519 assert flavor
.id == flavor_single
.id
520 ids
.append(flavor
.id)
522 assert new_flavor_id
in ids
524 def test_image_apis(self
, cloud_config
):
527 1. If the new image is created and available via read APIs
528 2. Verifies the READ APIs
530 account
= cloud_config
.account
531 cal
= cloud_config
.cal
533 if type(cloud_config
) is Aws
:
535 new_image_id
= "ami-7070231a"
537 status
, new_image_id
= cal
.create_image(account
, cloud_config
.image())
538 cloud_config
.image_id
= new_image_id
539 assert status
== RwStatus
.SUCCESS
540 cloud_config
.check_state(new_image_id
, "get_image", "active")
543 status
, images
= cal
.get_image_list(account
)
546 for image
in images
.imageinfo_list
:
547 status
, image_single
= cal
.get_image(account
, image
.id)
548 assert status
== RwStatus
.SUCCESS
549 assert image_single
.id == image
.id
552 assert new_image_id
in ids
554 def test_virtual_link_create(self
, cloud_config
):
557 1. If the new Vlink is created and available via read APIs
558 2. Verifies the READ APIs
560 account
= cloud_config
.account
561 cal
= cloud_config
.cal
563 status
, new_vlink_id
= cal
.create_virtual_link(account
, cloud_config
.virtual_link())
564 cloud_config
.virtual_link_id
= new_vlink_id
565 assert status
.status
== RwStatus
.SUCCESS
566 cloud_config
.check_state(new_vlink_id
, "get_virtual_link", "active")
568 status
, vlinks
= cal
.get_virtual_link_list(account
)
569 assert status
== RwStatus
.SUCCESS
572 for vlink
in vlinks
.virtual_link_info_list
:
573 status
, vlink_single
= cal
.get_virtual_link(account
, vlink
.virtual_link_id
)
574 assert status
== RwStatus
.SUCCESS
575 assert vlink_single
.virtual_link_id
== vlink
.virtual_link_id
576 ids
.append(vlink
.virtual_link_id
)
578 assert new_vlink_id
in ids
580 def test_vdu_apis(self
, cloud_config
):
583 1. If the new VDU is created and available via read APIs
584 2. Verifies the READ APIs
586 account
= cloud_config
.account
587 cal
= cloud_config
.cal
589 status
, new_vdu_id
= cal
.create_vdu(account
, cloud_config
.vdu())
590 cloud_config
.vdu_id
= new_vdu_id
591 assert status
.status
== RwStatus
.SUCCESS
592 cloud_config
.check_state(new_vdu_id
, "get_vdu", "active")
594 status
, vdus
= cal
.get_vdu_list(account
)
595 assert status
== RwStatus
.SUCCESS
598 for vdu
in vdus
.vdu_info_list
:
599 status
, vdu_single
= cal
.get_vdu(account
, vdu
.vdu_id
)
600 assert status
== RwStatus
.SUCCESS
601 assert vdu_single
.vdu_id
== vdu
.vdu_id
602 ids
.append(vdu
.vdu_id
)
604 assert new_vdu_id
in ids
606 def test_modify_vdu_api(self
, cloud_config
):
607 account
= cloud_config
.account
608 cal
= cloud_config
.cal
610 vdu_modify
= RwcalYang
.VDUModifyParams()
611 vdu_modify
.vdu_id
= cloud_config
.vdu_id
612 c1
= vdu_modify
.connection_points_add
.add()
613 c1
.name
= "c_modify1"
615 c1
.virtual_link_id
= cloud_config
.virtual_link_id
617 status
= cal
.modify_vdu(account
, vdu_modify
)
618 assert status
== RwStatus
.SUCCESS
620 @pytest.mark
.incremental
621 class TestCalTeardown
:
622 def test_flavor_delete(self
, cloud_config
):
625 1. If flavor is deleted
627 account
= cloud_config
.account
628 cal
= cloud_config
.cal
630 if type(cloud_config
) != Aws
:
631 status
= cal
.delete_flavor(account
, cloud_config
.flavor_id
)
632 assert status
== RwStatus
.SUCCESS
634 def test_image_delete(self
, cloud_config
):
637 1. If image is deleted
639 account
= cloud_config
.account
640 cal
= cloud_config
.cal
642 if type(cloud_config
) != Aws
:
643 status
= cal
.delete_image(account
, cloud_config
.image_id
)
644 assert status
== RwStatus
.SUCCESS
646 def test_virtual_link_delete(self
, cloud_config
):
649 1. If VLink is deleted
651 account
= cloud_config
.account
652 cal
= cloud_config
.cal
654 status
= cal
.delete_virtual_link(account
, cloud_config
.virtual_link_id
)
655 assert status
== RwStatus
.SUCCESS
657 def test_delete_vdu(self
, cloud_config
):
662 account
= cloud_config
.account
663 cal
= cloud_config
.cal
665 status
= cal
.delete_vdu(account
, cloud_config
.vdu_id
)
666 assert status
== RwStatus
.SUCCESS
668 def test_stop_server(self
, cloud_config
):
669 cloud_config
.stop_server()