fix indent error
[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 or slivers at their sites, or of which they
30     are members. 
31     (*) techs may only set tags of slivers at their sites.
32
33     Returns the new slice_tag_id (> 0) if successful, faults
34     otherwise.
35     """
36
37     roles = ['admin', 'pi', 'user', 'node']
38
39     accepts = [
40         Auth(),
41         Mixed(Slice.fields['slice_id'],
42               Slice.fields['name']),
43         Mixed(SliceTag.fields['tag_type_id'],
44               SliceTag.fields['tagname']),
45         Mixed(SliceTag.fields['value'],
46               InitScript.fields['name']),
47         Mixed(Node.fields['node_id'],
48               Node.fields['hostname'],
49               None),
50         Mixed(NodeGroup.fields['nodegroup_id'],
51               NodeGroup.fields['groupname'])
52         ]
53
54     returns = Parameter(int, 'New slice_tag_id (> 0) if successful')
55
56     def call(self, auth, slice_id_or_name, tag_type_id_or_name, value, node_id_or_hostname = None, nodegroup_id_or_name = None):
57         slices = Slices(self.api, [slice_id_or_name])
58         if not slices:
59             raise PLCInvalidArgument, "No such slice %r"%slice_id_or_name
60         slice = slices[0]
61
62         tag_types = TagTypes(self.api, [tag_type_id_or_name])
63         if not tag_types:
64             raise PLCInvalidArgument, "No such tag type %r"%tag_type_id_or_name
65         tag_type = tag_types[0]
66
67         # check authorizations
68         if 'admin' not in self.caller['roles']:
69             # this knows how to deal with self.caller being a node
70             if not AuthorizeHelpers.caller_may_access_tag_type (self.api, self.caller, tag_type):
71                 raise PLCPermissionDenied, "%s, forbidden tag %s"%(self.name,tag_type['tagname'])
72             # node callers: check the node is in the slice
73             if isinstance(self.caller, Node): 
74                 granted=AuthorizeHelpers.node_in_slice (self.api, self.caller, slice)
75             else:
76                 if nodegroup_id_or_name:
77                     raise PLCPermissionDenied, "%s, cannot set slice tag on nodegroup"%self.name
78                 # try all roles to find a match
79                 granted=False
80                 for role in self.caller['roles']:
81                     if role=='pi':
82                         if AuthorizeHelpers.person_in_slice(self.api, self.caller, slice): 
83                             granted=True ; break
84                         if node_id_or_hostname is not None and \
85                                 AuthorizeHelpers.node_id_or_hostname_in_slice(self.api, node_id_or_hostname_in_slice, slice):
86                             granted=True ; break
87                     elif role=='user':
88                         if AuthorizeHelpers.person_in_slice(self.api, self.caller, slice):
89                             granted=True ; break
90                     elif role=='tech':
91                         if node_id_or_hostname is not None and \
92                                 AuthorizeHelpers.node_id_or_hostname_in_slice(self.api, node_id_or_hostname_in_slice, slice):
93                             granted=True ; break
94             if not granted:
95                 raise PLCPermissionDenied, "%s, forbidden tag %s"%(self.name,tag_type['tagname'])
96
97         # if initscript is specified, validate value
98         if tag_type['tagname'] in ['initscript']:
99             initscripts = InitScripts(self.api, {'enabled': True, 'name': value})
100             if not initscripts:
101                 raise PLCInvalidArgument, "No such plc initscript %r"%value
102
103         slice_tag = SliceTag(self.api)
104         slice_tag['slice_id'] = slice['slice_id']
105         slice_tag['tag_type_id'] = tag_type['tag_type_id']
106         slice_tag['value'] = unicode(value)
107
108         # Sliver attribute if node is specified
109         if node_id_or_hostname is not None or isinstance(self.caller, Node):
110             node_id = None
111             if isinstance(self.caller, Node):
112                 node = self.caller
113                 node_id = node['node_id']
114
115             if node_id_or_hostname is not None:
116                 nodes = Nodes(self.api, [node_id_or_hostname])
117                 if not nodes:
118                     raise PLCInvalidArgument, "No such node"
119                 node = nodes[0]
120                 if node_id <> None and node_id <> node['node_id']:
121                     raise PLCPermissionDenied, "Not allowed to set another node's sliver attribute"
122                 else:
123                     node_id = node['node_id']
124
125             system_slice_tags = SliceTags(self.api, {'tagname': 'system', 'value': '1'}).dict('slice_id')
126             system_slice_ids = system_slice_tags.keys()
127             if slice['slice_id'] not in system_slice_ids and node_id not in slice['node_ids']:
128                 raise PLCInvalidArgument, "AddSliceTag: slice %s not on specified node %s nor is it a system slice (%r)"%\
129                     (slice['name'],node['hostname'],system_slice_ids)
130             slice_tag['node_id'] = node['node_id']
131
132         # Sliver attribute shared accross nodes if nodegroup is sepcified
133         if nodegroup_id_or_name is not None:
134             if isinstance(self.caller, Node):
135                 raise PLCPermissionDenied, "Not allowed to set nodegroup slice attributes"
136
137             nodegroups = NodeGroups(self.api, [nodegroup_id_or_name])
138             if not nodegroups:
139                 raise PLCInvalidArgument, "No such nodegroup %r"%nodegroup_id_or_name
140             nodegroup = nodegroups[0]
141
142             slice_tag['nodegroup_id'] = nodegroup['nodegroup_id']
143
144         # Check if slice attribute already exists
145         slice_tags_check = SliceTags(self.api, {'slice_id': slice['slice_id'],
146                                                 'tagname': tag_type['tagname'],
147                                                 'value': value})
148         for slice_tag_check in slice_tags_check:
149             # do not compare between slice tag and sliver tag
150             if 'node_id' not in slice_tag and slice_tag_check['node_id'] is not None:
151                 continue
152             # do not compare between sliver tag and slice tag
153             if 'node_id' in slice_tag and slice_tag['node_id'] is not None and slice_tag_check['node_id'] is None:
154                 continue
155             if 'node_id' in slice_tag and slice_tag['node_id'] == slice_tag_check['node_id']:
156                 raise PLCInvalidArgument, "Sliver attribute already exists"
157             if 'nodegroup_id' in slice_tag and slice_tag['nodegroup_id'] == slice_tag_check['nodegroup_id']:
158                 raise PLCInvalidArgument, "Slice attribute already exists for this nodegroup"
159             if node_id_or_hostname is None and nodegroup_id_or_name is None:
160                 raise PLCInvalidArgument, "Slice attribute already exists"
161
162         slice_tag.sync()
163         self.event_objects = {'SliceTag': [slice_tag['slice_tag_id']]}
164
165         return slice_tag['slice_tag_id']