Revision fb3891d0

b/Makefile.am
310 310
cmdlib_PYTHON = \
311 311
	lib/cmdlib/__init__.py \
312 312
	lib/cmdlib/common.py \
313
	lib/cmdlib/base.py
313
	lib/cmdlib/base.py \
314
	lib/cmdlib/tags.py
314 315

  
315 316
hypervisor_PYTHON = \
316 317
	lib/hypervisor/__init__.py \
b/lib/cmdlib/__init__.py
66 66
from ganeti.cmdlib.base import ResultWithJobs, LogicalUnit, NoHooksLU, \
67 67
  Tasklet, _QueryBase
68 68
from ganeti.cmdlib.common import _ExpandInstanceName, _ExpandItemName, \
69
  _ExpandNodeName
69
  _ExpandNodeName, _ShareAll
70
from ganeti.cmdlib.tags import LUTagsGet, LUTagsSearch, LUTagsSet, LUTagsDel
70 71

  
71 72
import ganeti.masterd.instance # pylint: disable=W0611
72 73

  
......
82 83
  ]))
83 84

  
84 85

  
85
def _ShareAll():
86
  """Returns a dict declaring all lock levels shared.
87

  
88
  """
89
  return dict.fromkeys(locking.LEVELS, 1)
90

  
91

  
92 86
def _AnnotateDiskParams(instance, devs, cfg):
93 87
  """Little helper wrapper to the rpc annotation method.
94 88

  
......
15377 15371
    return ResultWithJobs(jobs)
15378 15372

  
15379 15373

  
15380
class TagsLU(NoHooksLU): # pylint: disable=W0223
15381
  """Generic tags LU.
15382

  
15383
  This is an abstract class which is the parent of all the other tags LUs.
15384

  
15385
  """
15386
  def ExpandNames(self):
15387
    self.group_uuid = None
15388
    self.needed_locks = {}
15389

  
15390
    if self.op.kind == constants.TAG_NODE:
15391
      self.op.name = _ExpandNodeName(self.cfg, self.op.name)
15392
      lock_level = locking.LEVEL_NODE
15393
      lock_name = self.op.name
15394
    elif self.op.kind == constants.TAG_INSTANCE:
15395
      self.op.name = _ExpandInstanceName(self.cfg, self.op.name)
15396
      lock_level = locking.LEVEL_INSTANCE
15397
      lock_name = self.op.name
15398
    elif self.op.kind == constants.TAG_NODEGROUP:
15399
      self.group_uuid = self.cfg.LookupNodeGroup(self.op.name)
15400
      lock_level = locking.LEVEL_NODEGROUP
15401
      lock_name = self.group_uuid
15402
    elif self.op.kind == constants.TAG_NETWORK:
15403
      self.network_uuid = self.cfg.LookupNetwork(self.op.name)
15404
      lock_level = locking.LEVEL_NETWORK
15405
      lock_name = self.network_uuid
15406
    else:
15407
      lock_level = None
15408
      lock_name = None
15409

  
15410
    if lock_level and getattr(self.op, "use_locking", True):
15411
      self.needed_locks[lock_level] = lock_name
15412

  
15413
    # FIXME: Acquire BGL for cluster tag operations (as of this writing it's
15414
    # not possible to acquire the BGL based on opcode parameters)
15415

  
15416
  def CheckPrereq(self):
15417
    """Check prerequisites.
15418

  
15419
    """
15420
    if self.op.kind == constants.TAG_CLUSTER:
15421
      self.target = self.cfg.GetClusterInfo()
15422
    elif self.op.kind == constants.TAG_NODE:
15423
      self.target = self.cfg.GetNodeInfo(self.op.name)
15424
    elif self.op.kind == constants.TAG_INSTANCE:
15425
      self.target = self.cfg.GetInstanceInfo(self.op.name)
15426
    elif self.op.kind == constants.TAG_NODEGROUP:
15427
      self.target = self.cfg.GetNodeGroup(self.group_uuid)
15428
    elif self.op.kind == constants.TAG_NETWORK:
15429
      self.target = self.cfg.GetNetwork(self.network_uuid)
15430
    else:
15431
      raise errors.OpPrereqError("Wrong tag type requested (%s)" %
15432
                                 str(self.op.kind), errors.ECODE_INVAL)
15433

  
15434

  
15435
class LUTagsGet(TagsLU):
15436
  """Returns the tags of a given object.
15437

  
15438
  """
15439
  REQ_BGL = False
15440

  
15441
  def ExpandNames(self):
15442
    TagsLU.ExpandNames(self)
15443

  
15444
    # Share locks as this is only a read operation
15445
    self.share_locks = _ShareAll()
15446

  
15447
  def Exec(self, feedback_fn):
15448
    """Returns the tag list.
