4 # Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
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.
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.
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
22 """Logical units dealing with tags."""
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 _ExpandNodeName, _ExpandInstanceName, \
36 class TagsLU(NoHooksLU): # pylint: disable=W0223
39 This is an abstract class which is the parent of all the other tags LUs.
42 def ExpandNames(self):
43 self.group_uuid = None
44 self.needed_locks = {}
46 if self.op.kind == constants.TAG_NODE:
47 self.op.name = _ExpandNodeName(self.cfg, self.op.name)
48 lock_level = locking.LEVEL_NODE
49 lock_name = self.op.name
50 elif self.op.kind == constants.TAG_INSTANCE:
51 self.op.name = _ExpandInstanceName(self.cfg, self.op.name)
52 lock_level = locking.LEVEL_INSTANCE
53 lock_name = self.op.name
54 elif self.op.kind == constants.TAG_NODEGROUP:
55 self.group_uuid = self.cfg.LookupNodeGroup(self.op.name)
56 lock_level = locking.LEVEL_NODEGROUP
57 lock_name = self.group_uuid
58 elif self.op.kind == constants.TAG_NETWORK:
59 self.network_uuid = self.cfg.LookupNetwork(self.op.name)
60 lock_level = locking.LEVEL_NETWORK
61 lock_name = self.network_uuid
66 if lock_level and getattr(self.op, "use_locking", True):
67 self.needed_locks[lock_level] = lock_name
69 # FIXME: Acquire BGL for cluster tag operations (as of this writing it's
70 # not possible to acquire the BGL based on opcode parameters)
72 def CheckPrereq(self):
73 """Check prerequisites.
76 if self.op.kind == constants.TAG_CLUSTER:
77 self.target = self.cfg.GetClusterInfo()
78 elif self.op.kind == constants.TAG_NODE:
79 self.target = self.cfg.GetNodeInfo(self.op.name)
80 elif self.op.kind == constants.TAG_INSTANCE:
81 self.target = self.cfg.GetInstanceInfo(self.op.name)
82 elif self.op.kind == constants.TAG_NODEGROUP:
83 self.target = self.cfg.GetNodeGroup(self.group_uuid)
84 elif self.op.kind == constants.TAG_NETWORK:
85 self.target = self.cfg.GetNetwork(self.network_uuid)
87 raise errors.OpPrereqError("Wrong tag type requested (%s)" %
88 str(self.op.kind), errors.ECODE_INVAL)
91 class LUTagsGet(TagsLU):
92 """Returns the tags of a given object.
97 def ExpandNames(self):
98 TagsLU.ExpandNames(self)
100 # Share locks as this is only a read operation
101 self.share_locks = _ShareAll()
103 def Exec(self, feedback_fn):
104 """Returns the tag list.
107 return list(self.target.GetTags())
110 class LUTagsSearch(NoHooksLU):
111 """Searches the tags for a given pattern.
116 def ExpandNames(self):
117 self.needed_locks = {}
119 def CheckPrereq(self):
120 """Check prerequisites.
122 This checks the pattern passed for validity by compiling it.
126 self.re = re.compile(self.op.pattern)
127 except re.error, err:
128 raise errors.OpPrereqError("Invalid search pattern '%s': %s" %
129 (self.op.pattern, err), errors.ECODE_INVAL)
131 def Exec(self, feedback_fn):
132 """Returns the tag list.
136 tgts = [("/cluster", cfg.GetClusterInfo())]
137 ilist = cfg.GetAllInstancesInfo().values()
138 tgts.extend([("/instances/%s" % i.name, i) for i in ilist])
139 nlist = cfg.GetAllNodesInfo().values()
140 tgts.extend([("/nodes/%s" % n.name, n) for n in nlist])
141 tgts.extend(("/nodegroup/%s" % n.name, n)
142 for n in cfg.GetAllNodeGroupsInfo().values())
144 for path, target in tgts:
145 for tag in target.GetTags():
146 if self.re.search(tag):
147 results.append((path, tag))
151 class LUTagsSet(TagsLU):
152 """Sets a tag on a given object.
157 def CheckPrereq(self):
158 """Check prerequisites.
160 This checks the type and length of the tag name and value.
163 TagsLU.CheckPrereq(self)
164 for tag in self.op.tags:
165 objects.TaggableObject.ValidateTag(tag)
167 def Exec(self, feedback_fn):
172 for tag in self.op.tags:
173 self.target.AddTag(tag)
174 except errors.TagError, err:
175 raise errors.OpExecError("Error while setting tag: %s" % str(err))
176 self.cfg.Update(self.target, feedback_fn)
179 class LUTagsDel(TagsLU):
180 """Delete a list of tags from a given object.
185 def CheckPrereq(self):
186 """Check prerequisites.
188 This checks that we have the given tag.
191 TagsLU.CheckPrereq(self)
192 for tag in self.op.tags:
193 objects.TaggableObject.ValidateTag(tag)
194 del_tags = frozenset(self.op.tags)
195 cur_tags = self.target.GetTags()
197 diff_tags = del_tags - cur_tags
199 diff_names = ("'%s'" % i for i in sorted(diff_tags))
200 raise errors.OpPrereqError("Tag(s) %s not found" %
201 (utils.CommaJoin(diff_names), ),
204 def Exec(self, feedback_fn):
205 """Remove the tag from the object.
208 for tag in self.op.tags:
209 self.target.RemoveTag(tag)
210 self.cfg.Update(self.target, feedback_fn)