Skip to content

Commit ff5475d

Browse files
Merge pull request #2189 from openvstorage/develop
Promote
2 parents 540fc4a + 16aee0f commit ff5475d

File tree

44 files changed

+695
-489
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+695
-489
lines changed

ovs/constants/s3.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright (C) 2018 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+
17+
S3_BASE = '/ovs/framework/hosts/{0}/s3'

ovs/dal/hybrids/servicetype.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ class ServiceType(DataObject):
2929
'ARAKOON': 'Arakoon',
3030
'ALBA_MGR': 'AlbaManager',
3131
'MD_SERVER': 'MetadataServer',
32-
'ALBA_PROXY': 'AlbaProxy'})
32+
'ALBA_PROXY': 'AlbaProxy',
33+
'ALBA_S3_TRANSACTION': 'AlbaS3Transaction'})
3334
ARAKOON_CLUSTER_TYPES = DataObject.enumerator('Arakoon_cluster_type', ['ABM', 'FWK', 'NSM', 'SD', 'CFG'])
3435

3536
__properties = [Property('name', str, unique=True, indexed=True, doc='Name of the ServiceType.')]

ovs/extensions/generic/configuration.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,16 @@
2424
import string
2525
# noinspection PyUnresolvedReferences
2626
from ovs_extensions.caching.decorators import cache_file
27+
# ConnectionException, NotFoundException are here for backwards compatibility
2728
from ovs_extensions.generic.configuration import Configuration as _Configuration, ConnectionException, NotFoundException
29+
from ovs_extensions.constants.config import CONFIG_STORE_LOCATION
30+
from ovs.extensions.generic.system import System
2831

2932

3033
class Configuration(_Configuration):
3134
"""
3235
Extends the 'default' configuration class
3336
"""
34-
ARAKOON_NAME = 'cacc'
35-
ARAKOON_NAME_UNITTEST = 'unittest-cacc'
36-
CACC_LOCATION = '/opt/OpenvStorage/config/arakoon_cacc.ini'
37-
CONFIG_STORE_LOCATION = '/opt/OpenvStorage/config/framework.json'
3837