15449

  
15450
    """
15451
    return list(self.target.GetTags())
15452

  
15453

  
15454
class LUTagsSearch(NoHooksLU):
15455
  """Searches the tags for a given pattern.
15456

  
15457
  """
15458
  REQ_BGL = False
15459

  
15460
  def ExpandNames(self):
15461
    self.needed_locks = {}
15462

  
15463
  def CheckPrereq(self):
15464
    """Check prerequisites.
15465

  
15466
    This checks the pattern passed for validity by compiling it.
15467

  
15468
    """
15469
    try:
15470
      self.re = re.compile(self.op.pattern)
15471
    except re.error, err:
15472
      raise errors.OpPrereqError("Invalid search pattern '%s': %s" %
15473
                                 (self.op.pattern, err), errors.ECODE_INVAL)
15474

  
15475
  def Exec(self, feedback_fn):
15476
    """Returns the tag list.
15477

  
15478
    """
15479
    cfg = self.cfg
15480
    tgts = [("/cluster", cfg.GetClusterInfo())]
15481
    ilist = cfg.GetAllInstancesInfo().values()
15482
    tgts.extend([("/instances/%s" % i.name, i) for i in ilist])
15483
    nlist = cfg.GetAllNodesInfo().values()
15484
    tgts.extend([("/nodes/%s" % n.name, n) for n in nlist])
15485
    tgts.extend(("/nodegroup/%s" % n.name, n)
15486
                for n in cfg.GetAllNodeGroupsInfo().values())
15487
    results = []
15488
    for path, target in tgts:
15489
      for tag in target.GetTags():
15490
        if self.re.search(tag):
15491
          results.append((path, tag))
15492
    return results
15493

  
15494

  
15495
class LUTagsSet(TagsLU):
15496
  """Sets a tag on a given object.
15497

  
15498
  """
15499
  REQ_BGL = False
15500

  
15501
  def CheckPrereq(self):
15502
    """Check prerequisites.
15503

  
15504
    This checks the type and length of the tag name and value.
15505

  
15506
    """
15507
    TagsLU.CheckPrereq(self)
15508
    for tag in self.op.tags:
15509
      objects.TaggableObject.ValidateTag(tag)
15510

  
15511
  def Exec(self, feedback_fn):
15512
    """Sets the tag.
15513

  
15514
    """
15515
    try:
15516
      for tag in self.op.tags:
15517
        self.target.AddTag(tag)
15518
    except errors.TagError, err:
15519
      raise errors.OpExecError("Error while setting tag: %s" % str(err))
15520
    self.cfg.Update(self.target, feedback_fn)
15521

  
15522

  
15523
class LUTagsDel(TagsLU):
15524
  """Delete a list of tags from a given object.
15525

  
15526
  """
15527
  REQ_BGL = False
15528

  
15529
  def CheckPrereq(self):
15530
    """Check prerequisites.
15531

  
15532
    This checks that we have the given tag.
15533

  
15534
    """
15535
    TagsLU.CheckPrereq(self)
15536
    for tag in self.op.tags:
15537
      objects.TaggableObject.ValidateTag(tag)
15538
    del_tags = frozenset(self.op.tags)
15539
    cur_tags = self.target.GetTags()
15540

  
15541
    diff_tags = del_tags - cur_tags
15542
    if diff_tags:
15543
      diff_names = ("'%s'" % i for i in sorted(diff_tags))
15544
      raise errors.OpPrereqError("Tag(s) %s not found" %
15545
                                 (utils.CommaJoin(diff_names), ),
15546
                                 errors.ECODE_NOENT)
15547

  
15548
  def Exec(self, feedback_fn):
15549
    """Remove the tag from the object.
15550

  
15551
    """
15552
    for tag in self.op.tags:
15553
      self.target.RemoveTag(tag)
15554
    self.cfg.Update(self.target, feedback_fn)
15555

  
15556

  
15557 15374
class LUTestDelay(NoHooksLU):
15558 15375
  """Sleep for a specified amount of time.
15559 15376

  
b/lib/cmdlib/common.py
22 22
"""Common functions used by multiple logical units."""
23 23

  
24 24
from ganeti import errors
25
from ganeti import locking
25 26

  
26 27

  
27 28
def _ExpandItemName(fn, name, kind):
......
49 50
def _ExpandNodeName(cfg, name):
50 51
  """Wrapper over L{_ExpandItemName} for nodes."""
51 52
  return _ExpandItemName(cfg.ExpandNodeName, name, "Node")
53

  
54

  
55
def _ShareAll():
56
  """Returns a dict declaring all lock levels shared.
57

  
58
  """
59
  return dict.fromkeys(locking.LEVELS, 1)
b/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)

Also available in: Unified diff