[PATCHv6 0/4] LDAP authorization

From: Royce Lv <lvroyce@linux.vnet.ibm.com> v1>v4, split user and group and be compatible to previous access tagging v5>v6, Update testcases. Royce Lv (4): Split users and groups for permission query Move validation to authorizaiton change vm permission tag Update test model for authentication and authorization docs/API.md | 19 ++++++---- src/kimchi/control/groups.py | 28 ++++++++++++++ src/kimchi/control/host.py | 14 ------- src/kimchi/control/users.py | 35 +++++++++++++++++ src/kimchi/i18n.py | 1 + src/kimchi/mockmodel.py | 4 ++ src/kimchi/model/groups.py | 67 +++++++++++++++++++++++++++++++++ src/kimchi/model/host.py | 19 ---------- src/kimchi/model/users.py | 90 ++++++++++++++++++++++++++++++++++++++++++++ src/kimchi/model/vms.py | 65 ++++++++++++++++++++------------ tests/test_authorization.py | 3 +- tests/test_model.py | 3 +- tests/test_rest.py | 4 +- tests/utils.py | 3 +- 14 files changed, 284 insertions(+), 71 deletions(-) create mode 100644 src/kimchi/control/groups.py create mode 100644 src/kimchi/control/users.py create mode 100644 src/kimchi/model/groups.py create mode 100644 src/kimchi/model/users.py -- 1.8.3.2

