add/update/delete slice tags should be fine
[plcapi.git] / PLC / Methods / AddSliceTag.py
1 #
2 # Thierry Parmentelat - INRIA
3 #
4 from PLC.Faults import *
5 from PLC.Method import Method
6 from PLC.Parameter import Parameter, Mixed
7 from PLC.Auth import Auth
8
9 from PLC.TagTypes import TagType, TagTypes
10 from PLC.Slices import Slice, Slices
11 from PLC.Nodes import Node, Nodes
12 from PLC.SliceTags import SliceTag, SliceTags
13 from PLC.NodeGroups import NodeGroup, NodeGroups
14 from PLC.InitScripts import InitScript, InitScripts
15
16 from PLC.AuthorizeHelpers import AuthorizeHelpers
17
18 class AddSliceTag(Method):
19     """
20     Sets the specified tag of the slice to the specified value.
21     If nodegroup is specified, this applies to all slivers of that group.
22     If node is specified, this only applies to a sliver.
23
24     Admins have full access, including on nodegroups.
25
26     Non-admins need to have at least one of the roles 
27     attached to the tagtype. In addition:
28     (*) Users may only set tags of slices or slivers of which they are members. 
29     (*) PIs may only set tags of slices in their site
30     (*) techs cannot use this method
31
32     Returns the new slice_tag_id (> 0) if successful, faults
33     otherwise.
34     """
35
36     roles = ['admin', 'pi', 'user', 'node']
37
38     accepts = [
39         Auth(),
40         Mixed(Slice.fields['slice_id'],
41               Slice.fields['name']),
42         Mixed(SliceTag.fields['tag_type_id'],
43               SliceTag.fields['tagname']),
44         Mixed(SliceTag.fields['value'],
45               InitScript.fields['name']),
46         Mixed(Node.fields['node_id'],
47               Node.fields['hostname'],
48               None),
49         Mixed(NodeGroup.fields['nodegroup_id'],
50               NodeGroup.fields['groupname'])
51         ]
52
53     returns = Parameter(int, 'New slice_tag_id (> 0) if successful')
54
55     def call(self, auth, slice_id_or_name, tag_type_id_or_name, value, node_id_or_hostname = None, nodegroup_id_or_name = None):
56         slices = Slices(self.api, [slice_id_or_name])
57         if not slices:
58             raise PLCInvalidArgument, "No such slice %r"%slice_id_or_name
59         slice = slices[0]
60
61         tag_types = TagTypes(self.api, [tag_type_id_or_name])
62         if not tag_types:
63             raise PLCInvalidArgument, "No such tag type %r"%tag_type_id_or_name
64         tag_type = tag_types[0]
65
66         # check authorizations
67         granted=False
68         if 'admin' in self.caller['roles']:
69             granted=True
70         # does caller have right role(s) ? this knows how to deal with self.caller being a node
71         elif not AuthorizeHelpers.caller_may_access_tag_type (self.api, self.caller, tag_type):
72             granted=False
73         # node callers: check the node is in the slice
74         elif isinstance(self.caller, Node): 
75             # nodes can only set their own sliver tags
76             if node_id_or_hostname is None: 
77                 granted=False
78             elif not AuthorizeHelpers.node_match_id (self.api, self.caller, node_id_or_hostname):
79                 granted=False
80             elif not AuthorizeHelpers.node_in_slice (self.api, self.caller, slice):
81                 granted=False
82         # caller is a non-admin person
83         else:
84             # only admins can handle slice tags on a nodegroup
85             if nodegroup_id_or_name:
86                 raise PLCPermissionDenied, "%s, cannot set slice tag %s on nodegroup - restricted to admins"%\
87                     (self.name,tag_type['tagname'])
88             # if a node is specified it is expected to be in the slice
89             if node_id_or_hostname:
90                 if not AuthorizeHelpers.node_id_in_slice (self.api, node_id_or_hostname, slice):
91                     raise PLCPermissionDenied, "%s, node must be in slice when setting sliver tag"
92             # try all roles to find a match - tech are ignored b/c not in AddSliceTag.roles anyways
93             for role in AuthorizeHelpers.person_tag_type_common_roles(self.api,self.caller,tag_type):
94                 # regular users need to be in the slice
95                 if role=='user':
96                     if AuthorizeHelpers.person_in_slice(self.api, self.caller, slice):
97                         granted=True ; break
98                 # for convenience, pi's can tweak all the slices in their site
99                 elif role=='pi':
100                     if AuthorizeHelpers.slice_belongs_to_pi (self.api, slice, self.caller):
101                         granted=True ; break
102         if not granted:
103             raise PLCPermissionDenied, "%s, forbidden tag %s"%(self.name,tag_type['tagname'])
104
105         # if initscript is specified, validate value
106         if tag_type['tagname'] in ['initscript']:
107             initscripts = InitScripts(self.api, {'enabled': True, 'name': value})
108             if not initscripts:
109                 raise PLCInvalidArgument, "No such plc initscript %r"%value
110
111         slice_tag = SliceTag(self.api)
112         slice_tag['slice_id'] = slice['slice_id']
113         slice_tag['tag_type_id'] = tag_type['tag_type_id']
114         slice_tag['value'] = unicode(value)
115
116         # Sliver attribute if node is specified
117         if node_id_or_hostname is not None or isinstance(self.caller, Node):
118             node_id = None
119             if isinstance(self.caller, Node):
120                 node = self.caller
121                 node_id = node['node_id']
122
123             if node_id_or_hostname is not None:
124                 nodes = Nodes(self.api, [node_id_or_hostname])
125                 if not nodes:
126                     raise PLCInvalidArgument, "No such node"
127                 node = nodes[0]
128                 if node_id <> None and node_id <> node['node_id']:
129                     raise PLCPermissionDenied, "Not allowed to set another node's sliver attribute"
130                 else:
131                     node_id = node['node_id']
132
133             system_slice_tags = SliceTags(self.api, {'tagname': 'system', 'value': '1'}).dict('slice_id')
134             system_slice_ids = system_slice_tags.keys()
135             if slice['slice_id'] not in system_slice_ids and node_id not in slice['node_ids']:
136                 raise PLCInvalidArgument, "AddSliceTag: slice %s not on specified node %s nor is it a system slice (%r)"%\
137                     (slice['name'],node['hostname'],system_slice_ids)
138             slice_tag['node_id'] = node['node_id']
139
140         # Sliver attribute shared accross nodes if nodegroup is sepcified
141         if nodegroup_id_or_name is not None:
142             if isinstance(self.caller, Node):
143                 raise PLCPermissionDenied, "Not allowed to set nodegroup slice attributes"
144
145             nodegroups = NodeGroups(self.api, [nodegroup_id_or_name])
146             if not nodegroups:
147                 raise PLCInvalidArgument, "No such nodegroup %r"%nodegroup_id_or_name
148             nodegroup = nodegroups[0]
149
150             slice_tag['nodegroup_id'] = nodegroup['nodegroup_id']
151
152         # Check if slice attribute already exists
153         slice_tags_check = SliceTags(self.api, {'slice_id': slice['slice_id'],
154                                                 'tagname': tag_type['tagname'],
155                                                 'value': value})
156         for slice_tag_check in slice_tags_check:
157             # do not compare between slice tag and sliver tag
158             if 'node_id' not in slice_tag and slice_tag_check['node_id'] is not None:
159                 continue
160             # do not compare between sliver tag and slice tag
161             if 'node_id' in slice_tag and slice_tag['node_id'] is not None and slice_tag_check['node_id'] is None:
162                 continue
163             if 'node_id' in slice_tag and slice_tag['node_id'] == slice_tag_check['node_id']:
164                 raise PLCInvalidArgument, "Sliver attribute already exists"
165             if 'nodegroup_id' in slice_tag and slice_tag['nodegroup_id'] == slice_tag_check['nodegroup_id']:
166                 raise PLCInvalidArgument, "Slice attribute already exists for this nodegroup"
167             if node_id_or_hostname is None and nodegroup_id_or_name is None:
168                 raise PLCInvalidArgument, "Slice attribute already exists"
169
170         slice_tag.sync()
171         self.event_objects = {'SliceTag': [slice_tag['slice_tag_id']]}
172
173         return slice_tag['slice_tag_id']