3938
base_config = {'cluster_id': None,
4039
'external_config': None,
@@ -125,6 +124,7 @@ def initialize(cls, external_config=None, logging_target=None):
125124
base_cfg['messagequeue'][key] = value
126125
for key, value in base_cfg.iteritems():
127126
cls.set('/ovs/framework/{0}'.format(key), value, raw=False)
127+
cls.register_usage(System.get_component_identifier())
128128

129129
@classmethod
130130
@cache_file(CONFIG_STORE_LOCATION)
@@ -135,7 +135,7 @@ def read_store_info(cls):
135135
:return: The configured store
136136
:rtype: str
137137
"""
138-
with open(cls.CONFIG_STORE_LOCATION) as config_file:
138+
with open(CONFIG_STORE_LOCATION) as config_file:
139139
contents = json.load(config_file)
140140
return contents['configuration_store']
141141

ovs/extensions/generic/graphiteclient.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
# Open vStorage is distributed in the hope that it will be useful,
1515
# but WITHOUT ANY WARRANTY of any kind.
1616

17-
import time
18-
import socket
1917
from ovs.extensions.generic.configuration import Configuration
2018
from ovs_extensions.generic.configuration.exceptions import ConfigurationNotFoundException as NotFoundException
2119
from ovs_extensions.generic.graphiteclient import GraphiteClient as _graphite_client
@@ -39,14 +37,14 @@ def __init__(self, ip=None, port=None, database=None):
3937
:param database: name of the database
4038
:type database: str
4139
"""
40+
graphite_data = {}
4241
if all(p is None for p in [ip, port]):
4342
# Nothing specified
44-
try:
45-
graphite_data = Configuration.get(self.CONFIG_PATH)
46-
except NotFoundException:
43+
graphite_data = self.get_graphite_config()
44+
if not graphite_data:
4745
raise RuntimeError('No graphite data found in config path `{0}`'.format(self.CONFIG_PATH))
4846

49-
ip = ip or graphite_data['host']
47+
ip = ip or graphite_data['ip']
5048
port = port or graphite_data.get('port', 2003)
5149

5250
ExtensionsToolbox.verify_required_params(verify_keys=True,
@@ -86,3 +84,17 @@ def send_statsmonkey_data(self, sm_data, function_name):
8684
for fieldkey, fieldvalue in datapointset['fields'].items():
8785
tmp_path = '{0}.{1}'.format(path, fieldkey)
8886
self.send(tmp_path, fieldvalue)
87+
88+
@classmethod
89+
def get_graphite_config(cls):
90+
# type: () -> Dict[str, Union[str, int]]
91+
"""
92+
Retrieve the graphite config (if any)
93+
:return:
94+
"""
95+
try:
96+
graphite_data = Configuration.get(cls.CONFIG_PATH)
97+
return {'ip': graphite_data['host'],
98+
'port': graphite_data.get('port', 2003)}
99+
except NotFoundException:
100+
return {}

ovs/extensions/generic/system.py

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import os
2222
from ovs_extensions.caching.decorators import cache_file
2323
from ovs_extensions.generic.system import System as _System
24-
from ovs.extensions.packages.packagefactory import PackageFactory
2524

2625

2726
class System(_System):
@@ -30,7 +29,6 @@ class System(_System):
3029
"""
3130

3231
OVS_ID_FILE = '/etc/openvstorage_id'
33-
RELEASE_NAME_FILE = '/opt/OpenvStorage/config/release_name'
3432
_machine_id = {}
3533

3634
def __init__(self):
@@ -60,24 +58,6 @@ def read_my_machine_id(cls):
6058
with open(cls.OVS_ID_FILE, 'r') as the_file:
6159
return the_file.read().strip()
6260

63-
@classmethod
64-
def get_release_name(cls, client=None):
65-
"""
66-
Retrieve the release name
67-
:param client: Client on which to retrieve the release name
68-
:type client: ovs_extensions.generic.sshclient.SSHClient
69-
:return: The name of the release
70-
:rtype: str
71-
"""
72-
try:
73-
if client is not None:
74-
return client.run(['cat', cls.RELEASE_NAME_FILE]).strip()
75-
with open(cls.RELEASE_NAME_FILE, 'r') as the_file:
76-
return the_file.read().strip()
77-
except:
78-
manager = PackageFactory.get_manager()
79-
return manager.get_release_name()
80-
8161
@classmethod
8262
def get_my_storagerouter(cls):
8363
"""
@@ -90,3 +70,13 @@ def get_my_storagerouter(cls):
9070
if storagerouter is None:
9171
raise RuntimeError('Could not find the local StorageRouter')
9272
return storagerouter
73+
74+
@staticmethod
75+
def get_component_identifier():
76+
# type: () -> str
77+
"""
78+
Retrieve the identifier of the component
79+
:return: The ID of the component
80+
:rtype: str
81+
"""
82+
return 'framework'

ovs/extensions/generic/watcher.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import pika
2626
import uuid
2727
import argparse
28+
from ovs_extensions.constants.config import ARAKOON_NAME, CACC_LOCATION
2829
from ovs_extensions.db.arakoon.pyrakoon.pyrakoon.compat import NoGuarantee
2930
from ovs.extensions.db.arakooninstaller import ArakoonInstaller, ArakoonClusterConfig
3031
from ovs.extensions.generic.configuration import Configuration
@@ -141,9 +142,9 @@ def services_running(self):
141142
self.log_message(' Error during configuration store test: {0}'.format(ex), 2)
142143
return False
143144

144-
with open(Configuration.CACC_LOCATION) as config_file:
145+
with open(CACC_LOCATION) as config_file:
145146
contents = config_file.read()
146-
config = ArakoonClusterConfig(cluster_id=Configuration.ARAKOON_NAME, load_config=False)
147+
config = ArakoonClusterConfig(cluster_id=ARAKOON_NAME, load_config=False)
147148
config.read_config(contents=contents)
148149
client = ArakoonInstaller.build_client(config)
149150
contents = client.get(ArakoonInstaller.INTERNAL_CONFIG_KEY, consistency=NoGuarantee())
@@ -153,12 +154,12 @@ def services_running(self):
153154
except Exception as ex:
154155
self.log_message(' Configuration stored in configuration store seems to be corrupt: {0}'.format(ex), 2)
155156
return False
156-
temp_filename = '{0}~'.format(Configuration.CACC_LOCATION)
157+
temp_filename = '{0}~'.format(CACC_LOCATION)
157158
with open(temp_filename, 'w') as config_file:
158159
config_file.write(contents)
159160
config_file.flush()
160161
os.fsync(config_file)
161-
os.rename(temp_filename, Configuration.CACC_LOCATION)
162+
os.rename(temp_filename, CACC_LOCATION)
162163
Watcher.LOG_CONTENTS = contents
163164
self.log_message(' Configuration store OK', 0)
164165

ovs/extensions/packages/packagefactory.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ class PackageFactory(_PackageFactory):
2727
"""
2828
Factory class returning specialized classes
2929
"""
30+
# Allow the user to add a custom release name
31+
RELEASE_NAME_FILE = '/opt/OpenvStorage/config/release_name'
3032
_logger = Logger('extensions-packages')
3133

3234
def __init__(self):
@@ -91,3 +93,21 @@ def get_package_info(cls):
9193
'mutually_exclusive': {cls.PKG_VOLDRV_BASE, cls.PKG_VOLDRV_SERVER}}
9294
else:
9395
raise ValueError('Unsupported edition found: "{0}"'.format(edition))
96+
97+
@classmethod
98+
def get_release_name(cls, client=None):
99+
"""
100+
Retrieve the release name
101+
:param client: Client on which to retrieve the release name
102+
:type client: ovs_extensions.generic.sshclient.SSHClient
103+
:return: The name of the release
104+
:rtype: str
105+
"""
106+
try:
107+
if client is not None:
108+
return client.run(['cat', cls.RELEASE_NAME_FILE]).strip()
109+
with open(cls.RELEASE_NAME_FILE, 'r') as the_file:
110+
return the_file.read().strip()
111+
except:
112+
manager = cls.get_manager()
113+
return manager.get_release_name()

ovs/extensions/plugins/apiclient.py

Lines changed: 107 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,25 @@ def __init__(self, ip, port, credentials, timeout, log_min_duration=1):
7474
self.timeout = timeout
7575
self._log_min_duration = log_min_duration
7676

77-
def _call(self, method, url, data=None, timeout=None, clean=False):
77+
def _call(self, method, url, data=None, json=None, timeout=None, clean=False):
78+
# type: (callable, str, dict, dict, int, bool) -> any
79+
"""
80+
Calls the provided function and adds headings
81+
:param method: Method to call
82+
:type method: callable
83+
:param url: Url to call
84+
:type url: str
85+
:param data: Data to provide. This parameter will not set the JSON header so data may be interpreted differently!
86+
:type data: dict
87+
:param json: Data to provide as JSON parameters. This parameter will set the JSOn header to data will be interpreted as a JSON string
88+
:type json: dict
89+
:param timeout: Timeout to wait for a reply of the server
90+
:type timeout: int
91+
:param clean: Should the data be cleaned (metdata entries stripped from the result)
92+
:type clean: bool
93+
:return: The response
94+
:rtype: any
95+
"""
7896
if timeout is None:
7997
timeout = self.timeout
8098

@@ -86,8 +104,13 @@ def _call(self, method, url, data=None, timeout=None, clean=False):
86104
'headers': self._base_headers,
87105
'verify': False,
88106
'timeout': timeout}
89-
if data is not None:
90-
kwargs['data'] = data
107+
# Requests library can both take in 'data' or 'json' keyword.
108+
# When data is given: no extra heading is added and the data is serialized as json
109+
# When json is given: the 'Content type: Application/json' header is added.
110+
# The loop is to provide both options
111+
for key, val in [('json', json), ('data', data)]:
112+
if val is not None:
113+
kwargs[key] = val
91114
response = method(**kwargs)
92115
if response.status_code == 404:
93116
msg = 'URL not found: {0}'.format(kwargs['url'])
@@ -121,7 +144,7 @@ def _refresh(self):
121144
return self._base_url, self._base_headers
122145