From: Royce Lv <lvroyce@linux.vnet.ibm.com> Put ldap validation in a single function to resue in authorization. Tested: 1. LDAP: GET /users?_user_id=a_valid_user_id GET /users?_user_id=invalid_user_id GET /groups 2. PAM: GET /users GET /groups Signed-off-by: Royce Lv <lvroyce@linux.vnet.ibm.com> --- docs/API.md | 19 ++++++---- src/kimchi/control/groups.py | 28 ++++++++++++++ src/kimchi/control/host.py | 14 ------- src/kimchi/control/users.py | 35 +++++++++++++++++ src/kimchi/i18n.py | 1 + src/kimchi/model/groups.py | 67 +++++++++++++++++++++++++++++++++ src/kimchi/model/host.py | 19 ---------- src/kimchi/model/users.py | 90 ++++++++++++++++++++++++++++++++++++++++++++ src/kimchi/model/vms.py | 4 +- tests/test_rest.py | 4 +- 10 files changed, 236 insertions(+), 45 deletions(-) create mode 100644 src/kimchi/control/groups.py create mode 100644 src/kimchi/control/users.py create mode 100644 src/kimchi/model/groups.py create mode 100644 src/kimchi/model/users.py diff --git a/docs/API.md b/docs/API.md index 6c36bb1..2c6aa44 100644 --- a/docs/API.md +++ b/docs/API.md @@ -846,23 +846,26 @@ Contains information of host. * swupdate: Start the update of packages in background and return a Task resource * task resource. * See Resource: Task * -### Resource: Host users +### Resource: Users -**URI:** /host/users -List of system users in the host. +**URI:** /users +List of available users. **Methods:** -* **GET**: Retrieve list of system users in the host. +* **GET**: Retrieve list of available users. + * Parameters: + * _user_id: Validate whether user exists. + Essential for 'ldap' authentication. -### Resource: Host groups +### Resource: Groups -**URI:** /host/groups -List of system groups in the host. +**URI:** /groups +List of available groups. **Methods:** -* **GET**: Retrieve list of system groups in the host. +* **GET**: Retrieve list of available groups, only support 'pam' authentication. ### Resource: HostStats diff --git a/src/kimchi/control/groups.py b/src/kimchi/control/groups.py new file mode 100644 index 0000000..f18b2ab --- /dev/null +++ b/src/kimchi/control/groups.py @@ -0,0 +1,28 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from kimchi.control.base import SimpleCollection +from kimchi.control.utils import UrlSubNode + + +@UrlSubNode('groups', True) +class Groups(SimpleCollection): + def __init__(self, model): + super(Groups, self).__init__(model) + self.role_key = 'guests' diff --git a/src/kimchi/control/host.py b/src/kimchi/control/host.py index 4362da7..5a185e3 100644 --- a/src/kimchi/control/host.py +++ b/src/kimchi/control/host.py @@ -36,8 +36,6 @@ class Host(Resource): self.devices = Devices(self.model) self.packagesupdate = PackagesUpdate(self.model) self.repositories = Repositories(self.model) - self.users = Users(self.model) - self.groups = Groups(self.model) self.swupdate = self.generate_action_handler_task('swupdate') @property @@ -159,15 +157,3 @@ class Repository(Resource): @property def data(self): return self.info - - -class Users(SimpleCollection): - def __init__(self, model): - super(Users, self).__init__(model) - self.role_key = 'guests' - - -class Groups(SimpleCollection): - def __init__(self, model): - super(Groups, self).__init__(model) - self.role_key = 'guests' diff --git a/src/kimchi/control/users.py b/src/kimchi/control/users.py new file mode 100644 index 0000000..45603d0 --- /dev/null +++ b/src/kimchi/control/users.py @@ -0,0 +1,35 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013-2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +from kimchi.control.base import SimpleCollection +from kimchi.control.utils import get_class_name, model_fn, UrlSubNode +from kimchi.template import render + + +@UrlSubNode('users', True) +class Users(SimpleCollection): + def __init__(self, model): + super(Users, self).__init__(model) + self.role_key = 'guests' + + def get(self, filter_params): + res_list = [] + get_list = getattr(self.model, model_fn(self, 'get_list')) + res_list = get_list(*self.model_args, **filter_params) + return render(get_class_name(self), res_list) diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py index 8f6b67e..3d925b3 100644 --- a/src/kimchi/i18n.py +++ b/src/kimchi/i18n.py @@ -40,6 +40,7 @@ messages = { "KCHAUTH0001E": _("Authentication failed for user '%(username)s'. [Error code: %(code)s]"), "KCHAUTH0002E": _("You are not authorized to access Kimchi"), "KCHAUTH0003E": _("Specify %(item)s to login into Kimchi"), + "KCHAUTH0004E": _("User %(user_id)s not found with given LDAP settings."), "KCHAUTH0005E": _("Invalid LDAP configuration: %(item)s : %(value)s"), "KCHDEVS0001E": _('Unknown "_cap" specified'), diff --git a/src/kimchi/model/groups.py b/src/kimchi/model/groups.py new file mode 100644 index 0000000..0af3f8f --- /dev/null +++ b/src/kimchi/model/groups.py @@ -0,0 +1,67 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import grp + +from kimchi.config import config + + +class GroupsModel(object): + def __init__(self, **args): + auth_type = config.get("authentication", "method") + for klass in GroupsModel.__subclasses__(): + if auth_type == klass.auth_type: + self.grp = klass(**args) + + def get_list(self, **args): + if hasattr(self.grp, '_get_list'): + return self.grp._get_list(**args) + else: + return list() + + def validate(self, gid): + return self.grp._validate(gid) + + +class PAMGroupsModel(GroupsModel): + auth_type = 'pam' + + def __init__(self, **kargs): + pass + + def _get_list(self): + return sorted([group.gr_name + for group in grp.getgrall()]) + + def _validate(self, gid): + try: + grp.getgrnam(gid) + except KeyError: + return False + return True + + +class LDAPGroupsModel(GroupsModel): + auth_type = 'ldap' + + def __init__(self, **kargs): + pass + + def _validate(self, gid): + return False diff --git a/src/kimchi/model/host.py b/src/kimchi/model/host.py index 3b43b95..dff89cb 100644 --- a/src/kimchi/model/host.py +++ b/src/kimchi/model/host.py @@ -17,12 +17,10 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -import grp import libvirt import os import time import platform -import pwd from collections import defaultdict import psutil @@ -458,20 +456,3 @@ class RepositoryModel(object): raise InvalidOperation('KCHREPOS0014E') return self._repositories.removeRepository(repo_id) - - -class UsersModel(object): - def __init__(self, **kargs): - pass - - def get_list(self): - return [user.pw_name for user in pwd.getpwall() - if user.pw_shell.rsplit("/")[-1] not in ["nologin", "false"]] - - -class GroupsModel(object): - def __init__(self, **kargs): - pass - - def get_list(self): - return [group.gr_name for group in grp.getgrall()] diff --git a/src/kimchi/model/users.py b/src/kimchi/model/users.py new file mode 100644 index 0000000..1422bae --- /dev/null +++ b/src/kimchi/model/users.py @@ -0,0 +1,90 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2014 +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import ldap +import pwd + +from kimchi.config import config +from kimchi.exception import NotFoundError + + +class UsersModel(object): + def __init__(self, **args): + auth_type = config.get("authentication", "method") + for klass in UsersModel.__subclasses__(): + if auth_type == klass.auth_type: + self.user = klass(**args) + + def get_list(self, **args): + return self.user._get_list(**args) + + def validate(self, user): + return self.user._validate(user) + + +class PAMUsersModel(UsersModel): + auth_type = 'pam' + + def __init__(self, **kargs): + pass + + def _get_list(self): + return [user.pw_name for user in pwd.getpwall() + if user.pw_shell.rsplit("/")[-1] not in ["nologin", "false"]] + + def _validate(self, user): + try: + return user in self._get_list() + except: + return False + + +class LDAPUsersModel(UsersModel): + auth_type = 'ldap' + + def __init__(self, **kargs): + pass + + def _get_list(self, _user_id=''): + return self._get_user(_user_id) + + def _validate(self, user): + try: + self._get_user(user) + return True + except NotFoundError: + return False + + def _get_user(self, _user_id): + ldap_server = config.get("authentication", "ldap_server").strip('"') + ldap_search_base = config.get( + "authentication", "ldap_search_base").strip('"') + ldap_search_filter = config.get( + "authentication", "ldap_search_filter", + vars={"username": _user_id.encode("utf-8")}).strip('"') + + connect = ldap.open(ldap_server) + try: + result = connect.search_s( + ldap_search_base, ldap.SCOPE_SUBTREE, ldap_search_filter) + if len(result) == 0: + raise NotFoundError("KCHAUTH0004E", {'user_id': _user_id}) + return result[0][1] + except ldap.NO_SUCH_OBJECT: + raise NotFoundError("KCHAUTH0004E", {'user_id': _user_id}) diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index d861157..7ad5858 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -263,8 +263,8 @@ class VMModel(object): self.objstore = kargs['objstore'] self.caps = CapabilitiesModel(**kargs) self.vmscreenshot = VMScreenshotModel(**kargs) - self.users = import_class('kimchi.model.host.UsersModel')(**kargs) - self.groups = import_class('kimchi.model.host.GroupsModel')(**kargs) + self.users = import_class('kimchi.model.users.UsersModel')(**kargs) + self.groups = import_class('kimchi.model.groups.GroupsModel')(**kargs) self.vms = VMsModel(**kargs) self.task = TaskModel(**kargs) self.storagepool = model.storagepools.StoragePoolModel(**kargs) diff --git a/tests/test_rest.py b/tests/test_rest.py index 0f6cd6d..2e5cff1 100644 --- a/tests/test_rest.py +++ b/tests/test_rest.py @@ -282,7 +282,7 @@ class RestTests(unittest.TestCase): self.assertEquals(params[key], vm[key]) # change only VM users - groups are not changed (default is empty) - resp = self.request('/host/users', '{}', 'GET') + resp = self.request('/users', '{}', 'GET') users = json.loads(resp.read()) req = json.dumps({'users': users}) resp = self.request('/vms/∨м-црdαtеd', req, 'PUT') @@ -291,7 +291,7 @@ class RestTests(unittest.TestCase): self.assertEquals(users, info['users']) # change only VM groups - users are not changed (default is empty) - resp = self.request('/host/groups', '{}', 'GET') + resp = self.request('/groups', '{}', 'GET') groups = json.loads(resp.read()) req = json.dumps({'groups': groups}) resp = self.request('/vms/∨м-црdαtеd', req, 'PUT') -- 1.8.3.2

