Skip to content

Commit 51c1c0e

Browse files
Merge pull request #87 from openvstorage/develop
Promote develop
2 parents 46c143a + 8a3b646 commit 51c1c0e

35 files changed

+2039
-567
lines changed

docs/guide.md

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
## Description
44

55
This repository contains the automation library for Open vStorage.
6-
This library delegates component creation/removal to the REST API of Open vStorage through Python code.
76

87
## System requirements
98

@@ -26,17 +25,36 @@ This library delegates component creation/removal to the REST API of Open vStora
2625
- Automation library HELPERS logging file `/var/log/ovs/helpers.log`
2726

2827
## Sections
28+
### Api Library
29+
This library delegates component creation/removal to the REST API of Open vStorage through Python code.
30+
31+
#### Helpers section
32+
Contains functions to assist in removal, setup and validation of components such as backends, disks, storagerouters and -drivers, as well as gathering of metadata etc.
33+
34+
#### Remove section
35+
Contains functions for removal of arakoon clusters, backends, roles, vDisks and vPools from Open vStorage.
36+
37+
#### Setup section
38+
Contains functions to set up new arakoon clusters, backends, domains, proxies, roles, vDisks and vPools in Open vStorage.
2939

30-
### Helpers section
31-
Contains helping function that provide required meta information during setup, removal or validation
40+
#### Validation section
41+
Contains function to validate functionality of Open vStorage components.
42+
This includes decorators for checking prerequisites of functions throughout the package.
3243