123146
def extract_data(self, response_data, old_key=None):
124-
# type: (dict) -> any
147+
# type: (dict, Optional[str]) -> any
125148
"""
126149
Extract the data from the API
127150
For backwards compatibility purposes (older asd-managers might not wrap their data)
@@ -158,3 +181,83 @@ def clean(cls, data):
158181
elif isinstance(data_copy[key], dict):
159182
data_copy[key] = cls.clean(data_copy[key])
160183
return data_copy
184+
185+
def get(self, url, data=None, json=None, timeout=None, clean=False):
186+
"""
187+
Executes a GET call
188+
:param url: Url to call
189+
:type url: str
190+
:param data: Data to provide. This parameter will not set the JSON header so data may be interpreted differently!
191+
:type data: dict
192+
:param json: Data to provide as JSON parameters. This parameter will set the JSOn header to data will be interpreted as a JSON string
193+
:type json: dict
194+
:param timeout: Timeout to wait for a reply of the server
195+
:type timeout: int
196+
:param clean: Should the data be cleaned (metadata entries stripped from the result)
197+
:type clean: bool
198+
"""
199+
return self._call(method=requests.get, url=url, data=data, json=json, clean=clean, timeout=timeout)
200+
201+
def post(self, url, data=None, json=None, timeout=None, clean=False):
202+
"""
203+
Executes a POST call
204+
:param url: Url to call
205+
:type url: str
206+
:param data: Data to provide. This parameter will not set the JSON header so data may be interpreted differently!
207+
:type data: dict
208+
:param json: Data to provide as JSON parameters. This parameter will set the JSOn header to data will be interpreted as a JSON string
209+
:type json: dict
210+
:param timeout: Timeout to wait for a reply of the server
211+
:type timeout: int
212+
:param clean: Should the data be cleaned (metadata entries stripped from the result)
213+
:type clean: bool
214+
"""
215+
return self._call(method=requests.post, url=url, data=data, json=json, clean=clean, timeout=timeout)
216+
217+
def put(self, url, data=None, json=None, timeout=None, clean=False):
218+
"""
219+
Executes a PUT call
220+
:param url: Url to call
221+
:type url: str
222+
:param data: Data to provide. This parameter will not set the JSON header so data may be interpreted differently!
223+
:type data: dict
224+
:param json: Data to provide as JSON parameters. This parameter will set the JSOn header to data will be interpreted as a JSON string
225+
:type json: dict
226+
:param timeout: Timeout to wait for a reply of the server
227+
:type timeout: int
228+
:param clean: Should the data be cleaned (metadata entries stripped from the result)
229+
:type clean: bool
230+
"""
231+
return self._call(method=requests.put, url=url, data=data, json=json, clean=clean, timeout=timeout)
232+
233+
def patch(self, url, data=None, json=None, timeout=None, clean=False):
234+
"""
235+
Executes a PATCH call
236+
:param url: Url to call
237+
:type url: str
238+
:param data: Data to provide. This parameter will not set the JSON header so data may be interpreted differently!
239+
:type data: dict
240+
:param json: Data to provide as JSON parameters. This parameter will set the JSOn header to data will be interpreted as a JSON string
241+
:type json: dict
242+
:param timeout: Timeout to wait for a reply of the server
243+
:type timeout: int
244+
:param clean: Should the data be cleaned (metadata entries stripped from the result)
245+
:type clean: bool
246+
"""
247+
return self._call(method=requests.patch, url=url, data=data, json=json, clean=clean, timeout=timeout)
248+
249+
def delete(self, url, data=None, json=None, timeout=None, clean=False):
250+
"""
251+
Executes a DELETE call
252+
:param url: Url to call
253+
:type url: str
254+
:param data: Data to provide. This parameter will not set the JSON header so data may be interpreted differently!
255+
:type data: dict
256+
:param json: Data to provide as JSON parameters. This parameter will set the JSOn header to data will be interpreted as a JSON string
257+
:type json: dict
258+
:param timeout: Timeout to wait for a reply of the server
259+
:type timeout: int
260+
:param clean: Should the data be cleaned (metadata entries stripped from the result)
261+
:type clean: bool
262+
"""
263+
return self._call(method=requests.delete, url=url, data=data, json=json, clean=clean, timeout=timeout)

ovs/extensions/support/agent.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@
3434
from ovs.extensions.generic.system import System
3535
from ovs.extensions.packages.packagefactory import PackageFactory
3636
from ovs.extensions.services.servicefactory import ServiceFactory
37+
from ovs_extensions.constants.config import CONFIG_STORE_LOCATION
3738
from ovs.lib.helpers.toolbox import Toolbox
3839

39-
4040
class ConfigurationNotFoundError(RuntimeError):
4141
"""
4242
Raised if the config key could not be found
@@ -120,7 +120,7 @@ def __init__(self):
120120
raise NotImplementedError('Only Systemd is supported')
121121

122122
# Potential failing calls
123-
self._cluster_id = self.get_config_key(self.LOCATION_CLUSTER_ID, fallback=[Configuration.CONFIG_STORE_LOCATION, 'cluster_id'])
123+
self._cluster_id = self.get_config_key(self.LOCATION_CLUSTER_ID, fallback=[CONFIG_STORE_LOCATION, 'cluster_id'])
124124
self.interval = self.get_config_key(self.LOCATION_INTERVAL, fallback=[self.FALLBACK_CONFIG, self.KEY_INTERVAL], default=self.DEFAULT_INTERVAL)
125125
self._openvpn_service_name = 'openvpn@ovs_{0}-{1}'.format(self._cluster_id, self._node_id)
126126

0 commit comments

Comments
 (0)