From 1a95c1e6b33d9b3efcfd92e1de64feee7e9b5c68 Mon Sep 17 00:00:00 2001 From: SerenaFeng Date: Fri, 9 Mar 2018 16:35:22 +0800 Subject: restructure testapiclient project Change-Id: I13d24ce7b436f203a66fe14f4930e58b3ab1193c Signed-off-by: SerenaFeng --- testapi/testapi-client/testapiclient/auth.py | 14 ---- .../testapi-client/testapiclient/cli/__init__.py | 0 testapi/testapi-client/testapiclient/cli/auth.py | 14 ++++ testapi/testapi-client/testapiclient/cli/pods.py | 78 ++++++++++++++++++ .../testapi-client/testapiclient/cli/projects.py | 95 ++++++++++++++++++++++ testapi/testapi-client/testapiclient/command.py | 38 --------- .../testapi-client/testapiclient/http_client.py | 67 --------------- testapi/testapi-client/testapiclient/identity.py | 37 --------- testapi/testapi-client/testapiclient/main.py | 12 +-- testapi/testapi-client/testapiclient/pods.py | 78 ------------------ testapi/testapi-client/testapiclient/projects.py | 95 ---------------------- testapi/testapi-client/testapiclient/url_parse.py | 22 ----- testapi/testapi-client/testapiclient/user.py | 2 - .../testapi-client/testapiclient/utils/__init__.py | 0 .../testapi-client/testapiclient/utils/command.py | 39 +++++++++ .../testapiclient/utils/http_client.py | 68 ++++++++++++++++ .../testapi-client/testapiclient/utils/identity.py | 38 +++++++++ .../testapiclient/utils/url_parse.py | 22 +++++ testapi/testapi-client/testapiclient/utils/user.py | 2 + 19 files changed, 362 insertions(+), 359 deletions(-) delete mode 100644 testapi/testapi-client/testapiclient/auth.py create mode 100644 testapi/testapi-client/testapiclient/cli/__init__.py create mode 100644 testapi/testapi-client/testapiclient/cli/auth.py create mode 100644 testapi/testapi-client/testapiclient/cli/pods.py create mode 100644 testapi/testapi-client/testapiclient/cli/projects.py delete mode 100644 testapi/testapi-client/testapiclient/command.py delete mode 100644 testapi/testapi-client/testapiclient/http_client.py delete mode 100644 testapi/testapi-client/testapiclient/identity.py delete mode 100644 testapi/testapi-client/testapiclient/pods.py delete mode 100644 testapi/testapi-client/testapiclient/projects.py delete mode 100644 testapi/testapi-client/testapiclient/url_parse.py delete mode 100644 testapi/testapi-client/testapiclient/user.py create mode 100644 testapi/testapi-client/testapiclient/utils/__init__.py create mode 100644 testapi/testapi-client/testapiclient/utils/command.py create mode 100644 testapi/testapi-client/testapiclient/utils/http_client.py create mode 100644 testapi/testapi-client/testapiclient/utils/identity.py create mode 100644 testapi/testapi-client/testapiclient/utils/url_parse.py create mode 100644 testapi/testapi-client/testapiclient/utils/user.py (limited to 'testapi/testapi-client/testapiclient') diff --git a/testapi/testapi-client/testapiclient/auth.py b/testapi/testapi-client/testapiclient/auth.py deleted file mode 100644 index 3728498..0000000 --- a/testapi/testapi-client/testapiclient/auth.py +++ /dev/null @@ -1,14 +0,0 @@ -from testapiclient import command -from testapiclient import identity - - -class Auth(command.Command): - "Handle Authentication for users" - - def get_parser(self, prog_name): - parser = super(Auth, self).get_parser(prog_name) - return parser - - @identity.authenticate - def take_action(self, parsed_args): - print "Authentication has been successful!" diff --git a/testapi/testapi-client/testapiclient/cli/__init__.py b/testapi/testapi-client/testapiclient/cli/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/testapi/testapi-client/testapiclient/cli/auth.py b/testapi/testapi-client/testapiclient/cli/auth.py new file mode 100644 index 0000000..434c55a --- /dev/null +++ b/testapi/testapi-client/testapiclient/cli/auth.py @@ -0,0 +1,14 @@ +from testapiclient.utils import command +from testapiclient.utils import identity + + +class Auth(command.Command): + "Handle Authentication for users" + + def get_parser(self, prog_name): + parser = super(Auth, self).get_parser(prog_name) + return parser + + @identity.authenticate + def take_action(self, parsed_args): + print "Authentication has been successful!" diff --git a/testapi/testapi-client/testapiclient/cli/pods.py b/testapi/testapi-client/testapiclient/cli/pods.py new file mode 100644 index 0000000..cdedc3e --- /dev/null +++ b/testapi/testapi-client/testapiclient/cli/pods.py @@ -0,0 +1,78 @@ +import json + +from testapiclient.utils import command +from testapiclient.utils import http_client as client +from testapiclient.utils import identity +from testapiclient.utils import url_parse + + +def pods_url(): + return url_parse.resource_join('pods') + + +def pod_url(parsed_args): + return url_parse.path_join(pods_url(), parsed_args.name) + + +class PodGet(command.Lister): + "Handle get request for pods" + + def get_parser(self, prog_name): + parser = super(PodGet, self).get_parser(prog_name) + parser.add_argument('-name', + default='', + help='Search pods using name') + return parser + + def take_action(self, parsed_args): + self.show(client.get(self.filter_by_name(pods_url(), parsed_args))) + + +class PodGetOne(command.ShowOne): + "Handle get request for pod by name" + + def get_parser(self, prog_name): + parser = super(PodGetOne, self).get_parser(prog_name) + parser.add_argument('name', + default='', + help='Find pod using name') + return parser + + def take_action(self, parsed_args): + self.show(client.get(pod_url(parsed_args))) + + +class PodCreate(command.Command): + "Handle post request for pods" + + def get_parser(self, prog_name): + parser = super(PodCreate, self).get_parser(prog_name) + parser.add_argument('pod', + type=json.loads, + help='Pod create request format :\n' + '\'{"role": "", "name": "", "details": "", ' + '"mode": ""}\',\n role should be either ' + '"community-ci" or "production-ci", and ' + 'mode should be either "metal" or "virtual.') + return parser + + @identity.authenticate + def take_action(self, parsed_args): + self.show('Create', + client.post(pods_url(), parsed_args.pod)) + + +class PodDelete(command.Command): + "Handle delete request for pods" + + def get_parser(self, prog_name): + parser = super(PodDelete, self).get_parser(prog_name) + parser.add_argument('name', + type=str, + help='Delete pods using name') + return parser + + @identity.authenticate + def take_action(self, parsed_args): + self.show('Delete', + client.delete(pod_url(parsed_args))) diff --git a/testapi/testapi-client/testapiclient/cli/projects.py b/testapi/testapi-client/testapiclient/cli/projects.py new file mode 100644 index 0000000..f847961 --- /dev/null +++ b/testapi/testapi-client/testapiclient/cli/projects.py @@ -0,0 +1,95 @@ +import json + +from testapiclient.utils import command +from testapiclient.utils import http_client as client +from testapiclient.utils import identity +from testapiclient.utils import url_parse + + +def projects_url(): + url_parse.resource_join('projects') + + +def project_url(parsed_args): + return url_parse.path_join(projects_url(), parsed_args.name) + + +class ProjectGet(command.Lister): + + def get_parser(self, prog_name): + parser = super(ProjectGet, self).get_parser(prog_name) + parser.add_argument('-name', + default='', + help='Search projects by name') + return parser + + def take_action(self, parsed_args): + self.show(client.get(self.filter_name(projects_url(), parsed_args))) + + +class ProjectGetOne(command.ShowOne): + + def get_parser(self, prog_name): + parser = super(ProjectGetOne, self).get_parser(prog_name) + parser.add_argument('-name', + default='', + required=True, + help='Search project by name') + return parser + + def take_action(self, parsed_args): + self.show(client.get(project_url(parsed_args))) + + +class ProjectCreate(command.Command): + + def get_parser(self, prog_name): + parser = super(ProjectCreate, self).get_parser(prog_name) + parser.add_argument('project', + type=json.loads, + help='Project create request format :{' + ' "name": (required)"", ' + '"description": (optional)""}') + return parser + + @identity.authenticate + def take_action(self, parsed_args): + self.show('Create', + client.post(projects_url(), parsed_args.project)) + + +class ProjectDelete(command.Command): + + def get_parser(self, prog_name): + parser = super(ProjectDelete, self).get_parser(prog_name) + parser.add_argument('-name', + type=str, + required=True, + help='Delete project by name') + return parser + + @identity.authenticate + def take_action(self, parsed_args): + self.show('Delete', + client.delete(project_url(parsed_args))) + + +class ProjectPut(command.Command): + + def get_parser(self, prog_name): + parser = super(ProjectPut, self).get_parser(prog_name) + parser.add_argument('-name', + type=str, + required=True, + help='Update project by name') + parser.add_argument('project', + type=json.loads, + help='Project Update request format :{' + '"name": (required)"", ' + '"description": (optional)""}') + return parser + + @identity.authenticate + def take_action(self, parsed_args): + self.show('Update', + client.put(project_url(parsed_args), parsed_args.project)) diff --git a/testapi/testapi-client/testapiclient/command.py b/testapi/testapi-client/testapiclient/command.py deleted file mode 100644 index 62a8b86..0000000 --- a/testapi/testapi-client/testapiclient/command.py +++ /dev/null @@ -1,38 +0,0 @@ -from cliff import command -from testapiclient import url_parse - - -class Command(command.Command): - def get_parser(self, prog_name): - parser = super(Command, self).get_parser(prog_name) - parser.add_argument('-u', - type=str, - help='Username for authentication') - parser.add_argument('-p', - type=str, - help='Password for authentication') - - return parser - - def show(self, request, response): - print ' '.join([request, - 'success' if response.status_code < 300 - else 'failed: {}'.format(response.text)]) - - -class Lister(command.Command): - - @staticmethod - def filter_by_name(url, parsed_args): - def query_url(): - return url_parse.query_join(url, name=parsed_args.name) - - return query_url() if parsed_args.name else url - - def show(self, response): - print response.json() if response.status_code < 300 else response.text - - -class ShowOne(command.Command): - def show(self, response): - print response.json() if response.status_code < 300 else response.text diff --git a/testapi/testapi-client/testapiclient/http_client.py b/testapi/testapi-client/testapiclient/http_client.py deleted file mode 100644 index 8a33a8c..0000000 --- a/testapi/testapi-client/testapiclient/http_client.py +++ /dev/null @@ -1,67 +0,0 @@ -import json - -import requests -from testapiclient import user - - -class HTTPClient(object): - - __instance = None - headers = {'Content-type': 'application/json', 'Accept': 'text/plain'} - - @staticmethod - def get_Instance(): - """ Static access method. """ - if HTTPClient.__instance is None: - HTTPClient() - return HTTPClient.__instance - - def __init__(self): - """ Virtually private constructor. """ - if HTTPClient.__instance is not None: - raise Exception("This class is a singleton!") - else: - HTTPClient.__instance = self - - def get(self, url): - return requests.get(url) - - def post(self, url, data): - return self._request('post', url, - data=json.dumps(data), - headers=self.headers) - - def put(self, url, data): - return self._request('put', url, - data=json.dumps(data), - headers=self.headers) - - def delete(self, url, *args): - data = json.dumps(args[0]) if len(args) > 0 else None - return self._request('delete', url, - data=data, - headers=self.headers) - - def _request(self, method, *args, **kwargs): - return getattr(user.User.session, method)(*args, **kwargs) - - -def _request(method, *args, **kwargs): - client = HTTPClient.get_Instance() - return getattr(client, method)(*args, **kwargs) - - -def get(url): - return _request('get', url) - - -def post(url, data): - return _request('post', url, data) - - -def put(url, data): - return _request('put', url, data) - - -def delete(url, data=None): - return _request('delete', url, data) diff --git a/testapi/testapi-client/testapiclient/identity.py b/testapi/testapi-client/testapiclient/identity.py deleted file mode 100644 index f38d8e1..0000000 --- a/testapi/testapi-client/testapiclient/identity.py +++ /dev/null @@ -1,37 +0,0 @@ -import functools -import os -import urllib - -import requests -from testapiclient import user - - -def _authenticate(username, password): - session = requests.Session() - hostname = '{}{}{}'.format(os.environ.get('testapi_cas_auth_url'), - urllib.quote(os.environ.get('testapi_url')), - os.environ.get('testapi_cas_signin_return')) - data = { - 'name': username, - 'pass': password, - 'form_id': 'user_login' - } - response = session.post(hostname, data) - if "login" not in response.text: - user.User.session = session - return response - - -def authenticate(xstep): - @functools.wraps(xstep) - def wrapper(self, parsed_args): - if(user.User.session is None): - username = parsed_args.u - password = parsed_args.p - if(username and password): - response = _authenticate(username, password) - if "login" in response.text: - print "Authentication has failed." - return - xstep(self, parsed_args) - return wrapper diff --git a/testapi/testapi-client/testapiclient/main.py b/testapi/testapi-client/testapiclient/main.py index 6c6cf56..dfa6284 100644 --- a/testapi/testapi-client/testapiclient/main.py +++ b/testapi/testapi-client/testapiclient/main.py @@ -1,21 +1,21 @@ import sys -from cliff.app import App -from cliff.commandmanager import CommandManager +from cliff import app +from cliff import commandmanager import requests -from testapiclient import user +from testapiclient.utils import user -class TestAPIClient(App): +class TestAPIClient(app.App): def __init__(self): super(TestAPIClient, self).__init__( description='TestAPI Client', version='0.1', - command_manager=CommandManager('testapi'), + command_manager=commandmanager.CommandManager('testapi'), deferred_help=True, - ) + ) user.User.session = requests.Session() def initialize_app(self, argv): diff --git a/testapi/testapi-client/testapiclient/pods.py b/testapi/testapi-client/testapiclient/pods.py deleted file mode 100644 index 85c19e4..0000000 --- a/testapi/testapi-client/testapiclient/pods.py +++ /dev/null @@ -1,78 +0,0 @@ -import json - -from testapiclient import command -from testapiclient import http_client as client -from testapiclient import identity -from testapiclient import url_parse - - -def pods_url(): - return url_parse.resource_join('pods') - - -def pod_url(parsed_args): - return url_parse.path_join(pods_url(), parsed_args.name) - - -class PodGet(command.Lister): - "Handle get request for pods" - - def get_parser(self, prog_name): - parser = super(PodGet, self).get_parser(prog_name) - parser.add_argument('-name', - default='', - help='Search pods using name') - return parser - - def take_action(self, parsed_args): - self.show(client.get(self.filter_by_name(pods_url(), parsed_args))) - - -class PodGetOne(command.ShowOne): - "Handle get request for pod by name" - - def get_parser(self, prog_name): - parser = super(PodGetOne, self).get_parser(prog_name) - parser.add_argument('name', - default='', - help='Find pod using name') - return parser - - def take_action(self, parsed_args): - self.show(client.get(pod_url(parsed_args))) - - -class PodCreate(command.Command): - "Handle post request for pods" - - def get_parser(self, prog_name): - parser = super(PodCreate, self).get_parser(prog_name) - parser.add_argument('pod', - type=json.loads, - help='Pod create request format :\n' - '\'{"role": "", "name": "", "details": "", ' - '"mode": ""}\',\n role should be either ' - '"community-ci" or "production-ci", and ' - 'mode should be either "metal" or "virtual.') - return parser - - @identity.authenticate - def take_action(self, parsed_args): - self.show('Create', - client.post(pods_url(), parsed_args.pod)) - - -class PodDelete(command.Command): - "Handle delete request for pods" - - def get_parser(self, prog_name): - parser = super(PodDelete, self).get_parser(prog_name) - parser.add_argument('name', - type=str, - help='Delete pods using name') - return parser - - @identity.authenticate - def take_action(self, parsed_args): - self.show('Delete', - client.delete(pod_url(parsed_args))) diff --git a/testapi/testapi-client/testapiclient/projects.py b/testapi/testapi-client/testapiclient/projects.py deleted file mode 100644 index 7f98b56..0000000 --- a/testapi/testapi-client/testapiclient/projects.py +++ /dev/null @@ -1,95 +0,0 @@ -import json - -from testapiclient import command -from testapiclient import http_client as client -from testapiclient import identity -from testapiclient import url_parse - - -def projects_url(): - url_parse.resource_join('projects') - - -def project_url(parsed_args): - return url_parse.path_join(projects_url(), parsed_args.name) - - -class ProjectGet(command.Lister): - - def get_parser(self, prog_name): - parser = super(ProjectGet, self).get_parser(prog_name) - parser.add_argument('-name', - default='', - help='Search projects by name') - return parser - - def take_action(self, parsed_args): - self.show(client.get(self.filter_name(projects_url(), parsed_args))) - - -class ProjectGetOne(command.ShowOne): - - def get_parser(self, prog_name): - parser = super(ProjectGetOne, self).get_parser(prog_name) - parser.add_argument('-name', - default='', - required=True, - help='Search project by name') - return parser - - def take_action(self, parsed_args): - self.show(client.get(project_url(parsed_args))) - - -class ProjectCreate(command.Command): - - def get_parser(self, prog_name): - parser = super(ProjectCreate, self).get_parser(prog_name) - parser.add_argument('project', - type=json.loads, - help='Project create request format :{' - ' "name": (required)"", ' - '"description": (optional)""}') - return parser - - @identity.authenticate - def take_action(self, parsed_args): - self.show('Create', - client.post(projects_url(), parsed_args.project)) - - -class ProjectDelete(command.Command): - - def get_parser(self, prog_name): - parser = super(ProjectDelete, self).get_parser(prog_name) - parser.add_argument('-name', - type=str, - required=True, - help='Delete project by name') - return parser - - @identity.authenticate - def take_action(self, parsed_args): - self.show('Delete', - client.delete(project_url(parsed_args))) - - -class ProjectPut(command.Command): - - def get_parser(self, prog_name): - parser = super(ProjectPut, self).get_parser(prog_name) - parser.add_argument('-name', - type=str, - required=True, - help='Update project by name') - parser.add_argument('project', - type=json.loads, - help='Project Update request format :{' - '"name": (required)"", ' - '"description": (optional)""}') - return parser - - @identity.authenticate - def take_action(self, parsed_args): - self.show('Update', - client.put(project_url(parsed_args), parsed_args.project)) diff --git a/testapi/testapi-client/testapiclient/url_parse.py b/testapi/testapi-client/testapiclient/url_parse.py deleted file mode 100644 index 08f7a63..0000000 --- a/testapi/testapi-client/testapiclient/url_parse.py +++ /dev/null @@ -1,22 +0,0 @@ -import os - -from six.moves.urllib import parse - - -def path_join(base, *urls): - def _path_join(base, url): - if not base.endswith('/'): - base += '/' - return parse.urljoin(base, url) - - urls = (base,) + urls - return reduce(_path_join, urls) - - -def query_join(base, **queries): - return base + '?' + parse.urlencode(queries) - - -def resource_join(url): - testapi_url = os.environ.get('testapi_url') - return path_join(testapi_url, url) diff --git a/testapi/testapi-client/testapiclient/user.py b/testapi/testapi-client/testapiclient/user.py deleted file mode 100644 index 7e72163..0000000 --- a/testapi/testapi-client/testapiclient/user.py +++ /dev/null @@ -1,2 +0,0 @@ -class User(): - session = None diff --git a/testapi/testapi-client/testapiclient/utils/__init__.py b/testapi/testapi-client/testapiclient/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/testapi/testapi-client/testapiclient/utils/command.py b/testapi/testapi-client/testapiclient/utils/command.py new file mode 100644 index 0000000..95f1fb0 --- /dev/null +++ b/testapi/testapi-client/testapiclient/utils/command.py @@ -0,0 +1,39 @@ +from cliff import command + +from testapiclient.utils import url_parse + + +class Command(command.Command): + def get_parser(self, prog_name): + parser = super(Command, self).get_parser(prog_name) + parser.add_argument('-u', + type=str, + help='Username for authentication') + parser.add_argument('-p', + type=str, + help='Password for authentication') + + return parser + + def show(self, request, response): + print ' '.join([request, + 'success' if response.status_code < 300 + else 'failed: {}'.format(response.text)]) + + +class Lister(command.Command): + + @staticmethod + def filter_by_name(url, parsed_args): + def query_url(): + return url_parse.query_join(url, name=parsed_args.name) + + return query_url() if parsed_args.name else url + + def show(self, response): + print response.json() if response.status_code < 300 else response.text + + +class ShowOne(command.Command): + def show(self, response): + print response.json() if response.status_code < 300 else response.text diff --git a/testapi/testapi-client/testapiclient/utils/http_client.py b/testapi/testapi-client/testapiclient/utils/http_client.py new file mode 100644 index 0000000..6be33ee --- /dev/null +++ b/testapi/testapi-client/testapiclient/utils/http_client.py @@ -0,0 +1,68 @@ +import json + +import requests + +from testapiclient.utils import user + + +class HTTPClient(object): + + __instance = None + headers = {'Content-type': 'application/json', 'Accept': 'text/plain'} + + @staticmethod + def get_Instance(): + """ Static access method. """ + if HTTPClient.__instance is None: + HTTPClient() + return HTTPClient.__instance + + def __init__(self): + """ Virtually private constructor. """ + if HTTPClient.__instance is not None: + raise Exception("This class is a singleton!") + else: + HTTPClient.__instance = self + + def get(self, url): + return requests.get(url) + + def post(self, url, data): + return self._request('post', url, + data=json.dumps(data), + headers=self.headers) + + def put(self, url, data): + return self._request('put', url, + data=json.dumps(data), + headers=self.headers) + + def delete(self, url, *args): + data = json.dumps(args[0]) if len(args) > 0 else None + return self._request('delete', url, + data=data, + headers=self.headers) + + def _request(self, method, *args, **kwargs): + return getattr(user.User.session, method)(*args, **kwargs) + + +def _request(method, *args, **kwargs): + client = HTTPClient.get_Instance() + return getattr(client, method)(*args, **kwargs) + + +def get(url): + return _request('get', url) + + +def post(url, data): + return _request('post', url, data) + + +def put(url, data): + return _request('put', url, data) + + +def delete(url, data=None): + return _request('delete', url, data) diff --git a/testapi/testapi-client/testapiclient/utils/identity.py b/testapi/testapi-client/testapiclient/utils/identity.py new file mode 100644 index 0000000..2aeb87a --- /dev/null +++ b/testapi/testapi-client/testapiclient/utils/identity.py @@ -0,0 +1,38 @@ +import functools +import os +import urllib + +import requests + +from testapiclient.utils import user + + +def _authenticate(username, password): + session = requests.Session() + hostname = '{}{}{}'.format(os.environ.get('testapi_cas_auth_url'), + urllib.quote(os.environ.get('testapi_url')), + os.environ.get('testapi_cas_signin_return')) + data = { + 'name': username, + 'pass': password, + 'form_id': 'user_login' + } + response = session.post(hostname, data) + if "login" not in response.text: + user.User.session = session + return response + + +def authenticate(xstep): + @functools.wraps(xstep) + def wrapper(self, parsed_args): + if(user.User.session is None): + username = parsed_args.u + password = parsed_args.p + if(username and password): + response = _authenticate(username, password) + if "login" in response.text: + print "Authentication has failed." + return + xstep(self, parsed_args) + return wrapper diff --git a/testapi/testapi-client/testapiclient/utils/url_parse.py b/testapi/testapi-client/testapiclient/utils/url_parse.py new file mode 100644 index 0000000..08f7a63 --- /dev/null +++ b/testapi/testapi-client/testapiclient/utils/url_parse.py @@ -0,0 +1,22 @@ +import os + +from six.moves.urllib import parse + + +def path_join(base, *urls): + def _path_join(base, url): + if not base.endswith('/'): + base += '/' + return parse.urljoin(base, url) + + urls = (base,) + urls + return reduce(_path_join, urls) + + +def query_join(base, **queries): + return base + '?' + parse.urlencode(queries) + + +def resource_join(url): + testapi_url = os.environ.get('testapi_url') + return path_join(testapi_url, url) diff --git a/testapi/testapi-client/testapiclient/utils/user.py b/testapi/testapi-client/testapiclient/utils/user.py new file mode 100644 index 0000000..7e72163 --- /dev/null +++ b/testapi/testapi-client/testapiclient/utils/user.py @@ -0,0 +1,2 @@ +class User(): + session = None -- cgit 1.2.3-korg