(2.10) Minor changes regarding hotplug support
[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 ExpandNodeName, ExpandInstanceName, ShareAll
33
34
35 class TagsLU(NoHooksLU): # pylint: disable=W0223
36   """Generic tags LU.
37
38   This is an abstract class which is the parent of all the other tags LUs.
39
40   """
41   def ExpandNames(self):
42     self.group_uuid = None
43     self.needed_locks = {}
44
45     if self.op.kind == constants.TAG_NODE:
46       self.op.name = ExpandNodeName(self.cfg, self.op.name)
47       lock_level = locking.LEVEL_NODE
48       lock_name = self.op.name
49     elif self.op.kind == constants.TAG_INSTANCE:
50       self.op.name = ExpandInstanceName(self.cfg, self.op.name)
51       lock_level = locking.LEVEL_INSTANCE
52       lock_name = self.op.name
53     elif self.op.kind == constants.TAG_NODEGROUP:
54       self.group_uuid = self.cfg.LookupNodeGroup(self.op.name)
55       lock_level = locking.LEVEL_NODEGROUP
56       lock_name = self.group_uuid
57     elif self.op.kind == constants.TAG_NETWORK:
58       self.network_uuid = self.cfg.LookupNetwork(self.op.name)
59       lock_level = locking.LEVEL_NETWORK
60       lock_name = self.network_uuid
61     else:
62       lock_level = None
63       lock_name = None
64
65     if lock_level and getattr(self.op, "use_locking", True):
66       self.needed_locks[lock_level] = lock_name
67
68     # FIXME: Acquire BGL for cluster tag operations (as of this writing it's
69     # not possible to acquire the BGL based on opcode parameters)
70
71   def CheckPrereq(self):
72     """Check prerequisites.
73
74     """
75     if self.op.kind == constants.TAG_CLUSTER:
76       self.target = self.cfg.GetClusterInfo()
77     elif self.op.kind == constants.TAG_NODE:
78       self.target = self.cfg.GetNodeInfo(self.op.name)
79     elif self.op.kind == constants.TAG_INSTANCE:
80       self.target = self.cfg.GetInstanceInfo(self.op.name)
81     elif self.op.kind == constants.TAG_NODEGROUP:
82       self.target = self.cfg.GetNodeGroup(self.group_uuid)
83     elif self.op.kind == constants.TAG_NETWORK:
84       self.target = self.cfg.GetNetwork(self.network_uuid)
85     else:
86       raise errors.OpPrereqError("Wrong tag type requested (%s)" %
87                                  str(self.op.kind), errors.ECODE_INVAL)
88
89
90 class LUTagsGet(TagsLU):
91   """Returns the tags of a given object.
92
93   """
94   REQ_BGL = False
95
96   def ExpandNames(self):
97     TagsLU.ExpandNames(self)
98
99     # Share locks as this is only a read operation
100     self.share_locks = ShareAll()
101
102   def Exec(self, feedback_fn):
103     """Returns the tag list.
104
105     """
106     return list(self.target.GetTags())
107
108
109 class LUTagsSearch(NoHooksLU):
110   """Searches the tags for a given pattern.
111
112   """
113   REQ_BGL = False
114
115   def ExpandNames(self):
116     self.needed_locks = {}
117
118   def CheckPrereq(self):
119     """Check prerequisites.
120
121     This checks the pattern passed for validity by compiling it.
122
123     """
124     try:
125       self.re = re.compile(self.op.pattern)
126     except re.error, err:
127       raise errors.OpPrereqError("Invalid search pattern '%s': %s" %
128                                  (self.op.pattern, err), errors.ECODE_INVAL)
129
130   @staticmethod
131   def _ExtendTagTargets(targets, object_type_name, object_info_dict):
132     return targets.extend(("/%s/%s" % (object_type_name, o.name), o)
133                           for o in object_info_dict.values())
134
135   def Exec(self, feedback_fn):
136     """Returns the tag list.
137
138     """
139     cfg = self.cfg
140     tgts = [("/cluster", cfg.GetClusterInfo())]
141
142     LUTagsSearch._ExtendTagTargets(tgts, "instances", cfg.GetAllInstancesInfo())
143     LUTagsSearch._ExtendTagTargets(tgts, "nodes", cfg.GetAllNodesInfo())
144     LUTagsSearch._ExtendTagTargets(tgts, "nodegroup",
145                                    cfg.GetAllNodeGroupsInfo())
146     LUTagsSearch._ExtendTagTargets(tgts, "network", cfg.GetAllNetworksInfo())
147
148     results = []
149     for path, target in tgts:
150       for tag in target.GetTags():
151         if self.re.search(tag):
152           results.append((path, tag))
153     return results
154
155
156 class LUTagsSet(TagsLU):
157   """Sets a tag on a given object.
158
159   """
160   REQ_BGL = False
161
162   def CheckPrereq(self):
163     """Check prerequisites.
164
165     This checks the type and length of the tag name and value.
166
167     """
168     TagsLU.CheckPrereq(self)
169     for tag in self.op.tags:
170       objects.TaggableObject.ValidateTag(tag)
171
172   def Exec(self, feedback_fn):
173     """Sets the tag.
174
175     """
176     try:
177       for tag in self.op.tags:
178         self.target.AddTag(tag)
179     except errors.TagError, err:
180       raise errors.OpExecError("Error while setting tag: %s" % str(err))
181     self.cfg.Update(self.target, feedback_fn)
182
183
184 class LUTagsDel(TagsLU):
185   """Delete a list of tags from a given object.
186
187   """
188   REQ_BGL = False
189
190   def CheckPrereq(self):
191     """Check prerequisites.
192
193     This checks that we have the given tag.
194
195     """
196     TagsLU.CheckPrereq(self)
197     for tag in self.op.tags:
198       objects.TaggableObject.ValidateTag(tag)
199     del_tags = frozenset(self.op.tags)
200     cur_tags = self.target.GetTags()
201
202     diff_tags = del_tags - cur_tags
203     if diff_tags:
204       diff_names = ("'%s'" % i for i in sorted(diff_tags))
205       raise errors.OpPrereqError("Tag(s) %s not found" %
206                                  (utils.CommaJoin(diff_names), ),
207                                  errors.ECODE_NOENT)
208
209   def Exec(self, feedback_fn):
210     """Remove the tag from the object.
211
212     """
213     for tag in self.op.tags:
214       self.target.RemoveTag(tag)
215     self.cfg.Update(self.target, feedback_fn)