make read-only a Parameter attribute
authorMark Huang <mlhuang@cs.princeton.edu>
Mon, 2 Oct 2006 18:32:31 +0000 (18:32 +0000)
committerMark Huang <mlhuang@cs.princeton.edu>
Mon, 2 Oct 2006 18:32:31 +0000 (18:32 +0000)
PLC/Nodes.py
PLC/Parameter.py
PLC/Persons.py
PLC/Sites.py
PLC/Slices.py

index 35b1ab4..7930ab1 100644 (file)
@@ -4,7 +4,7 @@
 # Mark Huang <mlhuang@cs.princeton.edu>
 # Copyright (C) 2006 The Trustees of Princeton University
 #
-# $Id: Nodes.py,v 1.6 2006/10/02 15:21:03 mlhuang Exp $
+# $Id: Nodes.py,v 1.7 2006/10/02 16:04:42 mlhuang Exp $
 #
 
 from types import StringTypes
@@ -33,16 +33,16 @@ class Node(Row):
         'boot_nonce': Parameter(str, "(Admin only) Random value generated by the node at last boot", max = 128),
         'version': Parameter(str, "Apparent Boot CD version", max = 64),
         'ssh_rsa_key': Parameter(str, "Last known SSH host key", max = 1024),
-        'date_created': Parameter(str, "Date and time when node entry was created"),
-        'last_updated': Parameter(str, "Date and time when node entry was created"),
+        'date_created': Parameter(str, "Date and time when node entry was created", ro = True),
+        'last_updated': Parameter(str, "Date and time when node entry was created", ro = True),
         'key': Parameter(str, "(Admin only) Node key", max = 256),
         'session': Parameter(str, "(Admin only) Node session value", max = 256),
-        'nodenetwork_ids': Parameter([int], "List of network interfaces that this node has"),
-        'nodegroup_ids': Parameter([int], "List of node groups that this node is in"),
-        # 'conf_file_ids': Parameter([int], "List of configuration files specific to this node"),
-        # 'root_person_ids': Parameter([int], "(Admin only) List of people who have root access to this node"),
-        'slice_ids': Parameter([int], "List of slices on this node"),
-        # 'pcu_ids': Parameter([int], "List of PCUs that control this node"),
+        'nodenetwork_ids': Parameter([int], "List of network interfaces that this node has", ro = True),
+        'nodegroup_ids': Parameter([int], "List of node groups that this node is in", ro = True),
+        # 'conf_file_ids': Parameter([int], "List of configuration files specific to this node", ro = True),
+        # 'root_person_ids': Parameter([int], "(Admin only) List of people who have root access to this node", ro = True),
+        'slice_ids': Parameter([int], "List of slices on this node", ro = True),
+        # 'pcu_ids': Parameter([int], "List of PCUs that control this node", ro = True),
         }
 
     def __init__(self, api, fields):
@@ -99,11 +99,10 @@ class Node(Row):
 
         # Filter out fields that cannot be set or updated directly
         nodes_fields = self.api.db.fields('nodes')
