Revision 5c947f38
b/lib/cmdlib.py | ||
---|---|---|
3506 | 3506 |
if not rpc.call_export_remove(node, instance.name): |
3507 | 3507 |
logger.Error("could not remove older export for instance %s" |
3508 | 3508 |
" on node %s" % (instance.name, node)) |
3509 |
|
|
3510 |
|
|
3511 |
class TagsLU(NoHooksLU): |
|
3512 |
"""Generic tags LU. |
|
3513 |
|
|
3514 |
This is an abstract class which is the parent of all the other tags LUs. |
|
3515 |
|
|
3516 |
""" |
|
3517 |
def CheckPrereq(self): |
|
3518 |
"""Check prerequisites. |
|
3519 |
|
|
3520 |
""" |
|
3521 |
if self.op.kind == constants.TAG_CLUSTER: |
|
3522 |
self.target = self.cfg.GetClusterInfo() |
|
3523 |
elif self.op.kind == constants.TAG_NODE: |
|
3524 |
name = self.cfg.ExpandNodeName(self.op.name) |
|
3525 |
if name is None: |
|
3526 |
raise errors.OpPrereqError, ("Invalid node name (%s)" % |
|
3527 |
(self.op.name,)) |
|
3528 |
self.op.name = name |
|
3529 |
self.target = self.cfg.GetNodeInfo(name) |
|
3530 |
elif self.op.kind == constants.TAG_INSTANCE: |
|
3531 |
name = self.cfg.ExpandInstanceName(name) |
|
3532 |
if name is None: |
|
3533 |
raise errors.OpPrereqError, ("Invalid instance name (%s)" % |
|
3534 |
(self.op.name,)) |
|
3535 |
self.op.name = name |
|
3536 |
self.target = self.cfg.GetInstanceInfo(name) |
|
3537 |
else: |
|
3538 |
raise errors.OpPrereqError, ("Wrong tag type requested (%s)" % |
|
3539 |
str(self.op.kind)) |
|
3540 |
|
|
3541 |
|
|
3542 |
class LUGetTags(TagsLU): |
|
3543 |
"""Returns the tags of a given object. |
|
3544 |
|
|
3545 |
""" |
|
3546 |
_OP_REQP = ["kind", "name"] |
|
3547 |
|
|
3548 |
def Exec(self, feedback_fn): |
|
3549 |
"""Returns the tag list. |
|
3550 |
|
|
3551 |
""" |
|
3552 |
return self.target.GetTags() |
|
3553 |
|
|
3554 |
|
|
3555 |
class LUAddTag(TagsLU): |
|
3556 |
"""Sets a tag on a given object. |
|
3557 |
|
|
3558 |
""" |
|
3559 |
_OP_REQP = ["kind", "name", "tag"] |
|
3560 |
|
|
3561 |
def CheckPrereq(self): |
|
3562 |
"""Check prerequisites. |
|
3563 |
|
|
3564 |
This checks the type and length of the tag name and value. |
|
3565 |
|
|
3566 |
""" |
|
3567 |
TagsLU.CheckPrereq(self) |
|
3568 |
objects.TaggableObject.ValidateTag(self.op.tag) |
|
3569 |
|
|
3570 |
def Exec(self, feedback_fn): |
|
3571 |
"""Sets the tag. |
|
3572 |
|
|
3573 |
""" |
|
3574 |
try: |
|
3575 |
self.target.AddTag(self.op.tag) |
|
3576 |
except errors.TagError, err: |
|
3577 |
raise errors.OpExecError, ("Error while setting tag: %s" % str(err)) |
|
3578 |
try: |
|
3579 |
self.cfg.Update(self.target) |
|
3580 |
except errors.ConfigurationError: |
|
3581 |
raise errors.OpRetryError, ("There has been a modification to the" |
|
3582 |
" config file and the operation has been" |
|
3583 |
" aborted. Please retry.") |
|
3584 |
|
|
3585 |
|
|
3586 |
class LUDelTag(TagsLU): |
|
3587 |
"""Delete a tag from a given object. |
|
3588 |
|
|
3589 |
""" |
|
3590 |
_OP_REQP = ["kind", "name", "tag"] |
|
3591 |
|
|
3592 |
def CheckPrereq(self): |
|
3593 |
"""Check prerequisites. |
|
3594 |
|
|
3595 |
This checks that we have the given tag. |
|
3596 |
|
|
3597 |
""" |
|
3598 |
TagsLU.CheckPrereq(self) |
|
3599 |
objects.TaggableObject.ValidateTag(self.op.tag) |
|
3600 |
if self.op.tag not in self.target.GetTags(): |
|
3601 |
raise errors.OpPrereqError, ("Tag not found") |
|
3602 |
|
|
3603 |
def Exec(self, feedback_fn): |
|
3604 |
"""Remove the tag from the object. |
|
3605 |
|
|
3606 |
""" |
|
3607 |
self.target.RemoveTag(self.op.tag) |
|
3608 |
try: |
|
3609 |
self.cfg.Update(self.target) |
|
3610 |
except errors.ConfigurationError: |
|
3611 |
raise errors.OpRetryError, ("There has been a modification to the" |
|
3612 |
" config file and the operation has been" |
|
3613 |
" aborted. Please retry.") |
b/lib/constants.py | ||
---|---|---|
85 | 85 |
# common exit codes |
86 | 86 |
EXIT_NOTMASTER = 11 |
87 | 87 |
|
88 |
# tags |
|
89 |
TAG_CLUSTER = "cluster" |
|
90 |
TAG_NODE = "node" |
|
91 |
TAG_INSTANCE = "instance" |
|
92 |
MAX_TAG_LEN = 128 |
|
93 |
MAX_TAGS_PER_OBJ = 4096 |
|
94 |
|
|
88 | 95 |
# others |
89 | 96 |
DEFAULT_BRIDGE = "xen-br0" |
90 | 97 |
SYNC_SPEED = 30 * 1024 |
b/lib/errors.py | ||
---|---|---|
136 | 136 |
""" |
137 | 137 |
|
138 | 138 |
|
139 |
class OpRetryError(OpExecError): |
|
140 |
"""Error during OpCode execution, action can be retried. |
|
141 |
|
|
142 |
""" |
|
143 |
|
|
144 |
|
|
139 | 145 |
class OpCodeUnknown(GenericError): |
140 | 146 |
"""Unknown opcode submitted. |
141 | 147 |
|
... | ... | |
173 | 179 |
class SshKeyError(GenericError): |
174 | 180 |
"""Invalid SSH key. |
175 | 181 |
""" |
182 |
|
|
183 |
|
|
184 |
class TagError(GenericError): |
|
185 |
"""Generic tag error. |
|
186 |
|
|
187 |
The argument to this exception will show the exact error. |
|
188 |
|
|
189 |
""" |
b/lib/mcpu.py | ||
---|---|---|
82 | 82 |
# exports lu |
83 | 83 |
opcodes.OpQueryExports: cmdlib.LUQueryExports, |
84 | 84 |
opcodes.OpExportInstance: cmdlib.LUExportInstance, |
85 |
# tags lu |
|
86 |
opcodes.OpGetTags: cmdlib.LUGetTags, |
|
87 |
opcodes.OpSetTag: cmdlib.LUAddTag, |
|
88 |
opcodes.OpDelTag: cmdlib.LUDelTag, |
|
85 | 89 |
} |
86 | 90 |
|
87 | 91 |
|
b/lib/objects.py | ||
---|---|---|
30 | 30 |
import cPickle |
31 | 31 |
from cStringIO import StringIO |
32 | 32 |
import ConfigParser |
33 |
import re |
|
33 | 34 |
|
34 | 35 |
from ganeti import errors |
36 |
from ganeti import constants |
|
35 | 37 |
|
36 | 38 |
|
37 | 39 |
__all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance", |
... | ... | |
146 | 148 |
return ConfigObject.Load(StringIO(data)) |
147 | 149 |
|
148 | 150 |
|
151 |
class TaggableObject(object): |
|
152 |
"""An generic class supporting tags. |
|
153 |
|
|
154 |
""" |
|
155 |
@staticmethod |
|
156 |
def ValidateTag(tag): |
|
157 |
"""Check if a tag is valid. |
|
158 |
|
|
159 |
If the tag is invalid, an errors.TagError will be raised. The |
|
160 |
function has no return value. |
|
161 |
|
|
162 |
""" |
|
163 |
if not isinstance(tag, basestring): |
|
164 |
raise errors.TagError, ("Invalid tag type (not a string)") |
|
165 |
if len(tag) > constants.MAX_TAG_LEN: |
|
166 |
raise errors.TagError, ("Tag too long (>%d)" % |
|
167 |
constants.MAX_TAG_LEN) |
|
168 |
if not tag: |
|
169 |
raise errors.TagError, ("Tags cannot be empty") |
|
170 |
if not re.match("^[ \w.+*/:-]+$", tag): |
|
171 |
raise errors.TagError, ("Tag contains invalid characters") |
|
172 |
|
|
173 |
def GetTags(self): |
|
174 |
"""Return the tags list. |
|
175 |
|
|
176 |
""" |
|
177 |
tags = getattr(self, "tags", None) |
|
178 |
if tags is None: |
|
179 |
tags = self.tags = set() |
|
180 |
return tags |
|
181 |
|
|
182 |
def AddTag(self, tag): |
|
183 |
"""Add a new tag. |
|
184 |
|
|
185 |
""" |
|
186 |
self.ValidateTag(tag) |
|
187 |
tags = self.GetTags() |
|
188 |
if len(tags) >= constants.MAX_TAGS_PER_OBJ: |
|
189 |
raise errors.TagError, ("Too many tags") |
|
190 |
self.GetTags().add(tag) |
|
191 |
|
|
192 |
def RemoveTag(self, tag): |
|
193 |
"""Remove a tag. |
|
194 |
|
|
195 |
""" |
|
196 |
self.ValidateTag(tag) |
|
197 |
tags = self.GetTags() |
|
198 |
try: |
|
199 |
tags.remove(tag) |
|
200 |
except KeyError: |
|
201 |
raise errors.TagError, ("Tag not found") |
|
202 |
|
|
203 |
|
|
149 | 204 |
class ConfigData(ConfigObject): |
150 | 205 |
"""Top-level config object.""" |
151 | 206 |
__slots__ = ["cluster", "nodes", "instances"] |
... | ... | |
231 | 286 |
return result |
232 | 287 |
|
233 | 288 |
|
234 |
class Instance(ConfigObject): |
|
289 |
class Instance(ConfigObject, TaggableObject):
|
|
235 | 290 |
"""Config object representing an instance.""" |
236 | 291 |
__slots__ = [ |
237 | 292 |
"name", |
... | ... | |
243 | 298 |
"nics", |
244 | 299 |
"disks", |
245 | 300 |
"disk_template", |
301 |
"tags", |
|
246 | 302 |
] |
247 | 303 |
|
248 | 304 |
def _ComputeSecondaryNodes(self): |
... | ... | |
337 | 393 |
] |
338 | 394 |
|
339 | 395 |
|
340 |
class Node(ConfigObject): |
|
396 |
class Node(ConfigObject, TaggableObject):
|
|
341 | 397 |
"""Config object representing a node.""" |
342 |
__slots__ = ["name", "primary_ip", "secondary_ip"] |
|
398 |
__slots__ = ["name", "primary_ip", "secondary_ip", "tags"]
|
|
343 | 399 |
|
344 | 400 |
|
345 |
class Cluster(ConfigObject): |
|
401 |
class Cluster(ConfigObject, TaggableObject):
|
|
346 | 402 |
"""Config object representing the cluster.""" |
347 | 403 |
__slots__ = [ |
348 | 404 |
"config_version", |
... | ... | |
353 | 409 |
"mac_prefix", |
354 | 410 |
"volume_group_name", |
355 | 411 |
"default_bridge", |
412 |
"tags", |
|
356 | 413 |
] |
357 | 414 |
|
415 |
|
|
358 | 416 |
class SerializableConfigParser(ConfigParser.SafeConfigParser): |
359 | 417 |
"""Simple wrapper over ConfigParse that allows serialization. |
360 | 418 |
|
b/lib/opcodes.py | ||
---|---|---|
239 | 239 |
"""Export an instance.""" |
240 | 240 |
OP_ID = "OP_BACKUP_EXPORT" |
241 | 241 |
__slots__ = ["instance_name", "target_node", "shutdown"] |
242 |
|
|
243 |
|
|
244 |
# Tags opcodes |
|
245 |
class OpGetTags(OpCode): |
|
246 |
"""Returns the tags of the given object.""" |
|
247 |
OP_ID = "OP_TAGS_GET" |
|
248 |
__slots__ = ["kind", "name"] |
|
249 |
|
|
250 |
|
|
251 |
class OpSetTag(OpCode): |
|
252 |
"""Sets the value of a tag on a given object.""" |
|
253 |
OP_ID = "OP_TAGS_SET" |
|
254 |
__slots__ = ["kind", "name", "tag"] |
|
255 |
|
|
256 |
|
|
257 |
class OpDelTag(OpCode): |
|
258 |
"""Remove a tag from a given object.""" |
|
259 |
OP_ID = "OP_TAGS_DEL" |
|
260 |
__slots__ = ["kind", "name", "tag"] |
Also available in: Unified diff