aboutsummaryrefslogtreecommitdiffstats
path: root/sdv/docker/sdvstate/tools
diff options
context:
space:
mode:
Diffstat (limited to 'sdv/docker/sdvstate/tools')
-rw-r--r--sdv/docker/sdvstate/tools/conf/__init__.py120
-rw-r--r--sdv/docker/sdvstate/tools/kube_utils.py85
-rw-r--r--sdv/docker/sdvstate/tools/result_api/__init__.py24
-rw-r--r--sdv/docker/sdvstate/tools/result_api/result_api.py73
-rw-r--r--sdv/docker/sdvstate/tools/result_api/rfile.py52
-rw-r--r--sdv/docker/sdvstate/tools/result_api/storage/__init__.py18
-rw-r--r--sdv/docker/sdvstate/tools/result_api/storage/local/__init__.py17
-rw-r--r--sdv/docker/sdvstate/tools/result_api/storage/local/local.py133
-rw-r--r--sdv/docker/sdvstate/tools/result_api/storage/storage_api.py46
9 files changed, 568 insertions, 0 deletions
diff --git a/sdv/docker/sdvstate/tools/conf/__init__.py b/sdv/docker/sdvstate/tools/conf/__init__.py
new file mode 100644
index 0000000..67c808f
--- /dev/null
+++ b/sdv/docker/sdvstate/tools/conf/__init__.py
@@ -0,0 +1,120 @@
+# Copyright 2020 University Of Delhi.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+
+
+"""Settings and configuration handlers.
+
+Settings will be loaded from several .yaml or .yml files
+and any user provided settings file.
+"""
+
+import os
+import ast
+
+import yaml
+
+# pylint: disable=invalid-name
+
+class Settings():
+ """Holding class for settings.
+ """
+ def __init__(self):
+ pass
+
+
+ def getValue(self, attr):
+ """
+ Return a settings item value
+ """
+ try:
+ attr = attr.lower()
+ return getattr(self, attr)
+ except AttributeError:
+ raise AttributeError("{obj} object has no attribute \
+ {attr}".format(obj=self.__class__, attr=attr))
+
+
+ def setValue(self, name, value):
+ """Set a value
+ """
+ if name is not None and value is not None:
+ super(Settings, self).__setattr__(name.lower(), value)
+
+
+ def load_from_file(self, path):
+ """Update ``settings`` with values found in module at ``path``.
+ """
+ with open(path) as file:
+ configs = yaml.load_all(file, Loader=yaml.SafeLoader)
+ for conf in configs:
+ for name, value in conf.items():
+ self.setValue(name, value)
+
+
+ def load_from_env(self):
+ """
+ Update ``settings`` with values found in the environment.
+ """
+ for key in os.environ:
+ value = os.environ[key]
+
+ #evaluate string to python type
+ try:
+ value = ast.literal_eval(os.environ[key])
+ except (ValueError, SyntaxError):
+ pass #already string
+
+ self.setValue(key, value)
+
+
+ def load_from_dir(self, dir_path):
+ """Update ``settings`` with contents of the yaml files at ``path``.
+
+ Files are read in ascending order, hence if a configuration item
+ exists in more than one file, then the setting in the file that
+ occurs in the last read file will have high precedence and
+ overwrite previous values.
+
+ Same precedence logic for sub-directories.
+ Also, child directory will have more precedence than it's parent
+
+ :param dir_path: The full path to the dir from which to load the
+ yaml files.
+
+ :returns: None
+ """
+ files = list_yamls(dir_path)
+
+ for file in files:
+ self.load_from_file(file)
+
+
+settings = Settings()
+
+
+def list_yamls(dir_path):
+ """Get all yaml files recursively in ``dir_path``
+ """
+ files = []
+ dir_list = [x[0] for x in os.walk(dir_path)]
+ dir_list.sort()
+ for path in dir_list:
+ dir_files = [path+'/'+f for f in os.listdir(path)
+ if f.endswith('.yaml') or f.endswith('.yml')]
+ if dir_files is not None:
+ dir_files.sort()
+ files.extend(dir_files)
+ return files
diff --git a/sdv/docker/sdvstate/tools/kube_utils.py b/sdv/docker/sdvstate/tools/kube_utils.py
new file mode 100644
index 0000000..3468ac6
--- /dev/null
+++ b/sdv/docker/sdvstate/tools/kube_utils.py
@@ -0,0 +1,85 @@
+# Copyright 2020 University Of Delhi.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+
+"""
+Kubernetes cluster api helper functions
+"""
+
+from kubernetes import client, config
+from kubernetes.stream import stream
+
+from tools.conf import settings # pylint: disable=import-error
+
+
+def load_kube_api():
+ """
+ Loads kubernetes api
+ """
+ config.load_kube_config(settings.getValue('kube_config'))
+ api = client.CoreV1Api()
+ settings.setValue('kube_api', api)
+
+
+def kube_api():
+ """
+ Returns kube_api object
+ """
+ return settings.getValue('kube_api')
+
+
+def get_pod_with_labels(labels):
+ """
+ Returns json details any one pod with matching labels
+
+ :param labels: labels to find matching pod
+ :return: pod details
+ """
+ api = kube_api()
+ pod = api.list_pod_for_all_namespaces(label_selector=labels).items[0]
+ return pod
+
+
+def kube_exec(pod, cmd):
+ """
+ Executes `cmd` inside `pod` and returns response
+
+ :param pod: pod object
+ :param cmd: command to execute inside pod
+ :return: response from pod
+ """
+ api = kube_api()
+ response = stream(api.connect_get_namespaced_pod_exec,
+ pod.metadata.name, pod.metadata.namespace, command=cmd,
+ stderr=True, stdin=False, stdout=True, tty=False)
+ return response
+
+
+def kube_curl(*args):
+ """
+ executes curl cmd in kubernetes network
+
+ :param args: comma separated list of args to pass to curl
+ :return: http response
+ """
+ args = list(args)
+ args.insert(0, "curl")
+
+ labels = "application=prometheus-openstack-exporter,component=exporter"
+ pod = get_pod_with_labels(labels)
+
+ response = kube_exec(pod, args)
+
+ return response
diff --git a/sdv/docker/sdvstate/tools/result_api/__init__.py b/sdv/docker/sdvstate/tools/result_api/__init__.py
new file mode 100644
index 0000000..0633103
--- /dev/null
+++ b/sdv/docker/sdvstate/tools/result_api/__init__.py
@@ -0,0 +1,24 @@
+# Copyright 2020 University Of Delhi.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+
+"""
+Result Manager Package
+"""
+from .result_api import result_api
+from .rfile import rfile
+
+from .storage.storage_api import StorageApi
+from .storage.local.local import Local
diff --git a/sdv/docker/sdvstate/tools/result_api/result_api.py b/sdv/docker/sdvstate/tools/result_api/result_api.py
new file mode 100644
index 0000000..95dfd56
--- /dev/null
+++ b/sdv/docker/sdvstate/tools/result_api/result_api.py
@@ -0,0 +1,73 @@
+# Copyright 2020 University Of Delhi.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+"""
+Result API
+Main entry point to use results manager
+"""
+
+import logging
+from .storage.storage_api import StorageApi
+
+class ResultApi():
+ """
+ Result API
+ Provides various storage options to use implemented as
+ plugin to storage api
+ """
+
+ def __init__(self):
+ """
+ Initialization function
+ """
+ self._logger = logging.getLogger(__name__)
+ self._storage_handles = []
+
+ def register_storage(self, storage_api):
+ """
+ Registers ``storage_api`` as an active storage option to use.
+ """
+ self._logger.debug("Loading new Storage API...")
+ if not isinstance(storage_api, StorageApi):
+ raise TypeError("incorrect storage type, Required StorageAPI obj")
+
+ storage_api.load_settings()
+ self._storage_handles.append(storage_api)
+ self._logger.info(f'{storage_api.name} api registered')
+
+ def unregister_storage(self, storage_api):
+ """
+ Removes registered ``storage_api`` if exists
+ """
+ while storage_api in self._storage_handles:
+ self._storage_handles.remove(storage_api)
+
+ def unregister_all(self):
+ """
+ Removes all registered storage endpoints
+ """
+ for storage_api in self._storage_handles:
+ self.unregister_storage(storage_api)
+
+ def store(self, data):
+ """
+ Calls all active storage_api and stores ``data`` in all of them
+ """
+ for api in self._storage_handles:
+ api.store(data)
+
+
+# pylint: disable=invalid-name
+result_api = ResultApi()
diff --git a/sdv/docker/sdvstate/tools/result_api/rfile.py b/sdv/docker/sdvstate/tools/result_api/rfile.py
new file mode 100644
index 0000000..71a0924
--- /dev/null
+++ b/sdv/docker/sdvstate/tools/result_api/rfile.py
@@ -0,0 +1,52 @@
+# Copyright 2020 University Of Delhi.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+
+"""rfile is Object representation of a file for Result_api and storage_api
+"""
+
+import logging
+
+# pylint: disable=invalid-name
+
+class rfile():
+ """
+ rfile object to represent files in Result API
+ """
+
+ def __init__(self, data):
+ """
+ Initialisation function
+ """
+ self._logger = logging.getLogger(__name__)
+ self.hold_data(data)
+
+ def get_data(self):
+ """
+ Returns stored data
+ """
+ if self._data == '':
+ self._logger.warning('Reading from a empty \'rfile\'')
+ return self._data
+
+
+ def hold_data(self, data):
+ """
+ Holds data of a file
+ """
+ if data is None:
+ self._logger.warning('Storing an empty \'rfile\'')
+ data = ''
+ self._data = data
diff --git a/sdv/docker/sdvstate/tools/result_api/storage/__init__.py b/sdv/docker/sdvstate/tools/result_api/storage/__init__.py
new file mode 100644
index 0000000..d647f0f
--- /dev/null
+++ b/sdv/docker/sdvstate/tools/result_api/storage/__init__.py
@@ -0,0 +1,18 @@
+# Copyright 2020 University Of Delhi.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+"""
+Abstract class for Storage API
+"""
diff --git a/sdv/docker/sdvstate/tools/result_api/storage/local/__init__.py b/sdv/docker/sdvstate/tools/result_api/storage/local/__init__.py
new file mode 100644
index 0000000..185ec01
--- /dev/null
+++ b/sdv/docker/sdvstate/tools/result_api/storage/local/__init__.py
@@ -0,0 +1,17 @@
+# Copyright 2020 University Of Delhi.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Local storage api
+"""
diff --git a/sdv/docker/sdvstate/tools/result_api/storage/local/local.py b/sdv/docker/sdvstate/tools/result_api/storage/local/local.py
new file mode 100644
index 0000000..d7dc67b
--- /dev/null
+++ b/sdv/docker/sdvstate/tools/result_api/storage/local/local.py
@@ -0,0 +1,133 @@
+# Copyright 2020 University Of Delhi.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+"""
+Local Storage Api
+"""
+
+import logging
+import os
+import random
+import string
+import json
+from tools.conf import settings # pylint: disable=import-error
+
+from ..storage_api import StorageApi
+from ... import rfile
+
+
+
+class Local(StorageApi):
+ """
+ Storage API
+ Provides abstract class for various storage options to implement as
+ plugin to storage api
+ """
+
+ def __init__(self):
+ """
+ Initialization function
+ """
+ super(Local, self).__init__()
+ self.name = 'Local Storage'
+ self._logger = logging.getLogger(__name__)
+ self._path = ''
+ self._filename = ''
+
+ def store(self, data):
+ """
+ stores ``data``, ``data`` should be a dict
+
+ :param data: dict object to store
+ """
+ if not isinstance(data, dict):
+ raise TypeError("incorrect data type to store, dict required")
+
+ if not os.path.isfile(self._filename):
+ with open(self._filename, 'w') as fhandle:
+ json.dump([], fhandle)
+
+ with open(self._filename, 'r') as fhandle:
+ records = json.load(fhandle)
+ temp_data = data.copy()
+ eval_rfile(temp_data)
+ records.append(temp_data)
+
+ with open(self._filename, 'w') as fhandle:
+ self._logger.info(f'{self.name}: New record saved')
+ json.dump(records, fhandle, indent=4, sort_keys=True, default=str)
+
+
+ def load_settings(self):
+ """
+ Load all required settings otherwise set to default
+ Settings to load:
+ * ``result_path`` (default: /tmp/local/)
+ * ``results_filename`` (default: results.json)
+ """
+ try:
+ path = settings.getValue('results_path')
+ except AttributeError:
+ path = '/tmp/local/'
+ settings.setValue('results_path', path)
+
+ try:
+ filename = settings.getValue('results_filename')
+ except AttributeError:
+ filename = 'results.json'
+ settings.setValue('results_filename', filename)
+
+ if not os.path.exists(path):
+ os.makedirs(path)
+
+ self._path = path
+ self._filename = path + filename
+
+
+
+
+
+def eval_rfile(data):
+ """
+ Find all values of a type rfile in data dict/list and evals them into
+ actual file
+ """
+ if isinstance(data, dict):
+ for key, value in data.items():
+ if isinstance(value, rfile):
+ data[key] = rfile_save(value, key)
+ else:
+ eval_rfile(value)
+ if isinstance(data, list):
+ for i, _ in enumerate(data):
+ if isinstance(data[i], rfile):
+ data[i] = rfile_save(data[i])
+ else:
+ eval_rfile(data[i])
+
+
+def rfile_save(rfile_obj, prefix='zz'):
+ """
+ Takes rfile Object and stores it into random file returning filename
+ """
+ letters = string.ascii_lowercase
+ suffix = ''.join(random.choice(letters) for i in range(6))
+ filename = settings.getValue('results_path') + f'{prefix}-{suffix}.txt'
+ if os.path.isfile(filename):
+ return rfile_save(rfile_obj, prefix)
+ else:
+ with open(filename, 'w') as fhandle:
+ fhandle.write(rfile_obj.get_data())
+ return f'{prefix}-{suffix}.txt'
diff --git a/sdv/docker/sdvstate/tools/result_api/storage/storage_api.py b/sdv/docker/sdvstate/tools/result_api/storage/storage_api.py
new file mode 100644
index 0000000..5ff0d8f
--- /dev/null
+++ b/sdv/docker/sdvstate/tools/result_api/storage/storage_api.py
@@ -0,0 +1,46 @@
+# Copyright 2020 University Of Delhi.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+"""
+Abstract class for Storage API
+"""
+
+import logging
+
+
+class StorageApi():
+ """
+ Storage API
+ Provides abstract class for various storage options to implement as
+ plugin to storage api
+ """
+
+ def __init__(self):
+ """
+ Initialization function
+ """
+ self._logger = logging.getLogger(__name__)
+
+ def store(self, data):
+ """
+ stores ``data``
+ """
+ raise NotImplementedError()
+
+ def load_settings(self):
+ """
+ Load all required settings
+ """
+ raise NotImplementedError()