[Kimchi-devel] [PATCH 4/5] Return users and groups when fetching VM info

Aline Manera alinefm at linux.vnet.ibm.com
Fri Apr 11 20:58:00 UTC 2014


From: Aline Manera <alinefm at br.ibm.com>

In order to have more control over what users can use a virtual machine
under Kimchi, a VM should have users and groups associated with it.

Kimchi uses metadata information
(http://libvirt.org/formatdomain.html#elementsMetadata) to store users
and groups to the virtual machines. The data is stored as string
representations of Python lists.
Keep in mind that these security restrictions will not apply when using
other virtual machine managers (e.g. virsh, virt-manager, etc).

Users and groups stored in the VM are now returned when the user queries the
VM data. Currently, there is no way to associate users and groups to a VM.

The REST command below now returns the users and groups of every virtual machine:

/vms/:name GET: It now lists the users and groups associated with that VM.

{
  "users":[
    "user1",
    "user2"
  ],
  "groups":[
    "group1",
    "group2"
  ],
...
}

If there is no metadata information about users and groups, empty lists
will be displayed

Signed-off-by: Crístian Viana <vianac at linux.vnet.ibm.com>
Signed-off-by: Aline Manera <alinefm at br.ibm.com>

show

show
---
 docs/API.md               |    4 ++++
 src/kimchi/API.json       |   22 ++++++++++++++++++++++
 src/kimchi/control/vms.py |    4 +++-
 src/kimchi/i18n.py        |    4 ++++
 src/kimchi/mockmodel.py   |    4 +++-
 src/kimchi/model/vms.py   |   13 ++++++++++---
 tests/test_mockmodel.py   |    2 +-
 tests/test_model.py       |    4 +++-
 tests/test_rest.py        |    2 ++
 9 files changed, 52 insertions(+), 7 deletions(-)

diff --git a/docs/API.md b/docs/API.md
index 143c70c..b726b9c 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -94,6 +94,10 @@ the following general conventions:
         * port: The real port number of the graphics, vnc or spice. Users
                 can use this port to connect to the vm with general vnc/spice
                 clients.
+    * users: A list of system users who have permission to access the VM.
+      Default is: empty.
+    * groups: A list of system groups whose users have permission to access
+      the VM. Default is: empty.
 * **DELETE**: Remove the Virtual Machine
 * **PUT**: update the parameters of existed VM
     * name: New name for this VM (only applied for shutoff VM)
diff --git a/src/kimchi/API.json b/src/kimchi/API.json
index 5ca94e3..6294dc8 100644
--- a/src/kimchi/API.json
+++ b/src/kimchi/API.json
@@ -201,6 +201,28 @@
                     "type": "string",
                     "minLength": 1,
                     "error": "KCHVM0011E"
+                },
+                "users": {
+                    "description": "Array of users who have permission to the VM",
+                    "type": "array",
+                    "uniqueItems": true,
+                    "error": "KCHVM0022E",
+                    "items": {
+                        "description": "User name",
+                        "type": "string",
+                        "error": "KCHVM0023E"
+                    }
+                },
+                "groups": {
+                    "description": "Array of groups who have permission to the VM",
+                    "type": "array",
+                    "uniqueItems": true,
+                    "error": "KCHVM0024E",
+                    "items": {
+                        "description": "Group name",
+                        "type": "string",
+                        "error": "KCHVM0025E"
+                    }
                 }
             }
         },
diff --git a/src/kimchi/control/vms.py b/src/kimchi/control/vms.py
index e75b27f..63c1e24 100644
--- a/src/kimchi/control/vms.py
+++ b/src/kimchi/control/vms.py
@@ -53,7 +53,9 @@ class VM(Resource):
                 'icon': self.info['icon'],
                 'graphics': {'type': self.info['graphics']['type'],
                              'listen': self.info['graphics']['listen'],
-                             'port': self.info['graphics']['port']}
+                             'port': self.info['graphics']['port']},
+                'users': self.info['users'],
+                'groups': self.info['groups']
                 }
 
 
diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py
index 0bde5b9..20f9716 100644
--- a/src/kimchi/i18n.py
+++ b/src/kimchi/i18n.py
@@ -80,6 +80,10 @@ messages = {
     "KCHVM0019E": _("Unable to start virtual machine %(name)s. Details: %(err)s"),
     "KCHVM0020E": _("Unable to power off virtual machine %(name)s. Details: %(err)s"),
     "KCHVM0021E": _("Unable to delete virtual machine %(name)s. Details: %(err)s"),
+    "KCHVM0022E": _("User names list must be an array"),
+    "KCHVM0023E": _("User name must be a string"),
+    "KCHVM0024E": _("Group names list must be an array"),
+    "KCHVM0025E": _("Group name must be a string"),
 
     "KCHVMIF0001E": _("Interface %(iface)s does not exist in virtual machine %(name)s"),
     "KCHVMIF0002E": _("Network %(network)s specified for virtual machine %(name)s does not exist"),
diff --git a/src/kimchi/mockmodel.py b/src/kimchi/mockmodel.py
index bf17975..87ca21c 100644
--- a/src/kimchi/mockmodel.py
+++ b/src/kimchi/mockmodel.py
@@ -969,7 +969,9 @@ class MockVM(object):
                      'cpus': template_info['cpus'],
                      'icon': None,
                      'graphics': {'type': 'vnc', 'listen': '0.0.0.0',
-                                  'port': None}
+                                  'port': None},
+                     'users': ['user1', 'user2', 'root'],
+                     'groups': ['group1', 'group2', 'admin']
                      }
         self.info['graphics'].update(template_info['graphics'])
 
diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py
index 2425a43..ba091e5 100644
--- a/src/kimchi/model/vms.py
+++ b/src/kimchi/model/vms.py
@@ -34,8 +34,9 @@ from kimchi.model.config import CapabilitiesModel
 from kimchi.model.templates import TemplateModel
 from kimchi.model.utils import get_vm_name
 from kimchi.screenshot import VMScreenshot
-from kimchi.utils import kimchi_log
-from kimchi.utils import run_setfacl_set_attr, template_name_from_uri
+from kimchi.utils import kimchi_log, run_setfacl_set_attr
+from kimchi.utils import template_name_from_uri
+from kimchi.xmlutils import xpath_get_text
 
 
 DOM_STATE_MAP = {0: 'nostate',
@@ -304,6 +305,10 @@ class VMModel(object):
         res['io_throughput'] = vm_stats.get('disk_io', 0)
         res['io_throughput_peak'] = vm_stats.get('max_disk_io', 100)
 
+        xml = dom.XMLDesc(0)
+        users = xpath_get_text(xml, "/domain/metadata/kimchi/access/user")
+        groups = xpath_get_text(xml, "/domain/metadata/kimchi/access/group")
+
         return {'state': state,
                 'stats': res,
                 'uuid': dom.UUIDString(),
@@ -313,7 +318,9 @@ class VMModel(object):
                 'icon': icon,
                 'graphics': {"type": graphics_type,
                              "listen": graphics_listen,
-                             "port": graphics_port}
+                             "port": graphics_port},
+                'users': users,
+                'groups': groups
                 }
 
     def _vm_get_disk_paths(self, dom):
diff --git a/tests/test_mockmodel.py b/tests/test_mockmodel.py
index 0798701..9e258ce 100644
--- a/tests/test_mockmodel.py
+++ b/tests/test_mockmodel.py
@@ -135,7 +135,7 @@ class MockModelTests(unittest.TestCase):
         self.assertEquals(u'test', vms[0])
 
         keys = set(('state', 'stats', 'uuid', 'memory', 'cpus', 'screenshot',
-                    'icon', 'graphics'))
+                    'icon', 'graphics', 'users', 'groups'))
         stats_keys = set(('cpu_utilization',
                           'net_throughput', 'net_throughput_peak',
                           'io_throughput', 'io_throughput_peak'))
diff --git a/tests/test_model.py b/tests/test_model.py
index 3041196..00c02d3 100644
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -61,7 +61,7 @@ class ModelTests(unittest.TestCase):
         self.assertEquals('test', vms[0])
 
         keys = set(('state', 'stats', 'uuid', 'memory', 'cpus', 'screenshot',
-                    'icon', 'graphics'))
+                    'icon', 'graphics', 'users', 'groups'))
         stats_keys = set(('cpu_utilization',
                           'net_throughput', 'net_throughput_peak',
                           'io_throughput', 'io_throughput_peak'))
@@ -73,6 +73,8 @@ class ModelTests(unittest.TestCase):
         self.assertEquals(None, info['icon'])
         self.assertEquals(stats_keys, set(info['stats'].keys()))
         self.assertRaises(NotFoundError, inst.vm_lookup, 'nosuchvm')
+        self.assertEquals([], info['users'])
+        self.assertEquals([], info['groups'])
 
     @unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
     def test_vm_lifecycle(self):
diff --git a/tests/test_rest.py b/tests/test_rest.py
index 6bce606..9c2f997 100644
--- a/tests/test_rest.py
+++ b/tests/test_rest.py
@@ -181,6 +181,8 @@ class RestTests(unittest.TestCase):
         vm = json.loads(self.request('/vms/vm-1').read())
         self.assertEquals('vm-1', vm['name'])
         self.assertEquals('shutoff', vm['state'])
+        self.assertEquals(['user1', 'user2', 'root'], vm['users'])
+        self.assertEquals(['group1', 'group2', 'admin'], vm['groups'])
 
     def test_edit_vm(self):
         req = json.dumps({'name': 'test', 'cdrom': '/nonexistent.iso'})
-- 
1.7.10.4




More information about the Kimchi-devel mailing list