From: Royce Lv <lvroyce@linux.vnet.ibm.com> Put validation in user and group class instead of validate in metadata update, so that different type of authorization can use their own authentication to validate input value. Signed-off-by: Royce Lv <lvroyce@linux.vnet.ibm.com> --- src/kimchi/model/vms.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index 7ad5858..eb8c831 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -581,16 +581,16 @@ class VMModel(object): users = groups = None if "users" in params: users = params["users"] - invalid_users = set(users) - set(self.users.get_list()) - if len(invalid_users) != 0: - raise InvalidParameter("KCHVM0027E", - {'users': ", ".join(invalid_users)}) + for user in users: + if not self.users.validate(user): + raise InvalidParameter("KCHVM0027E", + {'users': user}) if "groups" in params: groups = params["groups"] - invalid_groups = set(groups) - set(self.groups.get_list()) - if len(invalid_groups) != 0: - raise InvalidParameter("KCHVM0028E", - {'groups': ", ".join(invalid_groups)}) + for group in groups: + if not self.groups.validate(group): + raise InvalidParameter("KCHVM0028E", + {'groups': group}) if users is None and groups is None: return -- 1.8.3.2

From: Royce Lv <lvroyce@linux.vnet.ibm.com> Add authorization type to vm tag, and update set/retrieve access tag accordingly. So that we can switch between different types of authentication. Signed-off-by: Royce Lv <lvroyce@linux.vnet.ibm.com> --- src/kimchi/model/vms.py | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index eb8c831..9f2a5eb 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -31,7 +31,7 @@ import libvirt from cherrypy.process.plugins import BackgroundTask from kimchi import model, vnc -from kimchi.config import READONLY_POOL_TYPE +from kimchi.config import READONLY_POOL_TYPE, config from kimchi.exception import InvalidOperation, InvalidParameter from kimchi.exception import NotFoundError, OperationFailed from kimchi.model.config import CapabilitiesModel @@ -46,6 +46,7 @@ from kimchi.utils import add_task, get_next_clone_name, import_class from kimchi.utils import kimchi_log, run_setfacl_set_attr from kimchi.utils import template_name_from_uri from kimchi.xmlutils.utils import xpath_get_text, xml_item_update +from kimchi.xmlutils.utils import dictize DOM_STATE_MAP = {0: 'nostate', @@ -568,13 +569,16 @@ class VMModel(object): 'err': e.message}) def _build_access_elem(self, users, groups): - access = E.access() + auth = config.get("authentication", "method") + auth_elem = E.auth(type=auth) for user in users: - access.append(E.user(user)) + auth_elem.append(E.user(user)) for group in groups: - access.append(E.group(group)) + auth_elem.append(E.group(group)) + access = E.access() + access.append(auth_elem) return access def _vm_update_access_metadata(self, dom, params): @@ -595,17 +599,33 @@ class VMModel(object): if users is None and groups is None: return - access_xml = (get_metadata_node(dom, "access", - self.caps.metadata_support) or - """<access></access>""") - old_users = xpath_get_text(access_xml, "/access/user") - old_groups = xpath_get_text(access_xml, "/access/group") + old_users, old_groups = self._get_access_info(dom) users = old_users if users is None else users groups = old_groups if groups is None else groups node = self._build_access_elem(users, groups) set_metadata_node(dom, node, self.caps.metadata_support) + def _get_access_info(self, dom): + users = groups = list() + access_xml = (get_metadata_node(dom, "access", + self.caps.metadata_support) or + """<access></access>""") + access_info = dictize(access_xml) + auth = config.get("authentication", "method") + if ('auth' in access_info['access'] and + ('type' in access_info['access']['auth'] or + len(access_info['access']['auth']) > 1)): + users = xpath_get_text(access_xml, + "/access/auth[@type='%s']/user" % auth) + groups = xpath_get_text(access_xml, + "/access/auth[@type='%s']/group" % auth) + elif auth == 'pam': + # Compatible to old permission tagging + users = xpath_get_text(access_xml, "/access/user") + groups = xpath_get_text(access_xml, "/access/group") + return users, groups + @staticmethod def vm_get_os_metadata(dom, metadata_support): os_xml = (get_metadata_node(dom, "os", metadata_support) or @@ -735,12 +755,7 @@ class VMModel(object): res['net_throughput_peak'] = vm_stats.get('max_net_io', 100) res['io_throughput'] = vm_stats.get('disk_io', 0) res['io_throughput_peak'] = vm_stats.get('max_disk_io', 100) - - access_xml = (get_metadata_node(dom, "access", - self.caps.metadata_support) or - """<access></access>""") - users = xpath_get_text(access_xml, "/access/user") - groups = xpath_get_text(access_xml, "/access/group") + users, groups = self._get_access_info(dom) return {'name': name, 'state': state, -- 1.8.3.2

From: Royce Lv <lvroyce@linux.vnet.ibm.com> As test model includes test against pam user/group listing, using pam authentication instead of fake authentication. Also change test cases which used fake user/group update to use pam user validation and update. Signed-off-by: Royce Lv <lvroyce@linux.vnet.ibm.com> --- src/kimchi/mockmodel.py | 4 ++++ tests/test_authorization.py | 3 ++- tests/test_model.py | 3 ++- tests/utils.py | 3 ++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/kimchi/mockmodel.py b/src/kimchi/mockmodel.py index 9089ef6..5f91d7d 100644 --- a/src/kimchi/mockmodel.py +++ b/src/kimchi/mockmodel.py @@ -33,6 +33,8 @@ from kimchi.model.host import DeviceModel from kimchi.model.model import Model from kimchi.model.storagevolumes import StorageVolumesModel from kimchi.model.templates import LibvirtVMTemplate +from kimchi.model.users import PAMUsersModel +from kimchi.model.groups import PAMGroupsModel from kimchi.objectstore import ObjectStore from kimchi.utils import add_task, get_next_clone_name from kimchi.vmtemplate import VMTemplate @@ -99,6 +101,8 @@ class MockModel(Model): LibvirtVMTemplate._get_volume_path = self._get_volume_path VMTemplate.get_iso_info = self._probe_image imageinfo.probe_image = self._probe_image + PAMUsersModel.auth_type = 'fake' + PAMGroupsModel.auth_type = 'fake' def reset(self): MockModel._mock_vms = {} diff --git a/tests/test_authorization.py b/tests/test_authorization.py index a8a94fe..4fcc496 100644 --- a/tests/test_authorization.py +++ b/tests/test_authorization.py @@ -131,7 +131,8 @@ class AuthorizationTests(unittest.TestCase): model.vms_create({'name': u'test-groupa', 'template': '/templates/test'}) - model.vm_update(u'test-groupa', {'groups': ['wheel']}) + a_group = model.groups_get_list()[0] + model.vm_update(u'test-groupa', {'groups': [a_group]}) resp = self.request('/vms', '{}', 'GET') self.assertEquals(200, resp.status) diff --git a/tests/test_model.py b/tests/test_model.py index c68b01f..0b91edc 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -38,7 +38,7 @@ import iso_gen import kimchi.objectstore import utils from kimchi import netinfo -from kimchi.config import paths +from kimchi.config import config, paths from kimchi.exception import ImageFormatError, InvalidOperation from kimchi.exception import InvalidParameter, NotFoundError, OperationFailed from kimchi.iscsi import TargetClient @@ -934,6 +934,7 @@ class ModelTests(unittest.TestCase): 'new-test', params) def test_vm_edit(self): + config.set("authentication", "method", "pam") inst = model.Model(None, objstore_loc=self.tmp_store) diff --git a/tests/utils.py b/tests/utils.py index f846d48..c692041 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -20,6 +20,7 @@ import base64 import cherrypy +import grp import httplib import json import os @@ -181,7 +182,7 @@ class FakeUser(User): self.user[USER_ROLES] = dict.fromkeys(tabs, 'user') def get_groups(self): - return ['groupA', 'groupB', 'wheel'] + return sorted([group.gr_name for group in grp.getgrall()])[0:3] def get_roles(self): if self.sudo: -- 1.8.3.2

