From fb3891d0792bde1636592db7b106b447b7366fbe Mon Sep 17 00:00:00 2001 From: Thomas Thrainer Date: Mon, 13 May 2013 11:16:43 +0200 Subject: [PATCH] Extract tags related logical units from cmdlib LUTags* and their base class, TagsLU, are extracted to tags.py. An additional shared function, _ShareAll, is extracted to common.py for shared usage. Signed-off-by: Thomas Thrainer Reviewed-by: Bernardo Dal Seno --- Makefile.am | 3 +- lib/cmdlib/__init__.py | 187 +----------------------------------------- lib/cmdlib/common.py | 8 ++ lib/cmdlib/tags.py | 210 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 222 insertions(+), 186 deletions(-) create mode 100644 lib/cmdlib/tags.py diff --git a/Makefile.am b/Makefile.am index db39e7e..35d1e5d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -310,7 +310,8 @@ client_PYTHON = \ cmdlib_PYTHON = \ lib/cmdlib/__init__.py \ lib/cmdlib/common.py \ - lib/cmdlib/base.py + lib/cmdlib/base.py \ + lib/cmdlib/tags.py hypervisor_PYTHON = \ lib/hypervisor/__init__.py \ diff --git a/lib/cmdlib/__init__.py b/lib/cmdlib/__init__.py index 0166528..c3148af 100644 --- a/lib/cmdlib/__init__.py +++ b/lib/cmdlib/__init__.py @@ -66,7 +66,8 @@ from ganeti.masterd import iallocator from ganeti.cmdlib.base import ResultWithJobs, LogicalUnit, NoHooksLU, \ Tasklet, _QueryBase from ganeti.cmdlib.common import _ExpandInstanceName, _ExpandItemName, \ - _ExpandNodeName + _ExpandNodeName, _ShareAll +from ganeti.cmdlib.tags import LUTagsGet, LUTagsSearch, LUTagsSet, LUTagsDel import ganeti.masterd.instance # pylint: disable=W0611 @@ -82,13 +83,6 @@ CAN_CHANGE_INSTANCE_OFFLINE = (frozenset(INSTANCE_DOWN) | frozenset([ ])) -def _ShareAll(): - """Returns a dict declaring all lock levels shared. - - """ - return dict.fromkeys(locking.LEVELS, 1) - - def _AnnotateDiskParams(instance, devs, cfg): """Little helper wrapper to the rpc annotation method. @@ -15377,183 +15371,6 @@ class LUGroupEvacuate(LogicalUnit): return ResultWithJobs(jobs) -class TagsLU(NoHooksLU): # pylint: disable=W0223 - """Generic tags LU. - - This is an abstract class which is the parent of all the other tags LUs. - - """ - def ExpandNames(self): - self.group_uuid = None - self.needed_locks = {} - - if self.op.kind == constants.TAG_NODE: - self.op.name = _ExpandNodeName(self.cfg, self.op.name) - lock_level = locking.LEVEL_NODE - lock_name = self.op.name - elif self.op.kind == constants.TAG_INSTANCE: - self.op.name = _ExpandInstanceName(self.cfg, self.op.name) - lock_level = locking.LEVEL_INSTANCE - lock_name = self.op.name - elif self.op.kind == constants.TAG_NODEGROUP: - self.group_uuid = self.cfg.LookupNodeGroup(self.op.name) - lock_level = locking.LEVEL_NODEGROUP - lock_name = self.group_uuid - elif self.op.kind == constants.TAG_NETWORK: - self.network_uuid = self.cfg.LookupNetwork(self.op.name) - lock_level = locking.LEVEL_NETWORK - lock_name = self.network_uuid - else: - lock_level = None - lock_name = None - - if lock_level and getattr(self.op, "use_locking", True): - self.needed_locks[lock_level] = lock_name - - # FIXME: Acquire BGL for cluster tag operations (as of this writing it's - # not possible to acquire the BGL based on opcode parameters) - - def CheckPrereq(self): - """Check prerequisites. - - """ - if self.op.kind == constants.TAG_CLUSTER: - self.target = self.cfg.GetClusterInfo() - elif self.op.kind == constants.TAG_NODE: - self.target = self.cfg.GetNodeInfo(self.op.name) - elif self.op.kind == constants.TAG_INSTANCE: - self.target = self.cfg.GetInstanceInfo(self.op.name) - elif self.op.kind == constants.TAG_NODEGROUP: - self.target = self.cfg.GetNodeGroup(self.group_uuid) - elif self.op.kind == constants.TAG_NETWORK: - self.target = self.cfg.GetNetwork(self.network_uuid) - else: - raise errors.OpPrereqError("Wrong tag type requested (%s)" % - str(self.op.kind), errors.ECODE_INVAL) - - -class LUTagsGet(TagsLU): - """Returns the tags of a given object. - - """ - REQ_BGL = False - - def ExpandNames(self): - TagsLU.ExpandNames(self) - - # Share locks as this is only a read operation - self.share_locks = _ShareAll() - - def Exec(self, feedback_fn): - """Returns the tag list. - - """ - return list(self.target.GetTags()) - - -class LUTagsSearch(NoHooksLU): - """Searches the tags for a given pattern. - - """ - REQ_BGL = False - - def ExpandNames(self): - self.needed_locks = {} - - def CheckPrereq(self): - """Check prerequisites. - - This checks the pattern passed for validity by compiling it. - - """ - try: - self.re = re.compile(self.op.pattern) - except re.error, err: - raise errors.OpPrereqError("Invalid search pattern '%s': %s" % - (self.op.pattern, err), errors.ECODE_INVAL) - - def Exec(self, feedback_fn): - """Returns the tag list. - - """ - cfg = self.cfg - tgts = [("/cluster", cfg.GetClusterInfo())] - ilist = cfg.GetAllInstancesInfo().values() - tgts.extend([("/instances/%s" % i.name, i) for i in ilist]) - nlist = cfg.GetAllNodesInfo().values() - tgts.extend([("/nodes/%s" % n.name, n) for n in nlist]) - tgts.extend(("/nodegroup/%s" % n.name, n) - for n in cfg.GetAllNodeGroupsInfo().values()) - results = [] - for path, target in tgts: - for tag in target.GetTags(): - if self.re.search(tag): - results.append((path, tag)) - return results - - -class LUTagsSet(TagsLU): - """Sets a tag on a given object. - - """ - REQ_BGL = False - - def CheckPrereq(self): - """Check prerequisites. - - This checks the type and length of the tag name and value. - - """ - TagsLU.CheckPrereq(self) - for tag in self.op.tags: - objects.TaggableObject.ValidateTag(tag) - - def Exec(self, feedback_fn): - """Sets the tag. - - """ - try: - for tag in self.op.tags: - self.target.AddTag(tag) - except errors.TagError, err: - raise errors.OpExecError("Error while setting tag: %s" % str(err)) - self.cfg.Update(self.target, feedback_fn) - - -class LUTagsDel(TagsLU): - """Delete a list of tags from a given object. - - """ - REQ_BGL = False - - def CheckPrereq(self): - """Check prerequisites. - - This checks that we have the given tag. - - """ - TagsLU.CheckPrereq(self) - for tag in self.op.tags: - objects.TaggableObject.ValidateTag(tag) - del_tags = frozenset(self.op.tags) - cur_tags = self.target.GetTags() - - diff_tags = del_tags - cur_tags - if diff_tags: - diff_names = ("'%s'" % i for i in sorted(diff_tags)) - raise errors.OpPrereqError("Tag(s) %s not found" % - (utils.CommaJoin(diff_names), ), - errors.ECODE_NOENT) - - def Exec(self, feedback_fn): - """Remove the tag from the object. - - """ - for tag in self.op.tags: - self.target.RemoveTag(tag) - self.cfg.Update(self.target, feedback_fn) - - class LUTestDelay(NoHooksLU): """Sleep for a specified amount of time. diff --git a/lib/cmdlib/common.py b/lib/cmdlib/common.py index f565a0e..60d5fe5 100644 --- a/lib/cmdlib/common.py +++ b/lib/cmdlib/common.py @@ -22,6 +22,7 @@ """Common functions used by multiple logical units.""" from ganeti import errors +from ganeti import locking def _ExpandItemName(fn, name, kind): @@ -49,3 +50,10 @@ def _ExpandInstanceName(cfg, name): def _ExpandNodeName(cfg, name): """Wrapper over L{_ExpandItemName} for nodes.""" return _ExpandItemName(cfg.ExpandNodeName, name, "Node") + + +def _ShareAll(): + """Returns a dict declaring all lock levels shared. + + """ + return dict.fromkeys(locking.LEVELS, 1) diff --git a/lib/cmdlib/tags.py b/lib/cmdlib/tags.py new file mode 100644 index 0000000..0ec27a6 --- /dev/null +++ b/lib/cmdlib/tags.py @@ -0,0 +1,210 @@ +# +# + +# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + + +"""Logical units dealing with tags.""" + +import re + +from ganeti import constants +from ganeti import errors +from ganeti import locking +from ganeti import objects +from ganeti import utils +from ganeti.cmdlib.base import NoHooksLU +from ganeti.cmdlib.common import _ExpandNodeName, _ExpandInstanceName, \ + _ShareAll + + +class TagsLU(NoHooksLU): # pylint: disable=W0223 + """Generic tags LU. + + This is an abstract class which is the parent of all the other tags LUs. + + """ + def ExpandNames(self): + self.group_uuid = None + self.needed_locks = {} + + if self.op.kind == constants.TAG_NODE: + self.op.name = _ExpandNodeName(self.cfg, self.op.name) + lock_level = locking.LEVEL_NODE + lock_name = self.op.name + elif self.op.kind == constants.TAG_INSTANCE: + self.op.name = _ExpandInstanceName(self.cfg, self.op.name) + lock_level = locking.LEVEL_INSTANCE + lock_name = self.op.name + elif self.op.kind == constants.TAG_NODEGROUP: + self.group_uuid = self.cfg.LookupNodeGroup(self.op.name) + lock_level = locking.LEVEL_NODEGROUP + lock_name = self.group_uuid + elif self.op.kind == constants.TAG_NETWORK: + self.network_uuid = self.cfg.LookupNetwork(self.op.name) + lock_level = locking.LEVEL_NETWORK + lock_name = self.network_uuid + else: + lock_level = None + lock_name = None + + if lock_level and getattr(self.op, "use_locking", True): + self.needed_locks[lock_level] = lock_name + + # FIXME: Acquire BGL for cluster tag operations (as of this writing it's + # not possible to acquire the BGL based on opcode parameters) + + def CheckPrereq(self): + """Check prerequisites. + + """ + if self.op.kind == constants.TAG_CLUSTER: + self.target = self.cfg.GetClusterInfo() + elif self.op.kind == constants.TAG_NODE: + self.target = self.cfg.GetNodeInfo(self.op.name) + elif self.op.kind == constants.TAG_INSTANCE: + self.target = self.cfg.GetInstanceInfo(self.op.name) + elif self.op.kind == constants.TAG_NODEGROUP: + self.target = self.cfg.GetNodeGroup(self.group_uuid) + elif self.op.kind == constants.TAG_NETWORK: + self.target = self.cfg.GetNetwork(self.network_uuid) + else: + raise errors.OpPrereqError("Wrong tag type requested (%s)" % + str(self.op.kind), errors.ECODE_INVAL) + + +class LUTagsGet(TagsLU): + """Returns the tags of a given object. + + """ + REQ_BGL = False + + def ExpandNames(self): + TagsLU.ExpandNames(self) + + # Share locks as this is only a read operation + self.share_locks = _ShareAll() + + def Exec(self, feedback_fn): + """Returns the tag list. + + """ + return list(self.target.GetTags()) + + +class LUTagsSearch(NoHooksLU): + """Searches the tags for a given pattern. + + """ + REQ_BGL = False + + def ExpandNames(self): + self.needed_locks = {} + + def CheckPrereq(self): + """Check prerequisites. + + This checks the pattern passed for validity by compiling it. + + """ + try: + self.re = re.compile(self.op.pattern) + except re.error, err: + raise errors.OpPrereqError("Invalid search pattern '%s': %s" % + (self.op.pattern, err), errors.ECODE_INVAL) + + def Exec(self, feedback_fn): + """Returns the tag list. + + """ + cfg = self.cfg + tgts = [("/cluster", cfg.GetClusterInfo())] + ilist = cfg.GetAllInstancesInfo().values() + tgts.extend([("/instances/%s" % i.name, i) for i in ilist]) + nlist = cfg.GetAllNodesInfo().values() + tgts.extend([("/nodes/%s" % n.name, n) for n in nlist]) + tgts.extend(("/nodegroup/%s" % n.name, n) + for n in cfg.GetAllNodeGroupsInfo().values()) + results = [] + for path, target in tgts: + for tag in target.GetTags(): + if self.re.search(tag): + results.append((path, tag)) + return results + + +class LUTagsSet(TagsLU): + """Sets a tag on a given object. + + """ + REQ_BGL = False + + def CheckPrereq(self): + """Check prerequisites. + + This checks the type and length of the tag name and value. + + """ + TagsLU.CheckPrereq(self) + for tag in self.op.tags: + objects.TaggableObject.ValidateTag(tag) + + def Exec(self, feedback_fn): + """Sets the tag. + + """ + try: + for tag in self.op.tags: + self.target.AddTag(tag) + except errors.TagError, err: + raise errors.OpExecError("Error while setting tag: %s" % str(err)) + self.cfg.Update(self.target, feedback_fn) + + +class LUTagsDel(TagsLU): + """Delete a list of tags from a given object. + + """ + REQ_BGL = False + + def CheckPrereq(self): + """Check prerequisites. + + This checks that we have the given tag. + + """ + TagsLU.CheckPrereq(self) + for tag in self.op.tags: + objects.TaggableObject.ValidateTag(tag) + del_tags = frozenset(self.op.tags) + cur_tags = self.target.GetTags() + + diff_tags = del_tags - cur_tags + if diff_tags: + diff_names = ("'%s'" % i for i in sorted(diff_tags)) + raise errors.OpPrereqError("Tag(s) %s not found" % + (utils.CommaJoin(diff_names), ), + errors.ECODE_NOENT) + + def Exec(self, feedback_fn): + """Remove the tag from the object. + + """ + for tag in self.op.tags: + self.target.RemoveTag(tag) + self.cfg.Update(self.target, feedback_fn) -- 1.7.10.4