-        fields = dict(filter(lambda (key, value): key in nodes_fields,
+        fields = dict(filter(lambda (key, value): \
+                             key in nodes_fields and \
+                             (key not in self.fields or not self.fields[key].ro),
                              self.items()))
-        for ro_field in 'date_created', 'last_updated':
-            if ro_field in fields:
-                del fields[ro_field]
 
         # Parameterize for safety
         keys = fields.keys()
index 5dab363..5f573f8 100644 (file)
@@ -4,7 +4,7 @@
 # Mark Huang <mlhuang@cs.princeton.edu>
 # Copyright (C) 2006 The Trustees of Princeton University
 #
-# $Id: Parameter.py,v 1.1 2006/09/06 15:36:07 mlhuang Exp $
+# $Id: Parameter.py,v 1.2 2006/09/08 19:45:04 mlhuang Exp $
 #
 
 class Parameter:
@@ -14,9 +14,29 @@ class Parameter:
     sub-parameters (i.e., dict fields).
     """
 
-    def __init__(self, type, doc = "", min = None, max = None, optional = True, default = None):
-        (self.type, self.doc, self.min, self.max, self.optional, self.default) = \
-                    (type, doc, min, max, optional, default)
+    def __init__(self, type, doc = "",
+                 min = None, max = None,
+                 optional = True, default = None,
+                 ro = False):
+        # Basic type of the parameter. May be a builtin type or Mixed.
+        self.type = type
+
+        # Documentation string for the parameter
+        self.doc = doc
+
+        # Basic value checking. For numeric types, the minimum and
+        # maximum possible values, inclusive. For string types, the
+        # minimum and maximum possible UTF-8 encoded byte lengths.
+        self.min = min
+        self.max = max
+
+        # Whether the sub-parameter is optional or not. If optional,
+        # the default for the sub-parameter if not specified.
+        self.optional = optional
+        self.default = default
+
+        # Whether the DB field is read-only.
+        self.ro = ro
 
     def __repr__(self):
         return repr(self.type)
index b549a94..ac97192 100644 (file)
@@ -4,7 +4,7 @@
 # Mark Huang <mlhuang@cs.princeton.edu>
 # Copyright (C) 2006 The Trustees of Princeton University
 #
-# $Id: Persons.py,v 1.5 2006/10/02 15:25:03 mlhuang Exp $
+# $Id: Persons.py,v 1.6 2006/10/02 16:04:22 mlhuang Exp $
 #
 
 from types import StringTypes
@@ -42,13 +42,13 @@ class Person(Row):
         'bio': Parameter(str, "Biography", max = 254),
         'enabled': Parameter(bool, "Has been enabled"),
         'password': Parameter(str, "Account password in crypt() form", max = 254),
-        'last_updated': Parameter(str, "Date and time of last update"),
-        'date_created': Parameter(str, "Date and time when account was created"),
-        'role_ids': Parameter([int], "List of role identifiers"),
-        'roles': Parameter([str], "List of roles"),
-        'site_ids': Parameter([int], "List of site identifiers"),
-        'key_ids': Parameter([int], "List of key identifiers"),
-        'slice_ids': Parameter([int], "List of slice identifiers"),
+        'last_updated': Parameter(str, "Date and time of last update", ro = True),
+        'date_created': Parameter(str, "Date and time when account was created", ro = True),
+        'role_ids': Parameter([int], "List of role identifiers", ro = True),
+        'roles': Parameter([str], "List of roles", ro = True),
+        'site_ids': Parameter([int], "List of site identifiers", ro = True),
+        'key_ids': Parameter([int], "List of key identifiers", ro = True),
+        'slice_ids': Parameter([int], "List of slice identifiers", ro = True),
         }
 
     def __init__(self, api, fields):
@@ -242,11 +242,10 @@ class Person(Row):
 
         # Filter out fields that cannot be set or updated directly
         persons_fields = self.api.db.fields('persons')
-        fields = dict(filter(lambda (key, value): key in persons_fields,
+        fields = dict(filter(lambda (key, value): \
+                             key in persons_fields and \
+                             (key not in self.fields or not self.fields[key].ro),
                              self.items()))
-        for ro_field in 'date_created', 'last_updated':
-            if ro_field in fields:
-                del fields[ro_field]
 
         # Parameterize for safety
         keys = fields.keys()
index d18dac3..2fbcd1b 100644 (file)
@@ -28,15 +28,15 @@ class Site(Row):
         'latitude': Parameter(float, "Decimal latitude of the site", min = -90.0, max = 90.0),
         'longitude': Parameter(float, "Decimal longitude of the site", min = -180.0, max = 180.0),
         'url': Parameter(str, "URL of a page that describes the site", max = 254),
-        'date_created': Parameter(int, "Date and time when site entry was created, in seconds since UNIX epoch"),
-        'last_updated': Parameter(int, "Date and time when site entry was last updated, in seconds since UNIX epoch"),
+        'date_created': Parameter(int, "Date and time when site entry was created, in seconds since UNIX epoch", ro = True),
+        'last_updated': Parameter(int, "Date and time when site entry was last updated, in seconds since UNIX epoch", ro = True),
         'max_slices': Parameter(int, "Maximum number of slices that the site is able to create"),
         'max_slivers': Parameter(int, "Maximum number of slivers that the site is able to create"),
-        'person_ids': Parameter([int], "List of account identifiers"),
-        'slice_ids': Parameter([int], "List of slice identifiers"),
-        'address_ids': Parameter([int], "List of address identifiers"),
-        # 'pcu_ids': Parameter([int], "List of PCU identifiers"),
-        'node_ids': Parameter([int], "List of site node identifiers"),
+        'person_ids': Parameter([int], "List of account identifiers", ro = True),
+        'slice_ids': Parameter([int], "List of slice identifiers", ro = True),
+        'address_ids': Parameter([int], "List of address identifiers", ro = True),
+        # 'pcu_ids': Parameter([int], "List of PCU identifiers", ro = True),
+        'node_ids': Parameter([int], "List of site node identifiers", ro = True),
         }
 
     def __init__(self, api, fields):
@@ -145,11 +145,10 @@ class Site(Row):
 
         # Filter out fields that cannot be set or updated directly
         sites_fields = self.api.db.fields('sites')
-        fields = dict(filter(lambda (key, value): key in sites_fields,
+        fields = dict(filter(lambda (key, value): \
+                             key in sites_fields and \
+                             (key not in self.fields or not self.fields[key].ro),
                              self.items()))
-        for ro_field in 'date_created', 'last_updated':
-            if ro_field in fields:
-                del fields[ro_field]
 
         # Parameterize for safety
         keys = fields.keys()
index 449fba1..1b6ee92 100644 (file)
@@ -25,11 +25,11 @@ class Slice(Row):
         'description': Parameter(str, "Slice description", max = 2048),
         'max_nodes': Parameter(int, "Maximum number of nodes that can be assigned to this slice"),
         'creator_person_id': Parameter(int, "Identifier of the account that created this slice"),
-        'created': Parameter(int, "Date and time when slice was created, in seconds since UNIX epoch"),
+        'created': Parameter(int, "Date and time when slice was created, in seconds since UNIX epoch", ro = True),
         'expires': Parameter(int, "Date and time when slice expires, in seconds since UNIX epoch"),
-        'node_ids': Parameter([int], "List of nodes in this slice"),
-        'person_ids': Parameter([int], "List of accounts that can use this slice"),
-        'attribute_ids': Parameter([int], "List of slice attributes"),
+        'node_ids': Parameter([int], "List of nodes in this slice", ro = True),
+        'person_ids': Parameter([int], "List of accounts that can use this slice", ro = True),
+        'attribute_ids': Parameter([int], "List of slice attributes", ro = True),
         }
 
     def __init__(self, api, fields):
@@ -69,6 +69,104 @@ class Slice(Row):
 
         return person_id
 
+    def add_person(self, person, commit = True):
+        """
+        Add person to existing slice.
+        """
+
+        assert 'slice_id' in self
+        assert isinstance(person, PLC.Persons.Person)
+        assert 'person_id' in person
+
+        slice_id = self['slice_id']
+        person_id = person['person_id']
+        self.api.db.do("INSERT INTO slice_person (person_id, slice_id)" \
+                       " VALUES(%(person_id)d, %(slice_id)d)",
+                       locals())
+
+        if commit:
+            self.api.db.commit()
+
+        if 'person_ids' in self and person_id not in self['person_ids']:
+            self['person_ids'].append(person_id)
+
+        if 'slice_ids' in person and slice_id not in person['slice_ids']:
+            person['slice_ids'].append(slice_id)
+
+    def remove_person(self, person, commit = True):
+        """
+        Remove person from existing slice.
+        """
+
+        assert 'slice_id' in self
+        assert isinstance(person, PLC.Persons.Person)
+        assert 'person_id' in person
+
+        slice_id = self['slice_id']
+        person_id = person['person_id']
+        self.api.db.do("DELETE FROM slice_person" \
+                       " WHERE person_id = %(person_id)d" \
+                       " AND slice_id = %(slice_id)d",
+                       locals())
+
+        if commit:
+            self.api.db.commit()
+
+        if 'person_ids' in self and person_id in self['person_ids']:
+            self['person_ids'].remove(person_id)
+
+        if 'slice_ids' in person and slice_id in person['slice_ids']:
+            person['slice_ids'].remove(slice_id)
+
+    def add_node(self, node, commit = True):
+        """
+        Add node to existing slice.
+        """
+
+        assert 'slice_id' in self
+        assert isinstance(node, PLC.Nodes.Node)
+        assert 'node_id' in node
+
+        slice_id = self['slice_id']
+        node_id = node['node_id']
+        self.api.db.do("INSERT INTO slice_node (node_id, slice_id)" \
+                       " VALUES(%(node_id)d, %(slice_id)d)",
+                       locals())
+
+        if commit:
+            self.api.db.commit()
+
+        if 'node_ids' in self and node_id not in self['node_ids']:
+            self['node_ids'].append(node_id)
+
+        if 'slice_ids' in node and slice_id not in node['slice_ids']:
+            node['slice_ids'].append(slice_id)
+
+    def remove_node(self, node, commit = True):
+        """
+        Remove node from existing slice.
+        """
+
+        assert 'slice_id' in self
+        assert isinstance(node, PLC.Nodes.Node)
+        assert 'node_id' in node
+
+        slice_id = self['slice_id']
+        node_id = node['node_id']
+        self.api.db.do("DELETE FROM slice_node" \
+                       " WHERE node_id = %(node_id)d" \
+                       " AND slice_id = %(slice_id)d",
+                       locals())
+
+        if commit:
+            self.api.db.commit()
+
+        if 'node_ids' in self and node_id in self['node_ids']:
+            self['node_ids'].remove(node_id)
+
+        if 'slice_ids' in node and slice_id in node['slice_ids']:
+            node['slice_ids'].remove(slice_id)
+
     def sync(self, commit = True):
         """
         Flush changes back to the database.
@@ -96,11 +194,10 @@ class Slice(Row):
 
         # Filter out fields that cannot be set or updated directly
         slices_fields = self.api.db.fields('slices')
-        fields = dict(filter(lambda (key, value): key in slices_fields,
+        fields = dict(filter(lambda (key, value): \
+                             key in slices_fields and \
+                             (key not in self.fields or not self.fields[key].ro),
                              self.items()))
-        for ro_field in 'created',:
-            if ro_field in fields:
-                del fields[ro_field]
 
         # Parameterize for safety
         keys = fields.keys()