[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] Added support for state records in Xend, for keeping storage and network



# HG changeset patch
# User Ewan Mellor <ewan@xxxxxxxxxxxxx>
# Date 1167057505 0
# Node ID ae3f3dd40df45bbaf4619679023ba354ac470bc2
# Parent  4e079a8496b7521f60562d09ca285c0dd436c37d
Added support for state records in Xend, for keeping storage and network
details.

By Alastair Tse <atse@xxxxxxxxxxxxx>.

Signed-off-by: Ewan Mellor <ewan@xxxxxxxxxxxxx>
---
 tools/python/xen/xend/XendRoot.py       |    8 +
 tools/python/xen/xend/XendStateStore.py |  210 ++++++++++++++++++++++++++++++++
 2 files changed, 218 insertions(+)

diff -r 4e079a8496b7 -r ae3f3dd40df4 tools/python/xen/xend/XendRoot.py
--- a/tools/python/xen/xend/XendRoot.py Mon Dec 25 14:32:41 2006 +0000
+++ b/tools/python/xen/xend/XendRoot.py Mon Dec 25 14:38:25 2006 +0000
@@ -103,6 +103,9 @@ class XendRoot:
 
     """Default session storage path."""
     xend_domains_path_default = '/var/lib/xend/domains'
+
+    """Default xend management state storage."""
+    xend_state_path_default = '/var/lib/xend/state'
 
     components = {}
 
