First draft for leases
[plcapi.git] / PLC / Slices.py
index 1a1786c..81da51d 100644 (file)
@@ -1,3 +1,5 @@
+# $Id$
+# $URL$
 from types import StringTypes
 import time
 import re
 from types import StringTypes
 import time
 import re
@@ -10,7 +12,8 @@ from PLC.Table import Row, Table
 from PLC.SliceInstantiations import SliceInstantiation, SliceInstantiations
 from PLC.Nodes import Node
 from PLC.Persons import Person, Persons
 from PLC.SliceInstantiations import SliceInstantiation, SliceInstantiations
 from PLC.Nodes import Node
 from PLC.Persons import Person, Persons
-from PLC.SliceAttributes import SliceAttribute
+from PLC.SliceTags import SliceTag
+from PLC.Timestamp import Timestamp
 
 class Slice(Row):
     """
 
 class Slice(Row):
     """
@@ -22,7 +25,7 @@ class Slice(Row):
 
     table_name = 'slices'
     primary_key = 'slice_id'
 
     table_name = 'slices'
     primary_key = 'slice_id'
-    join_tables = ['slice_node', 'slice_person', 'slice_attribute', 'peer_slice', 'node_slice_whitelist']
+    join_tables = ['slice_node', 'slice_person', 'slice_tag', 'peer_slice', 'node_slice_whitelist', 'leases', ]
     fields = {
         'slice_id': Parameter(int, "Slice identifier"),
         'site_id': Parameter(int, "Identifier of the site to which this slice belongs"),
     fields = {
         'slice_id': Parameter(int, "Slice identifier"),
         'site_id': Parameter(int, "Identifier of the site to which this slice belongs"),
@@ -36,7 +39,7 @@ class Slice(Row):
         'expires': Parameter(int, "Date and time when slice expires, in seconds since UNIX epoch"),
         '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),
         'expires': Parameter(int, "Date and time when slice expires, in seconds since UNIX epoch"),
         '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),
-        'slice_attribute_ids': Parameter([int], "List of slice attributes", ro = True),
+        'slice_tag_ids': Parameter([int], "List of slice attributes", ro = True),
         'peer_id': Parameter(int, "Peer to which this slice belongs", nullok = True),
         'peer_slice_id': Parameter(int, "Foreign slice identifier at peer", nullok = True),
         }
         'peer_id': Parameter(int, "Peer to which this slice belongs", nullok = True),
         'peer_slice_id': Parameter(int, "Foreign slice identifier at peer", nullok = True),
         }
@@ -46,18 +49,9 @@ class Slice(Row):
        'nodes': [Mixed(Parameter(int, "Node identifier"),
                        Parameter(str, "Fully qualified hostname"))]
        }
        'nodes': [Mixed(Parameter(int, "Node identifier"),
                        Parameter(str, "Fully qualified hostname"))]
        }
-    # for Cache
-    class_key = 'name'
-    foreign_fields = ['instantiation', 'url', 'description', 'max_nodes', 'expires']
-    foreign_xrefs = [
-        {'field': 'node_ids' ,         'class': 'Node',   'table': 'slice_node' },
-       {'field': 'person_ids',        'class': 'Person', 'table': 'slice_person'},
-       {'field': 'creator_person_id', 'class': 'Person', 'table': 'unused-on-direct-refs'},
-        {'field': 'site_id',           'class': 'Site',   'table': 'unused-on-direct-refs'},
-    ]
-    # forget about this one, it is read-only anyway
-    # handling it causes Cache to re-sync all over again 
-    # 'created'
+
+    view_tags_name="view_slice_tags"
+    tags = {}
 
     def validate_name(self, name):
         # N.B.: Responsibility of the caller to ensure that login_base
 
     def validate_name(self, name):
         # N.B.: Responsibility of the caller to ensure that login_base
@@ -93,7 +87,7 @@ class Slice(Row):
         # N.B.: Responsibility of the caller to ensure that expires is
         # not too far into the future.
         check_future = not ('is_deleted' in self and self['is_deleted'])
         # N.B.: Responsibility of the caller to ensure that expires is
         # not too far into the future.
         check_future = not ('is_deleted' in self and self['is_deleted'])
-        return Row.validate_timestamp(self, expires, check_future = check_future)
+        return Timestamp.sql_validate( expires, check_future = check_future)
 
     add_person = Row.add_object(Person, 'slice_person')
     remove_person = Row.remove_object(Person, 'slice_person')
 
     add_person = Row.add_object(Person, 'slice_person')
     remove_person = Row.remove_object(Person, 'slice_person')
@@ -163,14 +157,14 @@ class Slice(Row):
                AddSliceToNodes.__call__(AddSliceToNodes(self.api), auth, self['slice_id'], list(new_nodes))
            if stale_nodes:
                DeleteSliceFromNodes.__call__(DeleteSliceFromNodes(self.api), auth, self['slice_id'], list(stale_nodes))                        
                AddSliceToNodes.__call__(AddSliceToNodes(self.api), auth, self['slice_id'], list(new_nodes))
            if stale_nodes:
                DeleteSliceFromNodes.__call__(DeleteSliceFromNodes(self.api), auth, self['slice_id'], list(stale_nodes))                        
-    def associate_slice_attributes(self, auth, fields, value):
+    def associate_slice_tags(self, auth, fields, value):
        """
        """
-       Deletes slice_attribute_ids not found in value list (using DeleteSliceAttribute). 
-       Adds slice_attributes if slice_fields w/o slice_id is found (using AddSliceAttribute).
-       Updates slice_attribute if slice_fields w/ slice_id is found (using UpdateSlceiAttribute).  
+       Deletes slice_tag_ids not found in value list (using DeleteSliceTag). 
+       Adds slice_tags if slice_fields w/o slice_id is found (using AddSliceTag).
+       Updates slice_tag if slice_fields w/ slice_id is found (using UpdateSlceiAttribute).  
        """
        
        """
        