33-
### Remove section
34-
Contains removal functions that makes it possible to remove components from Open vStorage
44+
###Scenario helpers section
45+
Classes in this section are used to execute the actual tests (referred to as[scenarios](#header_scenarios))
3546

36-
### Setup section
37-
Contains setup functions that makes it possible to add components to Open vStorage
47+
###<a name="header_scenarios"></a>Scenarios section
48+
This section contains code for testing a variety of integration scenarios.\
49+
Currently present tests:
50+
- api checkup post-reboot
51+
- several arakoon related checks
52+
- addition and removal of
53+
- backends
54+
- storagerouters
55+
- vDisks, vMachines and vPools
56+
- health checks
57+
- installation tests
58+
- hypervisor tests
3859

39-
### Validation section
40-
Provides validation for setup or removal of Open vStorage components.
41-
E.g. when a vPool is added, the required components are checked if they are present
4260

helpers/albanode.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,32 @@
1313
#
1414
# Open vStorage is distributed in the hope that it will be useful,
1515
# but WITHOUT ANY WARRANTY of any kind.
16+
1617
from ovs.dal.hybrids.albanode import AlbaNode
1718
from ovs.dal.lists.albanodelist import AlbaNodeList
1819
from ovs.extensions.generic.logger import Logger
20+
from ..helpers.ci_constants import CIConstants
1921

2022

21-
class AlbaNodeHelper(object):
23+
class AlbaNodeHelper(CIConstants):
2224
"""
2325
Alba node helper class
2426
"""
2527

2628
LOGGER = Logger('helpers-ci_albanode')
2729
IGNORE_KEYS = ('_error', '_duration', '_version', '_success')
2830

29-
@staticmethod
30-
def _map_alba_nodes(api):
31+
@classmethod
32+
def _map_alba_nodes(cls, *args, **kwargs):
3133
"""
3234
Will map the alba_node_id with its guid counterpart and return the map dict
33-
:param api: specify a valid api connection to the setup
34-
:type api: helpers.api.OVSClient
3535
"""
36-
mapping = {}
3736

37+
mapping = {}
3838
options = {
3939
'contents': 'node_id,_relations',
4040
}
41-
response = api.get(
41+
response = cls.api.get(
4242
api='alba/nodes',
4343
params=options
4444
)

helpers/api.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -193,17 +193,17 @@ def _call(self, api, params, func, **kwargs):
193193
if self._volatile_client is not None:
194194
self._token = self._volatile_client.get(self._key)
195195
first_connect = self._token is None
196-
headers, url = self._prepare(params=params)
196+
headers, _url = self._prepare(params=params)
197197
try:
198-
return self._process(func(url=url.format(api), headers=headers, verify=self._verify, **kwargs))
198+
return self._process(func(url=_url.format(api), headers=headers, verify=self._verify, **kwargs))
199199
except ForbiddenException:
200200
if self._volatile_client is not None:
201201
self._volatile_client.delete(self._key)
202202
if first_connect is True: # First connect, so no token was present yet, so no need to try twice without token
203203
raise
204204
self._token = None
205-
headers, url = self._prepare(params=params)
206-
return self._process(func(url=url.format(api), headers=headers, verify=self._verify, **kwargs))
205+
headers, _url = self._prepare(params=params)
206+
return self._process(func(url=_url.format(api), headers=headers, verify=self._verify, **kwargs))
207207
except Exception:
208208
if self._volatile_client is not None:
209209
self._volatile_client.delete(self._key)
@@ -264,7 +264,12 @@ def wait_for_task(self, task_id, timeout=None):
264264
if timeout is not None and timeout < (time.time() - start):
265265
raise TimeOutError('Waiting for task {0} has timed out.'.format(task_id))
266266
task_metadata = self.get('/tasks/{0}/'.format(task_id))
267-
print task_metadata
267+
output = 'Task with ID: {0: >40}, current status: {1: >8}, ready: {2: >2}. Result data: {3}'.format(task_metadata['id'],
268+
task_metadata['status'],
269+
task_metadata['successful'],
270+
task_metadata['result'])
271+
print output
272+
OVSClient._logger.debug(output)
268273
finished = task_metadata['status'] in ('FAILURE', 'SUCCESS')
269274
if finished is False:
270275
if task_metadata != previous_metadata:
@@ -286,8 +291,6 @@ def _to_json(dict_or_json):
286291
:return: json data
287292
:rtype: string
288293
"""
289-
try:
290-
json_object = json.loads(str(dict_or_json))
291-
except ValueError:
294+
if isinstance(dict_or_json, dict):
292295
return json.dumps(dict_or_json)
293-
return json_object
296+
return dict_or_json

helpers/backend.py

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,17 @@
1313
#
1414
# Open vStorage is distributed in the hope that it will be useful,
1515
# but WITHOUT ANY WARRANTY of any kind.
16+
17+
from ovs.dal.hybrids.albabackend import AlbaBackend
1618
from ovs.dal.lists.albabackendlist import AlbaBackendList
1719
from ovs.dal.lists.backendlist import BackendList
1820
from ovs.dal.lists.backendtypelist import BackendTypeList
19-
from ovs.dal.hybrids.albabackend import AlbaBackend
2021
from ovs.extensions.generic.logger import Logger
22+
from ..helpers.ci_constants import CIConstants
2123
from ..helpers.exceptions import PresetNotFoundError, AlbaBackendNotFoundError
2224

2325

24-
class BackendHelper(object):
26+
class BackendHelper(CIConstants):
2527
"""
2628
BackendHelper class
2729
"""
@@ -127,45 +129,40 @@ def get_albabackend_by_name(albabackend_name):
127129
BackendHelper.LOGGER.error(error_msg)
128130
raise NameError(error_msg)
129131

130-
@staticmethod
131-
def get_asd_safety(albabackend_guid, asd_id, api):
132+
@classmethod
133+
def get_asd_safety(cls, albabackend_guid, asd_id, *args, **kwargs):
132134
"""
133135
Request the calculation of the disk safety
134136
:param albabackend_guid: guid of the alba backend
135137
:type albabackend_guid: str
136138
:param asd_id: id of the asd
137139
:type asd_id: str
138-
:param api: specify a valid api connection to the setup
139-
:type api: helpers.api.OVSClient
140140
:return: asd safety
141141
:rtype: dict
142142
"""
143143
params = {'asd_id': asd_id}
144-
task_guid = api.get('alba/backends/{0}/calculate_safety'.format(albabackend_guid), params=params)
145-
result = api.wait_for_task(task_id=task_guid, timeout=30)
144+
task_guid = cls.api.get('alba/backends/{0}/calculate_safety'.format(albabackend_guid), params=params)
145+
result = cls.api.wait_for_task(task_id=task_guid, timeout=30)
146146

147147
if result[0] is False:
148148
errormsg = "Calculate safety for '{0}' failed with '{1}'".format(asd_id, result[1])
149149
BackendHelper.LOGGER.error(errormsg)
150150
raise RuntimeError(errormsg)
151151
return result[1]
152152

153-
@staticmethod
154-
def get_backend_local_stack(albabackend_name, api):
153+
@classmethod
154+
def get_backend_local_stack(cls, albabackend_name, *args, **kwargs):
155155
"""
156156
Fetches the local stack property of a backend
157157
158158
:param albabackend_name: backend name
159159
:type albabackend_name: str
160-
:param api: specify a valid api connection to the setup
161-
:type api: helpers.api.OVSClient
162160
"""
163161
options = {
164162
'contents': 'local_stack',
165163
}
166-
return api.get(api='/alba/backends/{0}/'.format(BackendHelper.get_alba_backend_guid_by_name(albabackend_name)),
167-
params={'queryparams': options}
168-
)
164+
return cls.api.get(api='/alba/backends/{0}/'.format(BackendHelper.get_alba_backend_guid_by_name(albabackend_name)),
165+
params={'queryparams': options})
169166

170167
@staticmethod
171168
def get_alba_backends():

helpers/ci_constants.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Copyright (C) 2016 iNuron NV
2+
#
3+
# This file is part of Open vStorage Open Source Edition (OSE),
4+
# as available from
5+
#
6+
# http://www.openvstorage.org and
7+
# http://www.openvstorage.com.
8+
#
9+
# This file is free software; you can redistribute it and/or modify it
10+
# under the terms of the GNU Affero General Public License v3 (GNU AGPLv3)
11+
# as published by the Free Software Foundation, in version 3 as it comes
12+
# in the LICENSE.txt file of the Open vStorage OSE distribution.
13+
#
14+
# Open vStorage is distributed in the hope that it will be useful,
15+
# but WITHOUT ANY WARRANTY of any kind.
16+
import json
17+
from ci.api_lib.helpers.api import OVSClient
18+
19+
20+
class CIConstants(object):
21+
"""
22+
Collection of multiple constants and constant related instances
23+
"""
24+
25+
CONFIG_LOC = "/opt/OpenvStorage/ci/config/setup.json"
26+
TEST_SCENARIO_LOC = "/opt/OpenvStorage/ci/scenarios/"
27+
TESTRAIL_LOC = "/opt/OpenvStorage/ci/config/testrail.json"
28+
29+
with open(CONFIG_LOC, 'r') as JSON_CONFIG:
30+
SETUP_CFG = json.load(JSON_CONFIG)
31+
32+
HYPERVISOR_INFO = SETUP_CFG['ci'].get('hypervisor')
33+
DOMAIN_INFO = SETUP_CFG['setup']['domains']
34+
BACKEND_INFO = SETUP_CFG['setup']['backends']
35+
STORAGEROUTER_INFO = SETUP_CFG['setup']['storagerouters']
36+
37+
class classproperty(property):
38+
def __get__(self, cls, owner):
39+
return classmethod(self.fget).__get__(None, owner)()
40+
41+
@classproperty
42+
def api(cls):
43+
return OVSClient(cls.SETUP_CFG['ci']['grid_ip'],
44+
cls.SETUP_CFG['ci']['user']['api']['username'],
45+
cls.SETUP_CFG['ci']['user']['api']['password'])
46+
47+
@classmethod
48+
def get_vpool_names(cls):
49+
names = []
50+
for sr_ip, items in cls.STORAGEROUTER_INFO.iteritems():
51+
vpools = items.get('vpools')
52+
for vp_name, vp_info in vpools.iteritems():
53+
if vp_name not in names:
54+
names.append(vp_name)
55+
return names

helpers/disk.py

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,10 @@ class DiskHelper(object):
2424
DiskHelper class
2525
"""
2626

27-
def __init__(self):
28-
pass
29-
3027
@staticmethod
3128
def get_diskpartitions_by_guid(diskguid):
3229
"""
3330
Fetch disk partitions by disk guid
34-
3531
:param diskguid: ip address of a storagerouter
3632
:type diskguid: str
3733
:return: list of DiskPartition Objects
@@ -41,59 +37,53 @@ def get_diskpartitions_by_guid(diskguid):
4137
return [dp for dp in DiskPartitionList.get_partitions() if dp.disk_guid == diskguid]
4238

4339
@staticmethod
44-
def get_roles_from_disks(storagerouter_ip=None):
40+
def get_roles_from_disks(storagerouter_guid=None):
4541
"""
4642
Fetch disk roles from all disks with optional storagerouter_ip
47-
48-
:param storagerouter_ip: ip address of a storage router
49-
:type storagerouter_ip: str
43+
:param storagerouter_guid: guid of a storage router
44+
:type storagerouter_guid: str
5045
:return: list of lists with roles
5146
:rtype: list > list
5247
"""
53-
if not storagerouter_ip:
48+
if not storagerouter_guid:
5449
return [partition.roles for disk in DiskList.get_disks() for partition in disk.partitions]
5550
else:
56-
storagerouter_guid = StoragerouterHelper.get_storagerouter_guid_by_ip(storagerouter_ip)
5751
return [partition.roles for disk in DiskList.get_disks()
5852
if disk.storagerouter_guid == storagerouter_guid for partition in disk.partitions]
5953

6054
@staticmethod
61-
def get_disk_by_diskname(storagerouter_ip, disk_name):
55+
def get_disk_by_diskname(storagerouter_guid, disk_name):
6256
"""
63-
Get a disk object by storagerouter ip and disk name
64-
65-
:param storagerouter_ip: ip address of a storage router
66-
:type storagerouter_ip: str
57+
Get a disk object by storagerouter guid and disk name
58+
:param storagerouter_guid: guid address of a storage router
59+
:type storagerouter_guid: str
6760
:param disk_name: name of a disk (e.g. sda)
6861
:type disk_name: str
6962
:return: disk object
7063
:rtype: ovs.dal.hybrids.Disk
7164
"""
72-
73-
storagerouter = StoragerouterHelper.get_storagerouter_by_ip(storagerouter_ip=storagerouter_ip)
65+
storagerouter = StoragerouterHelper.get_storagerouter_by_guid(storagerouter_guid=storagerouter_guid)
7466
for disk in storagerouter.disks:
7567
if disk.name == disk_name:
7668
return disk
7769

7870
@staticmethod
79-
def get_roles_from_disk(storagerouter_ip, disk_name):
71+
def get_roles_from_disk(storagerouter_guid, disk_name):
8072
"""
8173
Get the roles from a certain disk
82-
83-
:param storagerouter_ip: ip address of a storage router
84-
:type storagerouter_ip: str
74+
:param storagerouter_guid: guid address of a storage router
75+
:type storagerouter_guid: str
8576
:param disk_name: name of a disk (e.g. sda)
8677
:type disk_name: str
8778
:return: list of roles of all partitions on a certain disk
8879
:rtype: list
8980
"""
90-
91-
disk = DiskHelper.get_disk_by_diskname(storagerouter_ip, disk_name)
81+
disk = DiskHelper.get_disk_by_diskname(storagerouter_guid, disk_name)
9282
roles_on_disk = []
9383
if disk:
9484
for diskpartition in disk.partitions:
9585
for role in diskpartition.roles:
9686
roles_on_disk.append(role)
9787
return roles_on_disk
9888
else:
99-
raise RuntimeError("Disk with name `{0}` not found on storagerouter `{1}`".format(disk_name, storagerouter_ip))
89+
raise RuntimeError("Disk with name `{0}` not found on storagerouter `{1}`".format(disk_name, storagerouter_guid))

0 commit comments

Comments
 (0)