@@ -263,6 +266,11 @@ class XendRoot:
         """
         return self.get_config_value("xend-domains-path", 
self.xend_domains_path_default)
 
+    def get_xend_state_path(self):
+        """ Get the path for persistent domain configuration storage
+        """
+        return self.get_config_value("xend-state-path", 
self.xend_state_path_default)    
+
     def get_network_script(self):
         """@return the script used to alter the network configuration when
         Xend starts and stops, or None if no such script is specified."""
diff -r 4e079a8496b7 -r ae3f3dd40df4 tools/python/xen/xend/XendStateStore.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/xen/xend/XendStateStore.py   Mon Dec 25 14:38:25 2006 +0000
@@ -0,0 +1,210 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2004, 2005 Mike Wray <mike.wray@xxxxxx>
+# Copyright (c) 2006 Xensource Inc.
+#============================================================================
+
+import os
+
+from xen.xend import uuid
+from xen.xend.XendLogging import log
+from xml.dom import minidom
+from xml.dom import Node
+
+class XendStateStore:
+    """Manages persistent storage of Xend's internal state, mainly
+    relating to API objects.
+
+    It stores objects atomically in the file system as flat XML files
+    categorised by their 'class'.
+
+    For example:
+
+    /var/lib/xend/state/cpu.xml will contain the host cpu state
+    /var/lib/xend/state/sr.xml  will contain the storage repository state.
+
+    For the application, it will load the state via this class:
+
+    load_state('cpu') will return a marshalled dictionary object
+    containing the cpu state.
+
+    save_state('cpu', dict) will save the state contained in the dictionary
+    object about the 'cpu'.
+
+    The state is stored where each top level element has a UUID in its
+    attributes. eg:
+
+    host['49c01812-3c28-1ad4-a59d-2a3f81b13ec2'] = {
+       'name': 'norwich',
+       'desc': 'Test Xen Host',
+       'cpu': {'6fc2d1ed-7eb0-4c9d-8006-3657d5483ae0': <obj>,
+               '669df3b8-62be-4e61-800b-bbe8ee63a760': <obj>}
+    }
+
+    will turn into:
+
+    <hosts>
+       <host uuid='49c01812-3c28-1ad4-a59d-2a3f81b13ec2'>
+           <name type='string'>norwich</name>
+           <description type='string'>Test Xen Host</description>
+           <cpu uuid='6fc2d1ed-7eb0-4c9d-8006-3657d5483ae0' />
+           <cpu uuid='669df3b8-62be-4e61-800b-bbe8ee63a760' />
+       </host>
+    </hosts>
+
+    Note that it only dumps one level, so the references to CPU are
+    stored in a separate file.
+
+    """
+
+    def __init__(self, base = "/var/lib/xend/state"):
+        self.base = base
+        if not os.path.exists(self.base):
+            os.makedirs(self.base)
+
+    def _xml_file(self, cls):
+        """Return the absolute filename of the XML state storage file.
+
+        @param cls: name of the class.
+        @type  cls: string
+        @rtype: string
+        @return absolute filename of XML file to write/read from.
+        """
+        return os.path.join(self.base, '%s.xml' % cls)
+
+    def load_state(self, cls):
+        """Load the saved state of a class from persistent XML storage.
+
+        References loaded from the XML will just point to an empty
+        dictionary which the caller will need to replace manually.
+
+        @param cls: name of the class to load.
+        @type  cls: string
+        @rtype: dict
+        """
+        
+        xml_path = self._xml_file(cls)
+        if not os.path.exists(xml_path):
+            return {}
+
+        dom = minidom.parse(xml_path)
+        root = dom.documentElement
+        state = {}
+
+        for child in root.childNodes:
+            if child.nodeType != Node.ELEMENT_NODE:
+                continue # skip non element nodes
+                
+            uuid = child.getAttribute('uuid')
+            cls_dict = {}
+            for val_elem in child.childNodes:
+                if val_elem.nodeType != Node.ELEMENT_NODE:
+                    continue # skip non element nodes
+                
+                val_name = val_elem.tagName
+                val_type = val_elem.getAttribute('type').encode('utf8')
+                val_uuid = val_elem.getAttribute('uuid').encode('utf8')
+                val_elem.normalize()
+                val_text = ''
+                if val_elem.firstChild:
+                    val_text = val_elem.firstChild.nodeValue.strip()
+                
+                if val_type == '' and val_uuid != '':
+                    # this is a reference
+                    if val_name not in cls_dict:
+                        cls_dict[val_name] = {}
+                    cls_dict[val_name][val_uuid] = None
+                elif val_type == 'string':
+                    cls_dict[val_name] = val_text.encode('utf8')
+                elif val_type == 'float':
+                    cls_dict[val_name] = float(val_text)
+                elif val_type == 'int':
+                    cls_dict[val_name] = int(val_text)
+                elif val_type == 'bool':
+                    cls_dict[val_name] = bool(int(val_text))
+            state[uuid] = cls_dict
+
+        return state
+
+    def save_state(self, cls, state):
+        """Save a Xen API record struct into an XML persistent storage
+        for future loading when Xend restarts.
+
+        If we encounter a dictionary or a list, we only store the
+        keys because they are going to be UUID references to another
+        object.
+
+        @param cls: Class name (singular) of the record
+        @type  cls: string
+        @param state: a Xen API struct of the state of the class.
+        @type  state: dict
+        @rtype: None
+        """
+        
+        xml_path = self._xml_file(cls)
+
+        doc = minidom.getDOMImplementation().createDocument(None,
+                                                            cls + 's',
+                                                            None)
+        root = doc.documentElement
+
+        # Marshall a dictionary into our custom XML file format.
+        for uuid, info in state.items():
+            node = doc.createElement(cls)
+            root.appendChild(node)
+            node.setAttribute('uuid', uuid)
+            
+            for key, val in info.items():
+                store_val = val
+                store_type = None
+
+                # deal with basic types
+                if type(val) in (str, unicode):
+                    store_val = val
+                    store_type = 'string'
+                elif type(val) == int:
+                    store_val = str(val)
+                    store_type = 'int'
+                elif type(val) == float:
+                    store_val = str(val)
+                    store_type = 'float'
+                elif type(val) == bool:
+                    store_val = str(int(val))
+                    store_type = 'bool'
+
+                if store_type != None:
+                    val_node = doc.createElement(key)
+                    val_node.setAttribute('type', store_type)
+                    node.appendChild(val_node)
+                    # attach the value
+                    val_text = doc.createTextNode(store_val)
+                    val_node.appendChild(val_text)
+                    continue
+
+                # deal with dicts and lists
+                if type(val) == dict:
+                    for val_uuid in val.keys():
+                        val_node = doc.createElement(key)
+                        val_node.setAttribute('uuid', val_uuid)
+                        node.appendChild(val_node)
+                elif type(val) in (list, tuple):
+                    for val_uuid in val:
+                        val_node = doc.createElement(key)
+                        val_node.setAttribute('uuid', val_uuid)
+                        node.appendChild(val_node)
+
+        open(xml_path, 'w').write(doc.toprettyxml())
+        
+    

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.