-       assert 'slice_attribute_ids' in self
+       assert 'slice_tag_ids' in self
        assert isinstance(value, list)
 
        (attribute_ids, blank, attributes) = self.separate_types(value)
        assert isinstance(value, list)
 
        (attribute_ids, blank, attributes) = self.separate_types(value)
@@ -178,29 +172,29 @@ class Slice(Row):
        # There is no way to add attributes by id. They are
        # associated with a slice when they are created.
        # So we are only looking to delete here 
        # There is no way to add attributes by id. They are
        # associated with a slice when they are created.
        # So we are only looking to delete here 
-       if self['slice_attribute_ids'] != attribute_ids:
-           from PLC.Methods.DeleteSliceAttribute import DeleteSliceAttribute
-           stale_attributes = set(self['slice_attribute_ids']).difference(attribute_ids)
+       if self['slice_tag_ids'] != attribute_ids:
+           from PLC.Methods.DeleteSliceTag import DeleteSliceTag
+           stale_attributes = set(self['slice_tag_ids']).difference(attribute_ids)
        
            for stale_attribute in stale_attributes:
        
            for stale_attribute in stale_attributes:
-               DeleteSliceAttribute.__call__(DeleteSliceAttribute(self.api), auth, stale_attribute['slice_attribute_id'])              
+               DeleteSliceTag.__call__(DeleteSliceTag(self.api), auth, stale_attribute['slice_tag_id'])                
        
        # If dictionary exists, we are either adding new
         # attributes or updating existing ones.
         if attributes:
        
        # If dictionary exists, we are either adding new
         # attributes or updating existing ones.
         if attributes:
-            from PLC.Methods.AddSliceAttribute import AddSliceAttribute
-            from PLC.Methods.UpdateSliceAttribute import UpdateSliceAttribute
+            from PLC.Methods.AddSliceTag import AddSliceTag
+            from PLC.Methods.UpdateSliceTag import UpdateSliceTag
        
        
-           added_attributes = filter(lambda x: 'slice_attribute_id' not in x, attributes)
-           updated_attributes = filter(lambda x: 'slice_attribute_id' in x, attributes)
+           added_attributes = filter(lambda x: 'slice_tag_id' not in x, attributes)
+           updated_attributes = filter(lambda x: 'slice_tag_id' in x, attributes)
 
            for added_attribute in added_attributes:
 
            for added_attribute in added_attributes:
-               if 'attribute_type' in added_attribute:
-                   type = added_attribute['attribute_type']
-               elif 'attribute_type_id' in added_attribute:
-                   type = added_attribute['attribute_type_id']
+               if 'tag_type' in added_attribute:
+                   type = added_attribute['tag_type']
+               elif 'tag_type_id' in added_attribute:
+                   type = added_attribute['tag_type_id']
                else:
                else:
-                   raise PLCInvalidArgument, "Must specify attribute_type or attribute_type_id"
+                   raise PLCInvalidArgument, "Must specify tag_type or tag_type_id"
 
                if 'value' in added_attribute:
                    value = added_attribute['value']
 
                if 'value' in added_attribute:
                    value = added_attribute['value']
@@ -217,13 +211,13 @@ class Slice(Row):
                else:
                    nodegroup_id = None 
  
                else:
                    nodegroup_id = None 
  
-               AddSliceAttribute.__call__(AddSliceAttribute(self.api), auth, self['slice_id'], type, value, node_id, nodegroup_id)
+               AddSliceTag.__call__(AddSliceTag(self.api), auth, self['slice_id'], type, value, node_id, nodegroup_id)
            for updated_attribute in updated_attributes:
            for updated_attribute in updated_attributes:
-               attribute_id = updated_attribute.pop('slice_attribute_id')
-               if attribute_id not in self['slice_attribute_ids']:
+               attribute_id = updated_attribute.pop('slice_tag_id')
+               if attribute_id not in self['slice_tag_ids']:
                    raise PLCInvalidArgument, "Attribute doesnt belong to this slice" 
                else:
                    raise PLCInvalidArgument, "Attribute doesnt belong to this slice" 
                else:
-                   UpdateSliceAttribute.__call__(UpdateSliceAttribute(self.api), auth, attribute_id, updated_attribute)                 
+                   UpdateSliceTag.__call__(UpdateSliceTag(self.api), auth, attribute_id, updated_attribute)             
        
     def sync(self, commit = True):
         """
        
     def sync(self, commit = True):
         """
@@ -264,8 +258,15 @@ class Slices(Table):
     def __init__(self, api, slice_filter = None, columns = None, expires = int(time.time())):
         Table.__init__(self, api, Slice, columns)
 
     def __init__(self, api, slice_filter = None, columns = None, expires = int(time.time())):
         Table.__init__(self, api, Slice, columns)
 
-        sql = "SELECT %s FROM view_slices WHERE is_deleted IS False" % \
-              ", ".join(self.columns)
+        # the view that we're selecting upon: start with view_slices
+        view = "view_slices"
+        # as many left joins as requested tags
+        for tagname in self.tag_columns:
+            view= "%s left join %s using (%s)"%(view,Slice.tagvalue_view_name(tagname),
+                                                Slice.primary_key)
+            
+        sql = "SELECT %s FROM %s WHERE is_deleted IS False" % \
+              (", ".join(self.columns.keys()+self.tag_columns.keys()),view)
 
         if expires is not None:
             if expires >= 0:
 
         if expires is not None:
             if expires >= 0: