1 from types import StringTypes
6 from PLC.Faults import *
7 from PLC.Parameter import Parameter, Mixed
8 from PLC.Debug import profile
9 from PLC.Nodes import Node
10 from PLC.Persons import Person, Persons
11 from PLC.SlicePersons import SlicePerson, SlicePersons
12 from PLC.SliceNodes import SliceNode, SliceNodes
13 from PLC.SliceTags import SliceTag, SliceTags
14 from PLC.Timestamp import Timestamp
15 from PLC.Storage.AlchemyObject import AlchemyObj
17 class Slice(AlchemyObj):
19 Representation of a row in the slices table. To use, optionally
20 instantiate with a dict of values. Update as you would a
21 dict. Commit to the database with sync().To use, instantiate
22 with a dict of values.
28 'slice_id': Parameter(int, "Slice identifier", primary_key=True),
29 'site_id': Parameter(int, "Identifier of the site to which this slice belongs"),
30 'name': Parameter(str, "Slice name", max = 32),
31 'instantiation': Parameter(str, "Slice instantiation state", nullok=True),
32 'url': Parameter(str, "URL further describing this slice", max = 254, nullok = True),
33 'description': Parameter(str, "Slice description", max = 2048, nullok = True),
34 'max_nodes': Parameter(int, "Maximum number of nodes that can be assigned to this slice"),
35 'creator_person_id': Parameter(str, "Identifier of the account that created this slice"),
36 'created': Parameter(datetime, "Date and time when slice was created, in seconds since UNIX epoch", ro = True),
37 'expires': Parameter(datetime, "Date and time when slice expires, in seconds since UNIX epoch"),
38 'node_ids': Parameter([str], "List of nodes in this slice", joined = True),
39 'person_ids': Parameter([str], "List of accounts that can use this slice", joined = True),
40 'slice_tag_ids': Parameter([int], "List of slice attributes", joined = True),
41 'peer_id': Parameter(int, "Peer to which this slice belongs", nullok = True),
42 'peer_slice_id': Parameter(int, "Foreign slice identifier at peer", nullok = True),
46 def validate_name(self, name):
47 # N.B.: Responsibility of the caller to ensure that login_base
48 # portion of the slice name corresponds to a valid site, if
52 # 2. Begins with login_base (letters or numbers).
53 # 3. Then single underscore after login_base.
54 # 4. Then letters, numbers, or underscores.
55 good_name = r'^[a-z0-9]+_[a-zA-Z0-9_]+$'
57 not re.match(good_name, name):
58 raise PLCInvalidArgument, "Invalid slice name"
60 conflicts = Slices(self.api, [name])
61 for slice in conflicts:
62 if 'slice_id' not in self or self['slice_id'] != slice.slice_id:
63 raise PLCInvalidArgument, "Slice name already in use, %s"%name
67 def validate_expires(self, expires):
68 # N.B.: Responsibility of the caller to ensure that expires is
69 # not too far into the future.
70 check_future = not ('is_deleted' in self and self['is_deleted'])
71 return Timestamp.sql_validate( expires, check_future = check_future)
73 #add_person = Row.add_object(Person, 'slice_person')
74 #remove_person = Row.remove_object(Person, 'slice_person')
76 #add_node = Row.add_object(Node, 'slice_node')
77 #remove_node = Row.remove_object(Node, 'slice_node')
79 #add_to_node_whitelist = Row.add_object(Node, 'node_slice_whitelist')
80 #delete_from_node_whitelist = Row.remove_object(Node, 'node_slice_whitelist')
82 def sync(self, commit = True, validate=True):
84 Add or update a slice.
86 AlchemyObj.sync(self, commit, validate)
87 if 'slice_id' not in self:
88 # Before a new slice is added, delete expired slices
89 #expired = Slices(self.api, expires = -int(time.time()))
90 #for slice in expired:
91 # slice.delete(commit)
92 AlchemyObj.insert(self, dict(self))
94 AlchemyObj.update(self, {'slice_id': self['slice_id']}, dict(self))
96 def delete(self, commit = True):
98 Delete existing slice.
100 assert 'slice_id' in self
101 # delete relationships
102 SlicePerson().delete(self, filter={'slice_id': self['slice_id']})
103 SliceNode().delete(self, filter={'slice_id': self['slice_id']})
104 SliceTag().delete(self, filter={'slice_id': self['slice_id']})
105 AlchemyObj.delete(self, dict(self))
110 Representation of row(s) from the slices table in the
114 def __init__(self, api, slice_filter = None, columns = None, expires = int(time.time())):
116 # the view that we're selecting upon: start with view_slices
118 slices = Slice().select()
119 elif isinstance (slice_filter, StringTypes):
120 slices = Slice().select(filter={'name': slice_filter})
121 elif isinstance(slice_filter, dict):
122 slices = Slice().select(filter=slice_filter)
123 elif isinstance(slice_filter, (list, tuple, set)):
124 slices = Slice().select()
125 slices = [slice for slice in slices if slice.id in slice_filter]
127 raise PLCInvalidArgument, "Wrong slice filter %r"%slice_filter
130 slice = Slice(api, object=slice)
131 if not columns or 'person_ids' in columns:
132 slice_persons = SlicePerson().select(filter={'slice_id': slice.id})
133 slice['person_ids'] = [rec.person_id for rec in slice_persons]
135 if not columns or 'node_ids' in columns:
136 slice_nodes = SliceNode().select(filter={'slice_id': slice.id})
137 slice['node_ids'] = [rec.node_id for rec in slice_nodes]
139 if not columns or 'slice_tag_ids' in columns:
140 slice_tags = SliceTag().select(filter={'slice_id': slice.id})
141 slice['slice_tag_ids'] = [rec.slice_tag_id for rec in slice_tags]