The tests are failing for me: ====================================================================== FAIL: test_edit_vm (test_rest.HttpsRestTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "test_rest.py", line 289, in test_edit_vm self.assertEquals(200, resp.status) AssertionError: 200 != 400 ====================================================================== FAIL: test_edit_vm (test_rest.RestTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "test_rest.py", line 289, in test_edit_vm self.assertEquals(200, resp.status) AssertionError: 200 != 400 ---------------------------------------------------------------------- Ran 169 tests in 420.207s [19/Nov/2014:12:27:22] HTTP Request Headers: AUTHORIZATION: Basic cm9vdDpsZXRtZWluIQ== Content-Length: 2 HOST: 127.0.0.1 CONNECTION: close Remote-Addr: 127.0.0.1 X-REAL-IP: 127.0.0.1 ACCEPT: application/json X-FORWARDED-FOR: 127.0.0.1 Content-Type: application/json ACCEPT-ENCODING: identity [19/Nov/2014:12:27:22] HTTP Traceback (most recent call last): File "/usr/lib/python2.7/site-packages/cherrypy/_cprequest.py", line 656, in respond response.body = self.handler() File "/usr/lib/python2.7/site-packages/cherrypy/lib/encoding.py", line 188, in __call__ self.body = self.oldhandler(*args, **kwargs) File "/usr/lib/python2.7/site-packages/cherrypy/_cpdispatch.py", line 34, in __call__ return self.callable(*self.args, **self.kwargs) File "/home/alinefm/kimchi/src/kimchi/control/base.py", line 325, in index return self.get(filter_params) File "/home/alinefm/kimchi/src/kimchi/control/users.py", line 34, in get res_list = get_list(*self.model_args, **filter_params) File "/home/alinefm/kimchi/src/kimchi/model/users.py", line 35, in get_list return self.user._get_list(**args) AttributeError: 'UsersModel' object has no attribute 'user' On 11/19/2014 09:59 AM, lvroyce0210@gmail.com wrote:
From: Royce Lv <lvroyce@linux.vnet.ibm.com>
v1>v4, split user and group and be compatible to previous access tagging v5>v6, Update testcases.
Royce Lv (4): Split users and groups for permission query Move validation to authorizaiton change vm permission tag Update test model for authentication and authorization
docs/API.md | 19 ++++++---- src/kimchi/control/groups.py | 28 ++++++++++++++ src/kimchi/control/host.py | 14 ------- src/kimchi/control/users.py | 35 +++++++++++++++++ src/kimchi/i18n.py | 1 + src/kimchi/mockmodel.py | 4 ++ src/kimchi/model/groups.py | 67 +++++++++++++++++++++++++++++++++ src/kimchi/model/host.py | 19 ---------- src/kimchi/model/users.py | 90 ++++++++++++++++++++++++++++++++++++++++++++ src/kimchi/model/vms.py | 65 ++++++++++++++++++++------------ tests/test_authorization.py | 3 +- tests/test_model.py | 3 +- tests/test_rest.py | 4 +- tests/utils.py | 3 +- 14 files changed, 284 insertions(+), 71 deletions(-) create mode 100644 src/kimchi/control/groups.py create mode 100644 src/kimchi/control/users.py create mode 100644 src/kimchi/model/groups.py create mode 100644 src/kimchi/model/users.py

Seems it is related to module load order, I will adjust mockmodel to fix this problem. On 2014年11月19日 22:29, Aline Manera wrote:
The tests are failing for me:
====================================================================== FAIL: test_edit_vm (test_rest.HttpsRestTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "test_rest.py", line 289, in test_edit_vm self.assertEquals(200, resp.status) AssertionError: 200 != 400
====================================================================== FAIL: test_edit_vm (test_rest.RestTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "test_rest.py", line 289, in test_edit_vm self.assertEquals(200, resp.status) AssertionError: 200 != 400
---------------------------------------------------------------------- Ran 169 tests in 420.207s
[19/Nov/2014:12:27:22] HTTP Request Headers: AUTHORIZATION: Basic cm9vdDpsZXRtZWluIQ== Content-Length: 2 HOST: 127.0.0.1 CONNECTION: close Remote-Addr: 127.0.0.1 X-REAL-IP: 127.0.0.1 ACCEPT: application/json X-FORWARDED-FOR: 127.0.0.1 Content-Type: application/json ACCEPT-ENCODING: identity [19/Nov/2014:12:27:22] HTTP Traceback (most recent call last): File "/usr/lib/python2.7/site-packages/cherrypy/_cprequest.py", line 656, in respond response.body = self.handler() File "/usr/lib/python2.7/site-packages/cherrypy/lib/encoding.py", line 188, in __call__ self.body = self.oldhandler(*args, **kwargs) File "/usr/lib/python2.7/site-packages/cherrypy/_cpdispatch.py", line 34, in __call__ return self.callable(*self.args, **self.kwargs) File "/home/alinefm/kimchi/src/kimchi/control/base.py", line 325, in index return self.get(filter_params) File "/home/alinefm/kimchi/src/kimchi/control/users.py", line 34, in get res_list = get_list(*self.model_args, **filter_params) File "/home/alinefm/kimchi/src/kimchi/model/users.py", line 35, in get_list return self.user._get_list(**args) AttributeError: 'UsersModel' object has no attribute 'user'
On 11/19/2014 09:59 AM, lvroyce0210@gmail.com wrote:
From: Royce Lv <lvroyce@linux.vnet.ibm.com>
v1>v4, split user and group and be compatible to previous access tagging v5>v6, Update testcases.
Royce Lv (4): Split users and groups for permission query Move validation to authorizaiton change vm permission tag Update test model for authentication and authorization
docs/API.md | 19 ++++++---- src/kimchi/control/groups.py | 28 ++++++++++++++ src/kimchi/control/host.py | 14 ------- src/kimchi/control/users.py | 35 +++++++++++++++++ src/kimchi/i18n.py | 1 + src/kimchi/mockmodel.py | 4 ++ src/kimchi/model/groups.py | 67 +++++++++++++++++++++++++++++++++ src/kimchi/model/host.py | 19 ---------- src/kimchi/model/users.py | 90 ++++++++++++++++++++++++++++++++++++++++++++ src/kimchi/model/vms.py | 65 ++++++++++++++++++++------------ tests/test_authorization.py | 3 +- tests/test_model.py | 3 +- tests/test_rest.py | 4 +- tests/utils.py | 3 +- 14 files changed, 284 insertions(+), 71 deletions(-) create mode 100644 src/kimchi/control/groups.py create mode 100644 src/kimchi/control/users.py create mode 100644 src/kimchi/model/groups.py create mode 100644 src/kimchi/model/users.py
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel
participants (3)
-
Aline Manera
-
lvroyce0210@gmail.com
-
Royce Lv