cmdlib: Extract instance query related functionality
[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, \
33   _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.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
62     else:
63       lock_level = None
64       lock_name = None
65
66     if lock_level and getattr(self.op, "use_locking", True):
67       self.needed_locks[lock_level] = lock_name
68
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)
71
72   def CheckPrereq(self):
73     """Check prerequisites.
74
75     """
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)
86     else:
87       raise errors.OpPrereqError("Wrong tag type requested (%s)" %
88                                  str(self.op.kind), errors.ECODE_INVAL)
89
90
91 class LUTagsGet(TagsLU):
92   """Returns the tags of a given object.
93
94   """
95   REQ_BGL = False
96
97   def ExpandNames(self):
98     TagsLU.ExpandNames(self)
99
100     # Share locks as this is only a read operation
101     self.share_locks = _ShareAll()
102
103   def Exec(self, feedback_fn):
104     """Returns the tag list.
105
106     """
107     return list(self.target.GetTags())
108
109
110 class LUTagsSearch(NoHooksLU):
111   """Searches the tags for a given pattern.
112
113   """
114   REQ_BGL = False
115
116   def ExpandNames(self):
117     self.needed_locks = {}
118
119   def CheckPrereq(self):
120     """Check prerequisites.
121
122     This checks the pattern passed for validity by compiling it.
123
124     """
125     try:
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)
130
131   def Exec(self, feedback_fn):
132     """Returns the tag list.
133
134     """
135     cfg = self.cfg
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())
143     results = []
144     for path, target in tgts:
145       for tag in target.GetTags():
146         if self.re.search(tag):
147           results.append((path, tag))
148     return results
149
150
151 class LUTagsSet(TagsLU):
152   """Sets a tag on a given object.
153
154   """
155   REQ_BGL = False
156
157   def CheckPrereq(self):
158     """Check prerequisites.
159
160     This checks the type and length of the tag name and value.
161
162     """
163     TagsLU.CheckPrereq(self)
164     for tag in self.op.tags:
165       objects.TaggableObject.ValidateTag(tag)
166
167   def Exec(self, feedback_fn):
168     """Sets the tag.
169
170     """
171     try:
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)
177
178
179 class LUTagsDel(TagsLU):
180   """Delete a list of tags from a given object.
181
182   """
183   REQ_BGL = False
184
185   def CheckPrereq(self):
186     """Check prerequisites.
187
188     This checks that we have the given tag.
189
190     """
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()
196
197     diff_tags = del_tags - cur_tags
198     if diff_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), ),
202                                  errors.ECODE_NOENT)
203
204   def Exec(self, feedback_fn):
205     """Remove the tag from the object.
206
207     """
208     for tag in self.op.tags:
209       self.target.RemoveTag(tag)
210     self.cfg.Update(self.target, feedback_fn)