Fix a node name vs. UUID bug in instance import
[ganeti-local] / lib / cmdlib / tags.py
1 #
2 #
3
4 # Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
20
21
22 """Logical units dealing with tags."""
23
24 import re
25
26 from ganeti import constants
27 from ganeti import errors
28 from ganeti import locking
29 from ganeti import objects
30 from ganeti import utils
31 from ganeti.cmdlib.base import NoHooksLU
32 from ganeti.cmdlib.common import ExpandNodeUuidAndName, \
33   ExpandInstanceUuidAndName, ShareAll
34
35
36 class TagsLU(NoHooksLU): # pylint: disable=W0223
37   """Generic tags LU.
38
39   This is an abstract class which is the parent of all the other tags LUs.
40
41   """
42   def ExpandNames(self):
43     self.group_uuid = None
44     self.needed_locks = {}
45
46     if self.op.kind == constants.TAG_NODE:
47       (self.node_uuid, _) = \
48         ExpandNodeUuidAndName(self.cfg, None, self.op.name)
49       lock_level = locking.LEVEL_NODE
50       lock_name = self.node_uuid
51     elif self.op.kind == constants.TAG_INSTANCE:
52       (self.inst_uuid, inst_name) = \
53         ExpandInstanceUuidAndName(self.cfg, None, self.op.name)
54       lock_level = locking.LEVEL_INSTANCE
55       lock_name = inst_name
56     elif self.op.kind == constants.TAG_NODEGROUP:
57       self.group_uuid = self.cfg.LookupNodeGroup(self.op.name)
58       lock_level = locking.LEVEL_NODEGROUP
59       lock_name = self.group_uuid
60     elif self.op.kind == constants.TAG_NETWORK:
61       self.network_uuid = self.cfg.LookupNetwork(self.op.name)
62       lock_level = locking.LEVEL_NETWORK
63       lock_name = self.network_uuid
64     else:
65       lock_level = None
66       lock_name = None
67
68     if lock_level and getattr(self.op, "use_locking", True):
69       self.needed_locks[lock_level] = lock_name
70
71     # FIXME: Acquire BGL for cluster tag operations (as of this writing it's
72     # not possible to acquire the BGL based on opcode parameters)
73
74   def CheckPrereq(self):
75     """Check prerequisites.
76
77     """
78     if self.op.kind == constants.TAG_CLUSTER:
79       self.target = self.cfg.GetClusterInfo()
80     elif self.op.kind == constants.TAG_NODE:
81       self.target = self.cfg.GetNodeInfo(self.node_uuid)
82     elif self.op.kind == constants.TAG_INSTANCE:
83       self.target = self.cfg.GetInstanceInfo(self.inst_uuid)
84     elif self.op.kind == constants.TAG_NODEGROUP:
85       self.target = self.cfg.GetNodeGroup(self.group_uuid)
86     elif self.op.kind == constants.TAG_NETWORK:
87       self.target = self.cfg.GetNetwork(self.network_uuid)
88     else:
89       raise errors.OpPrereqError("Wrong tag type requested (%s)" %
90                                  str(self.op.kind), errors.ECODE_INVAL)
91
92
93 class LUTagsGet(TagsLU):
94   """Returns the tags of a given object.
95
96   """
97   REQ_BGL = False
98
99   def ExpandNames(self):
100     TagsLU.ExpandNames(self)
101
102     # Share locks as this is only a read operation
103     self.share_locks = ShareAll()
104
105   def Exec(self, feedback_fn):
106     """Returns the tag list.
107
108     """
109     return list(self.target.GetTags())
110
111
112 class LUTagsSearch(NoHooksLU):
113   """Searches the tags for a given pattern.
114
115   """
116   REQ_BGL = False
117
118   def ExpandNames(self):
119     self.needed_locks = {}
120
121   def CheckPrereq(self):
122     """Check prerequisites.
123
124     This checks the pattern passed for validity by compiling it.
125
126     """
127     try:
128       self.re = re.compile(self.op.pattern)
129     except re.error, err:
130       raise errors.OpPrereqError("Invalid search pattern '%s': %s" %
131                                  (self.op.pattern, err), errors.ECODE_INVAL)
132
133   def Exec(self, feedback_fn):
134     """Returns the tag list.
135
136     """
137     tgts = [("/cluster", self.cfg.GetClusterInfo())]
138     ilist = self.cfg.GetAllInstancesInfo().values()
139     tgts.extend([("/instances/%s" % i.name, i) for i in ilist])
140     nlist = self.cfg.GetAllNodesInfo().values()
141     tgts.extend([("/nodes/%s" % n.name, n) for n in nlist])
142     tgts.extend(("/nodegroup/%s" % n.name, n)
143                 for n in self.cfg.GetAllNodeGroupsInfo().values())
144     results = []
145     for path, target in tgts:
146       for tag in target.GetTags():
147         if self.re.search(tag):
148           results.append((path, tag))
149     return results
150
151
152 class LUTagsSet(TagsLU):
153   """Sets a tag on a given object.
154
155   """
156   REQ_BGL = False
157
158   def CheckPrereq(self):
159     """Check prerequisites.
160
161     This checks the type and length of the tag name and value.
162
163     """
164     TagsLU.CheckPrereq(self)
165     for tag in self.op.tags:
166       objects.TaggableObject.ValidateTag(tag)
167
168   def Exec(self, feedback_fn):
169     """Sets the tag.
170
171     """
172     try:
173       for tag in self.op.tags:
174         self.target.AddTag(tag)
175     except errors.TagError, err:
176       raise errors.OpExecError("Error while setting tag: %s" % str(err))
177     self.cfg.Update(self.target, feedback_fn)
178
179
180 class LUTagsDel(TagsLU):
181   """Delete a list of tags from a given object.
182
183   """
184   REQ_BGL = False
185
186   def CheckPrereq(self):
187     """Check prerequisites.
188
189     This checks that we have the given tag.
190
191     """
192     TagsLU.CheckPrereq(self)
193     for tag in self.op.tags:
194       objects.TaggableObject.ValidateTag(tag)
195     del_tags = frozenset(self.op.tags)
196     cur_tags = self.target.GetTags()
197
198     diff_tags = del_tags - cur_tags
199     if diff_tags:
200       diff_names = ("'%s'" % i for i in sorted(diff_tags))
201       raise errors.OpPrereqError("Tag(s) %s not found" %
202                                  (utils.CommaJoin(diff_names), ),
203                                  errors.ECODE_NOENT)
204
205   def Exec(self, feedback_fn):
206     """Remove the tag from the object.
207
208     """
209     for tag in self.op.tags:
210       self.target.RemoveTag(tag)
211     self.cfg.Update(self.target, feedback_fn)