From 65a823163f1e59d6dedd812da3782423f93c20fa Mon Sep 17 00:00:00 2001 From: Dileep Ranganathan Date: Wed, 5 Sep 2018 06:43:30 -0700 Subject: Create python distribution for onap-sms-client Renamed to onap-sms-client to conform to standard packaging Created and uploaded onap-sms-client python distribution to PyPI This will allow onapsmsclient to be installed using pip. Change-Id: I8ab1137fce5dbb022d54a2c96bc3acdc97d7e63d Issue-ID: AAF-438 Signed-off-by: Dileep Ranganathan --- sms-client/python/onap-sms-client/LICENSE | 17 ++ sms-client/python/onap-sms-client/README.md | 10 + sms-client/python/onap-sms-client/README.rst | 16 ++ .../onap-sms-client/onap-sms-client/__init__.py | 251 +++++++++++++++++++++ sms-client/python/onap-sms-client/setup.py | 36 +++ sms-client/python/sms/__init__.py | 248 -------------------- 6 files changed, 330 insertions(+), 248 deletions(-) create mode 100644 sms-client/python/onap-sms-client/LICENSE create mode 100644 sms-client/python/onap-sms-client/README.md create mode 100644 sms-client/python/onap-sms-client/README.rst create mode 100644 sms-client/python/onap-sms-client/onap-sms-client/__init__.py create mode 100644 sms-client/python/onap-sms-client/setup.py delete mode 100644 sms-client/python/sms/__init__.py diff --git a/sms-client/python/onap-sms-client/LICENSE b/sms-client/python/onap-sms-client/LICENSE new file mode 100644 index 0000000..0bb81a6 --- /dev/null +++ b/sms-client/python/onap-sms-client/LICENSE @@ -0,0 +1,17 @@ +# +# ------------------------------------------------------------------------- +# Copyright © 2018 Intel Corporation, Inc Intellectual Property +# 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. +# +# ------------------------------------------------------------------------- +# diff --git a/sms-client/python/onap-sms-client/README.md b/sms-client/python/onap-sms-client/README.md new file mode 100644 index 0000000..d426144 --- /dev/null +++ b/sms-client/python/onap-sms-client/README.md @@ -0,0 +1,10 @@ +# ONAP python SMSClient package +- python-package onap-sms-client client library for using Secret Management Service (SMS) inside ONAP. +- Refer https://wiki.onap.org/display/DW/Secret+Management+Service for more details. + +----- + +## install package +```bash + pip install onap-sms-client +``` diff --git a/sms-client/python/onap-sms-client/README.rst b/sms-client/python/onap-sms-client/README.rst new file mode 100644 index 0000000..07fa8ba --- /dev/null +++ b/sms-client/python/onap-sms-client/README.rst @@ -0,0 +1,16 @@ +ONAP python SMSClient package +============================= + +- python-package onap-sms-client client library for using Secret + Management Service (SMS) inside ONAP. +- Refer https://wiki.onap.org/display/DW/Secret+Management+Service for + more details. + +-------------- + +install package +--------------- + +.. code:: bash + + pip install onap-sms-client diff --git a/sms-client/python/onap-sms-client/onap-sms-client/__init__.py b/sms-client/python/onap-sms-client/onap-sms-client/__init__.py new file mode 100644 index 0000000..6f44006 --- /dev/null +++ b/sms-client/python/onap-sms-client/onap-sms-client/__init__.py @@ -0,0 +1,251 @@ +# Copyright 2018 Intel Corporation, Inc +# +# 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. + +import requests +import requests.exceptions +import urlparse + +name = "onap-sms-client" + + +class InvalidRequestException(Exception): + pass + + +class InternalServerError(Exception): + pass + + +class UnexpectedError(Exception): + pass + + +class Client(object): + """Python Client for Secret Management Service""" + + def __init__(self, url='http://localhost:10443', timeout=30, cacert=None): + """Creates a new SMS client instance + + Args: + url (str): Base URL with port pointing to the SMS service + timeout (int): Number of seconds before aborting the connection + cacert (str): Path to the cacert that will be used to verify + If this is None, verify will be False and the server cert + is not verified by the client. + Returns: + A Client object which can be used to interact with SMS service + """ + + self.base_url = url + self.timeout = timeout + self.cacert = cacert + self.session = requests.Session() + + self._base_api_url = '/v1/sms' + + def _urlJoin(self, *urls): + """Joins given urls into a single url + + Args: + urls (str): url fragments to be combined. + + Returns: + str: Joined URL + """ + + return '/'.join(urls) + + def _raiseException(self, statuscode, errors=None): + """ Handles Exception Raising based on statusCode + + Args: + statuscode (int): status code returned by the server + errors (str): list of strings containing error messages + + Returns: + exception: An exception is raised based on error message + """ + + if statuscode == 400: + raise InvalidRequestException(errors) + if statuscode == 500: + raise InternalServerError(errors) + + raise UnexpectedError(errors) + + def _request(self, method, url, headers=None, **kwargs): + """Handles request for all the client methods + + Args: + method (str): type of HTTP method (get, post or delete). + url (str): api URL. + headers (dict): custom headers if any. + **kwargs: various args supported by requests library + + Returns: + requests.Response: An object containing status_code and returned + json data is returned here. + """ + + if headers is None: + headers = { + 'content-type': "application/json", + 'Accept': "application/json" + } + + # Verify the server or not based on the cacert argument + if self.cacert is None: + verify = False + else: + verify = self.cacert + + url = urlparse.urljoin(self.base_url, url) + response = self.session.request(method, url, headers=headers, + allow_redirects=False, verify=verify, + timeout=self.timeout, **kwargs) + + errors = None + if response.status_code >= 400 and response.status_code < 600: + # Request Failed. Raise Exception. + errors = response.text + self._raiseException(response.status_code, errors) + + return response + + def getStatus(self): + """Returns Status of SMS Service + + Returns: + bool: True or False depending on if SMS Service is ready. + """ + + url = self._urlJoin(self._base_api_url, 'quorum', 'status') + + response = self._request('get', url) + return response.json()['sealstatus'] + + def createDomain(self, domainName): + """Creates a Secret Domain + + Args: + domainName (str): Name of the secret domain to create + + Returns: + string: UUID of the created domain name + """ + + domainName = domainName.strip() + data = {"name": domainName} + url = self._urlJoin(self._base_api_url, 'domain') + + response = self._request('post', url, json=data) + return response.json()['uuid'] + + def deleteDomain(self, domainName): + """Deletes a Secret Domain + + Args: + domainName (str): Name of the secret domain to delete + + Returns: + bool: True. An exception will be raised if delete failed. + """ + + domainName = domainName.strip() + url = self._urlJoin(self._base_api_url, 'domain', domainName) + + self._request('delete', url) + return True + + def getSecretNames(self, domainName): + """Get all Secret Names in Domain + + Args: + domainName (str): Name of the secret domain + + Returns: + string[]: List of strings each corresponding to a + Secret's Name in this Domain. + """ + + domainName = domainName.strip() + url = self._urlJoin(self._base_api_url, 'domain', domainName, + 'secret') + + response = self._request('get', url) + return response.json()['secretnames'] + + def storeSecret(self, domainName, secretName, values): + """Store a Secret in given Domain + + Args: + domainName (str): Name of the secret domain + secretName (str): Name for the Secret + values (dict): A dict containing name-value pairs which + form the secret + + Returns: + bool: True. An exception will be raised if store failed. + """ + + domainName = domainName.strip() + secretName = secretName.strip() + url = self._urlJoin(self._base_api_url, 'domain', domainName, + 'secret') + + if not isinstance(values, dict): + raise TypeError('Input values is not a dictionary') + + data = {"name": secretName, "values": values} + self._request('post', url, json=data) + return True + + def getSecret(self, domainName, secretName): + """Get a particular Secret from Domain. + + Args: + domainName (str): Name of the secret domain + secretName (str): Name of the secret + + Returns: + dict: dictionary containing the name-value pairs + which form the secret + """ + + domainName = domainName.strip() + secretName = secretName.strip() + url = self._urlJoin(self._base_api_url, 'domain', domainName, + 'secret', secretName) + + response = self._request('get', url) + return response.json()['values'] + + def deleteSecret(self, domainName, secretName): + """Delete a particular Secret from Domain. + + Args: + domainName (str): Name of the secret domain + secretName (str): Name of the secret + + Returns: + bool: True. An exception will be raised if delete failed. + """ + + domainName = domainName.strip() + secretName = secretName.strip() + url = self._urlJoin(self._base_api_url, 'domain', domainName, + 'secret', secretName) + + self._request('delete', url) + return True diff --git a/sms-client/python/onap-sms-client/setup.py b/sms-client/python/onap-sms-client/setup.py new file mode 100644 index 0000000..2adebc7 --- /dev/null +++ b/sms-client/python/onap-sms-client/setup.py @@ -0,0 +1,36 @@ +# Copyright 2018 Intel Corporation, Inc +# +# 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. + + +from setuptools import setup, find_packages + +setup( + + name='onap-sms-client', + keywords=("secret", "consul", "onap"), + description="ONAP python SMS client library", + long_description="python-package onap-sms-client client library for using" + " Secret Management Service (SMS) inside ONAP. Refer " + "https://wiki.onap.org/display/DW/Secret+Management+Service for more details.", + version="0.0.1", + url="https://gerrit.onap.org/r/gitweb?p=aaf%2Fsms.git;a=summary", + license="Apache 2", + author="Kiran Kamineni", + packages=find_packages(), + platforms=["all"], + classifiers=[ + "Intended Audience :: Developers", + "Programming Language :: Python :: 2.7" + ] +) diff --git a/sms-client/python/sms/__init__.py b/sms-client/python/sms/__init__.py deleted file mode 100644 index 88a7621..0000000 --- a/sms-client/python/sms/__init__.py +++ /dev/null @@ -1,248 +0,0 @@ -# Copyright 2018 Intel Corporation, Inc -# -# 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. - -import json -import requests -import requests.exceptions -import urlparse - -class InvalidRequestException(Exception): - pass - -class InternalServerError(Exception): - pass - -class UnexpectedError(Exception): - pass - -class Client(object): - """Python Client for Secret Management Service""" - - def __init__(self, url='http://localhost:10443', timeout=30, cacert=None): - """Creates a new SMS client instance - - Args: - url (str): Base URL with port pointing to the SMS service - timeout (int): Number of seconds before aborting the connection - cacert (str): Path to the cacert that will be used to verify - If this is None, verify will be False and the server cert - is not verified by the client. - Returns: - A Client object which can be used to interact with SMS service - """ - - self.base_url = url - self.timeout = timeout - self.cacert = cacert - self.session = requests.Session() - - self._base_api_url = '/v1/sms' - - def _urlJoin(self, *urls): - """Joins given urls into a single url - - Args: - urls (str): url fragments to be combined. - - Returns: - str: Joined URL - """ - - return '/'.join(urls) - - def _raiseException(self, statuscode, errors=None): - """ Handles Exception Raising based on statusCode - - Args: - statuscode (int): status code returned by the server - errors (str): list of strings containing error messages - - Returns: - exception: An exception is raised based on error message - """ - - if statuscode == 400: - raise InvalidRequestException(errors) - if statuscode == 500: - raise InternalServerError(errors) - - raise UnexpectedError(errors) - - def _request(self, method, url, headers=None, **kwargs): - """Handles request for all the client methods - - Args: - method (str): type of HTTP method (get, post or delete). - url (str): api URL. - headers (dict): custom headers if any. - **kwargs: various args supported by requests library - - Returns: - requests.Response: An object containing status_code and returned - json data is returned here. - """ - - if headers is None: - headers = { - 'content-type': "application/json", - 'Accept': "application/json" - } - - #Verify the server or not based on the cacert argument - if self.cacert is None: - verify = False - else: - verify = self.cacert - - url = urlparse.urljoin(self.base_url, url) - response = self.session.request(method, url, headers=headers, - allow_redirects=False, verify=verify, - timeout = self.timeout, **kwargs) - - errors = None - if response.status_code >= 400 and response.status_code < 600: - #Request Failed. Raise Exception. - errors = response.text - self._raiseException(response.status_code, errors) - - return response - - def getStatus(self): - """Returns Status of SMS Service - - Returns: - bool: True or False depending on if SMS Service is ready. - """ - - url = self._urlJoin(self._base_api_url, 'quorum', 'status') - - response = self._request('get', url) - return response.json()['sealstatus'] - - def createDomain(self, domainName): - """Creates a Secret Domain - - Args: - domainName (str): Name of the secret domain to create - - Returns: - string: UUID of the created domain name - """ - - - domainName = domainName.strip() - data = {"name": domainName} - url = self._urlJoin(self._base_api_url, 'domain') - - response = self._request('post', url, json = data) - return response.json()['uuid'] - - def deleteDomain(self, domainName): - """Deletes a Secret Domain - - Args: - domainName (str): Name of the secret domain to delete - - Returns: - bool: True. An exception will be raised if delete failed. - """ - - domainName = domainName.strip() - url = self._urlJoin(self._base_api_url, 'domain', domainName) - - self._request('delete', url) - return True - - def getSecretNames(self, domainName): - """Get all Secret Names in Domain - - Args: - domainName (str): Name of the secret domain - - Returns: - string[]: List of strings each corresponding to a - Secret's Name in this Domain. - """ - - domainName = domainName.strip() - url = self._urlJoin(self._base_api_url, 'domain', domainName, - 'secret') - - response = self._request('get', url) - return response.json()['secretnames'] - - - def storeSecret(self, domainName, secretName, values): - """Store a Secret in given Domain - - Args: - domainName (str): Name of the secret domain - secretName (str): Name for the Secret - values (dict): A dict containing name-value pairs which - form the secret - - Returns: - bool: True. An exception will be raised if store failed. - """ - - domainName = domainName.strip() - secretName = secretName.strip() - url = self._urlJoin(self._base_api_url, 'domain', domainName, - 'secret') - - if not isinstance(values, dict): - raise TypeError('Input values is not a dictionary') - - data = {"name": secretName, "values": values} - self._request('post', url, json = data) - return True - - def getSecret(self, domainName, secretName): - """Get a particular Secret from Domain. - - Args: - domainName (str): Name of the secret domain - secretName (str): Name of the secret - - Returns: - dict: dictionary containing the name-value pairs - which form the secret - """ - - domainName = domainName.strip() - secretName = secretName.strip() - url = self._urlJoin(self._base_api_url, 'domain', domainName, - 'secret', secretName) - - response = self._request('get', url) - return response.json()['values'] - - def deleteSecret(self, domainName, secretName): - """Delete a particular Secret from Domain. - - Args: - domainName (str): Name of the secret domain - secretName (str): Name of the secret - - Returns: - bool: True. An exception will be raised if delete failed. - """ - - domainName = domainName.strip() - secretName = secretName.strip() - url = self._urlJoin(self._base_api_url, 'domain', domainName, - 'secret', secretName) - - self._request('delete', url) - return True \ No newline at end of file -- cgit 1.2.3-korg