Add command to create, show, delete podmanager
This commit adds cli commands to create, show, delete podmanagers openstack valence podmanager create --help openstack valence podmanager show --help openstack valence podmanager delete --help Example: Create Podmanager request - openstack valence podmanager create <name> <url> --driver <driver> --auth type=<type> --auth username=<username> --auth password=<password> Show Podmanager - openstack valence podmanager show <podm-id> Delete Podmanager - openstack valence podmanager delete <podm-id1>, <podm-id2> Change-Id: Id5262d42232d592ea4de3de20ad88ee5c6aa03b9 Partially-Implements blueprint valenceclient
This commit is contained in:
parent
7f84237263
commit
f16f4a40c2
@ -6,3 +6,4 @@ pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
||||
oslo.utils>=3.20.0 # Apache-2.0
|
||||
oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0
|
||||
oslo.serialization!=2.19.1,>=1.10.0 # Apache-2.0
|
||||
osc-lib>=1.7.0 # Apache-2.0
|
||||
|
@ -29,6 +29,9 @@ openstack.cli.extension =
|
||||
|
||||
openstack.valence.v1 =
|
||||
valence_podmanager_list = valenceclient.osc.v1.podmanager:ListPodManagers
|
||||
valence_podmanager_create = valenceclient.osc.v1.podmanager:CreatePodManager
|
||||
valence_podmanager_delete = valenceclient.osc.v1.podmanager:DeletePodManagers
|
||||
valence_podmanager_show = valenceclient.osc.v1.podmanager:ShowPodManager
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
|
@ -15,6 +15,7 @@ testtools>=1.4.0 # MIT
|
||||
oslo.utils>=3.20.0 # Apache-2.0
|
||||
oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0
|
||||
oslo.serialization!=2.19.1,>=1.10.0 # Apache-2.0
|
||||
requests-mock>=1.1.0 # Apache-2.0
|
||||
|
||||
# releasenotes
|
||||
reno!=2.3.1,>=1.8.0 # Apache-2.0
|
||||
|
@ -14,7 +14,6 @@
|
||||
# under the License.
|
||||
|
||||
|
||||
import copy
|
||||
import functools
|
||||
import logging
|
||||
import requests
|
||||
@ -125,23 +124,24 @@ class HTTPClient(object):
|
||||
def _make_connection_url(self, url):
|
||||
return urlparse.urljoin(self.valence_url, url)
|
||||
|
||||
def _http_request(self, url, method, **kwargs):
|
||||
def _http_request(self, conn_url, method, **kwargs):
|
||||
"""Send an http request with the specified characteristics
|
||||
|
||||
Wrapper around request.Session.request to handle tasks such as
|
||||
setting headers and error handling.
|
||||
"""
|
||||
|
||||
kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {}))
|
||||
kwargs['headers'] = kwargs.get('headers', {})
|
||||
kwargs['headers'].setdefault('User-agent', USER_AGENT)
|
||||
|
||||
self.log_curl_request(method, url, kwargs)
|
||||
self.log_curl_request(method, conn_url, kwargs)
|
||||
|
||||
body = kwargs.pop('body', None)
|
||||
if body:
|
||||
kwargs['data'] = body
|
||||
conn_url = self._make_connection_url(url)
|
||||
headers = kwargs.pop('headers')
|
||||
|
||||
conn_url = self._make_connection_url(conn_url)
|
||||
try:
|
||||
resp = self.session.request(method, conn_url, **kwargs)
|
||||
resp = self.session.request(method, conn_url, headers=headers,
|
||||
data=body, json=kwargs)
|
||||
except requests.exceptions.RequestException as e:
|
||||
msg = (_("Error has occured while handling request for "
|
||||
"%(url)s: %(e)s") % dict(url=conn_url, e=e))
|
||||
@ -151,25 +151,25 @@ class HTTPClient(object):
|
||||
|
||||
self.log_http_response(resp, resp.text)
|
||||
body_iter = six.StringIO(resp.text)
|
||||
|
||||
if resp.status_code >= http_client.BAD_REQUEST:
|
||||
error_json = _extract_error_json(resp.text)
|
||||
raise exc.from_response(resp, error_json.get('faultstring'),
|
||||
error_json.get('debugfino'), method, url)
|
||||
error_json.get('debugfino'), method,
|
||||
conn_url)
|
||||
elif resp.status_code in (http_client.FOUND,
|
||||
http_client.USE_PROXY):
|
||||
return self._http_request(resp['location'], method, **kwargs)
|
||||
|
||||
return resp, body_iter
|
||||
|
||||
def json_request(self, method, url, **kwargs):
|
||||
def json_request(self, method, conn_url, **kwargs):
|
||||
kwargs.setdefault('headers', {})
|
||||
kwargs['headers'].setdefault('Content-Type', 'application/json')
|
||||
kwargs['headers'].setdefault('Accept', 'application/json')
|
||||
if 'body' in kwargs:
|
||||
kwargs['body'] = jsonutils.dump_as_bytes(kwargs['body'])
|
||||
|
||||
resp, body_iter = self._http_request(url, method, **kwargs)
|
||||
resp, body_iter = self._http_request(conn_url, method, **kwargs)
|
||||
content_type = resp.headers.get('Content-Type')
|
||||
if(resp.status_code in (http_client.NO_CONTENT,
|
||||
http_client.RESET_CONTENT)
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Copyright 2017 Intel, Inc.
|
||||
# Copyright 2017 NEC, Corp.
|
||||
#
|
||||
# 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
|
||||
@ -13,7 +13,9 @@
|
||||
# under the License.
|
||||
#
|
||||
|
||||
from osc_lib.cli import parseractions
|
||||
from osc_lib.command import command
|
||||
from osc_lib import exceptions
|
||||
from osc_lib import utils
|
||||
|
||||
|
||||
@ -32,3 +34,107 @@ class ListPodManagers(command.Lister):
|
||||
columns = ['uuid', 'name', 'url', 'driver', 'status', 'created_at',
|
||||
'updated_at']
|
||||
return (columns, (utils.get_dict_properties(s, columns) for s in obj))
|
||||
|
||||
|
||||
class CreatePodManager(command.ShowOne):
|
||||
_description = "Creates new podmanager"
|
||||
auth_required = False
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreatePodManager, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'name',
|
||||
metavar='<name>',
|
||||
help=('Name for the PodManager'))
|
||||
parser.add_argument(
|
||||
'url',
|
||||
metavar='<url>',
|
||||
help=('URL of the PodManager'))
|
||||
parser.add_argument(
|
||||
'--driver',
|
||||
metavar='<driver>',
|
||||
default='redfishv1',
|
||||
help=("PodManager driver, default is 'redfishv1'"))
|
||||
parser.add_argument(
|
||||
'--auth',
|
||||
metavar='<key=value>',
|
||||
required=True,
|
||||
action=parseractions.KeyValueAction,
|
||||
help=("auth information to connect to podmanager, repeat option "
|
||||
"to set each key. Accepted keys are type, username, password"
|
||||
"If type not specified 'basic' is taken by default"))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
auth = parsed_args.auth
|
||||
auth['type'] = auth.get('type', 'basic')
|
||||
|
||||
req = {
|
||||
'name': parsed_args.name,
|
||||
'url': parsed_args.url,
|
||||
'driver': parsed_args.driver,
|
||||
'authentication': [{'type': auth['type'],
|
||||
'auth_items': {
|
||||
'username': auth['username'],
|
||||
'password': auth['password']}}]
|
||||
}
|
||||
|
||||
client = self.app.client_manager.valence
|
||||
obj = client.create_podmanager(req)
|
||||
columns = ('uuid', 'name', 'url', 'driver', 'status', 'created_at',
|
||||
'updated_at')
|
||||
return (columns, (utils.get_dict_properties(obj, columns)))
|
||||
|
||||
|
||||
class DeletePodManagers(command.Command):
|
||||
_description = "Delete podmanagers"
|
||||
auth_required = False
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeletePodManagers, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'id',
|
||||
nargs='+',
|
||||
metavar='<id>',
|
||||
help=('Podmanagers id(s) to delete'))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
client = self.app.client_manager.valence
|
||||
count = 0
|
||||
for p in parsed_args.id:
|
||||
try:
|
||||
client.delete_podmanager(p)
|
||||
except Exception as e:
|
||||
count = count + 1
|
||||
self.log.error("podmanager %s deletion failed with error %s",
|
||||
p, str(e))
|
||||
|
||||
if count > 0:
|
||||
total = len(parsed_args.id)
|
||||
msg = (("%(result)s of %(total)s podmanagers(s) "
|
||||
"failed to delete.") % {'result': count, 'total': total})
|
||||
raise exceptions.CommandError(msg)
|
||||
|
||||
|
||||
class ShowPodManager(command.ShowOne):
|
||||
_description = "Show podmanager"
|
||||
auth_required = False
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowPodManager, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'id',
|
||||
metavar='<id>',
|
||||
help=('Podmanager id to show'))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
client = self.app.client_manager.valence
|
||||
obj = client.show_podmanager(parsed_args.id)
|
||||
columns = ('uuid', 'name', 'url', 'driver', 'status', 'created_at',
|
||||
'updated_at')
|
||||
return (columns, (utils.get_dict_properties(obj, columns)))
|
||||
|
@ -114,12 +114,12 @@ class HttpClientTest(utils.BaseTestCase):
|
||||
|
||||
client.json_request('GET', 'redfish/v1')
|
||||
|
||||
def test_server_http_not_valide_request(self):
|
||||
def test_server_http_not_valid_request(self):
|
||||
kwargs = {"valence_url": "http://localhost/"}
|
||||
client = http.HTTPClient(**kwargs)
|
||||
client.session.request = mock.Mock(
|
||||
side_effect=http.requests.exceptions.InvalidSchema)
|
||||
self.assertRaises(exc.ValidationError, client._http_request, 'GET',
|
||||
self.assertRaises(exc.ValidationError, client.json_request, 'GET',
|
||||
'http://localhost/')
|
||||
|
||||
@mock.patch.object(http.LOG, 'debug', autospec=True)
|
||||
@ -149,7 +149,7 @@ class HttpClientTest(utils.BaseTestCase):
|
||||
with mock.patch.object(client, 'session',
|
||||
autospec=True) as mock_session:
|
||||
mock_session.request.side_effect = iter([resp])
|
||||
response, body_iter = client._http_request('/redfish/v1/Nodes',
|
||||
'GET')
|
||||
response, body_iter = client.json_request('GET',
|
||||
'/redfish/v1/Nodes')
|
||||
|
||||
self.assertEqual(http_client.OK, response.status_code)
|
||||
|
0
valenceclient/tests/unit/osc/__init__.py
Normal file
0
valenceclient/tests/unit/osc/__init__.py
Normal file
28
valenceclient/tests/unit/osc/test_base.py
Normal file
28
valenceclient/tests/unit/osc/test_base.py
Normal file
@ -0,0 +1,28 @@
|
||||
# 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 argparse
|
||||
|
||||
import mock
|
||||
from osc_lib.tests import utils
|
||||
|
||||
|
||||
class TestValenceClient(utils.TestCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestValenceClient, self).setUp()
|
||||
self.namespace = argparse.Namespace()
|
||||
self.app.client_manager.session = mock.Mock()
|
||||
self.app.client_manager.valence = mock.Mock()
|
||||
self.valenceclient = self.app.client_manager.valence
|
||||
self.addCleanup(mock.patch.stopall)
|
92
valenceclient/tests/unit/osc/test_podmanager.py
Normal file
92
valenceclient/tests/unit/osc/test_podmanager.py
Normal file
@ -0,0 +1,92 @@
|
||||
# Copyright 2017 NEC, Corp.
|
||||
# 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 mock
|
||||
|
||||
from valenceclient.osc.v1 import podmanager
|
||||
from valenceclient.tests.unit.osc import test_base
|
||||
|
||||
|
||||
class TestCreatePodmanager(test_base.TestValenceClient):
|
||||
def test_create_podmanager(self):
|
||||
response = {"uuid": "test-id",
|
||||
"name": "test-podm",
|
||||
"url": "http://localhost",
|
||||
"driver": "redfishv1",
|
||||
"status": "Offline",
|
||||
"created_at": "2017-08-07 06:56:34 UTC",
|
||||
"updated_at": "2017-08-28 06:56:34 UTC"}
|
||||
|
||||
arglist = ['test-podm', 'http://localhost',
|
||||
'--auth', "username=user",
|
||||
'--auth', "password=pass"]
|
||||
verifylist = [
|
||||
('name', 'test-podm'),
|
||||
('url', 'http://localhost'),
|
||||
('auth', {'username': 'user', 'password': 'pass'}),
|
||||
|
||||
]
|
||||
|
||||
mocker = mock.Mock(return_value=response)
|
||||
self.valenceclient.create_podmanager = mocker
|
||||
cmd = podmanager.CreatePodManager(self.app, self.namespace)
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = list(cmd.take_action(parsed_args))
|
||||
filtered = [('uuid', 'name', 'url', 'driver', 'status', 'created_at',
|
||||
'updated_at'),
|
||||
('test-id', 'test-podm', 'http://localhost', 'redfishv1',
|
||||
'Offline', '2017-08-07 06:56:34 UTC',
|
||||
'2017-08-28 06:56:34 UTC')]
|
||||
self.assertEqual(filtered, result)
|
||||
|
||||
|
||||
class TestShowPolicy(test_base.TestValenceClient):
|
||||
def test_show_policy(self):
|
||||
podmanager_id = "test-id"
|
||||
arglist = [podmanager_id]
|
||||
verifylist = [
|
||||
('id', podmanager_id),
|
||||
]
|
||||
response = {"uuid": "test-id",
|
||||
"name": "test-podm",
|
||||
"url": "http://localhost",
|
||||
"driver": "redfishv1",
|
||||
"status": "Offline",
|
||||
"created_at": "2017-08-07 06:56:34 UTC",
|
||||
"updated_at": "2017-08-28 06:56:34 UTC"}
|
||||
|
||||
mocker = mock.Mock(return_value=response)
|
||||
self.valenceclient.show_podmanager = mocker
|
||||
cmd = podmanager.ShowPodManager(self.app, self.namespace)
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = list(cmd.take_action(parsed_args))
|
||||
filtered = [('uuid', 'name', 'url', 'driver', 'status', 'created_at',
|
||||
'updated_at'),
|
||||
('test-id', 'test-podm', 'http://localhost', 'redfishv1',
|
||||
'Offline', '2017-08-07 06:56:34 UTC',
|
||||
'2017-08-28 06:56:34 UTC')]
|
||||
self.assertEqual(filtered, result)
|
||||
|
||||
|
||||
class TestDeletePodmanager(test_base.TestValenceClient):
|
||||
def test_delete_podmanager(self):
|
||||
arglist = ['test-id']
|
||||
verifylist = [('id', ['test-id']), ]
|
||||
mocker = mock.Mock(return_value=None)
|
||||
self.valenceclient.delete_podmanager = mocker
|
||||
cmd = podmanager.DeletePodManagers(self.app, self.namespace)
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = cmd.take_action(parsed_args)
|
||||
mocker.assert_called_with('test-id')
|
||||
self.assertIsNone(result)
|
@ -18,11 +18,27 @@ from valenceclient.common import http
|
||||
|
||||
class Client(object):
|
||||
|
||||
podmanager_path = "/v1/pod_managers"
|
||||
podmanagers = "/v1/pod_managers"
|
||||
podmanager_path = "/v1/pod_managers/%s"
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.http_client = http.HTTPClient(**kwargs)
|
||||
|
||||
def list_podmanagers(self):
|
||||
resp, body = self.http_client.json_request('get', self.podmanager_path)
|
||||
resp, body = self.http_client.json_request('get', self.podmanagers)
|
||||
return body
|
||||
|
||||
def create_podmanager(self, request):
|
||||
resp, body = self.http_client.json_request('post', self.podmanagers,
|
||||
**request)
|
||||
return body
|
||||
|
||||
def delete_podmanager(self, id):
|
||||
resp, body = self.http_client.json_request('delete',
|
||||
self.podmanager_path % id)
|
||||
return body
|
||||
|
||||
def show_podmanager(self, id):
|
||||
resp, body = self.http_client.json_request('get',
|
||||
self.podmanager_path % id)
|
||||
return body
|
||||
|
Loading…
Reference in New Issue
Block a user