23 |
23 |
|
24 |
24 |
import re
|
25 |
25 |
import operator
|
|
26 |
import ipaddr
|
26 |
27 |
|
27 |
28 |
from ganeti import compat
|
28 |
29 |
from ganeti import utils
|
29 |
30 |
from ganeti import constants
|
|
31 |
from ganeti import objects
|
30 |
32 |
|
31 |
33 |
|
32 |
34 |
_PAREN_RE = re.compile("^[a-zA-Z0-9_-]+$")
|
... | ... | |
359 |
361 |
#: Maybe a list (list or None)
|
360 |
362 |
TMaybeList = TMaybe(TList)
|
361 |
363 |
|
|
364 |
|
|
365 |
#: a non-negative number (value > 0)
|
|
366 |
# val_type should be TInt, TDouble (== TFloat), or TNumber
|
|
367 |
def TNonNegative(val_type):
|
|
368 |
return WithDesc("EqualOrGreaterThanZero")(TAnd(val_type, lambda v: v >= 0))
|
|
369 |
|
|
370 |
|
|
371 |
#: a positive number (value >= 0)
|
|
372 |
# val_type should be TInt, TDouble (== TFloat), or TNumber
|
|
373 |
def TPositive(val_type):
|
|
374 |
return WithDesc("GreaterThanZero")(TAnd(val_type, lambda v: v > 0))
|
|
375 |
|
|
376 |
|
362 |
377 |
#: a non-negative integer (value >= 0)
|
363 |
|
TNonNegativeInt = \
|
364 |
|
TAnd(TInt, WithDesc("EqualOrGreaterThanZero")(lambda v: v >= 0))
|
|
378 |
TNonNegativeInt = TNonNegative(TInt)
|
365 |
379 |
|
366 |
380 |
#: a positive integer (value > 0)
|
367 |
|
TPositiveInt = \
|
368 |
|
TAnd(TInt, WithDesc("GreaterThanZero")(lambda v: v > 0))
|
|
381 |
TPositiveInt = TPositive(TInt)
|
369 |
382 |
|
370 |
383 |
#: a maybe positive integer (positive integer or None)
|
371 |
384 |
TMaybePositiveInt = TMaybe(TPositiveInt)
|
... | ... | |
383 |
396 |
TRegex(re.compile("^%s$" %
|
384 |
397 |
constants.JOB_ID_TEMPLATE))))
|
385 |
398 |
|
|
399 |
#: Double (== Float)
|
|
400 |
TDouble = TFloat
|
|
401 |
|
386 |
402 |
#: Number
|
387 |
403 |
TNumber = TOr(TInt, TFloat)
|
388 |
404 |
|
... | ... | |
415 |
431 |
TMaybeListOf = lambda item_type: TMaybe(TListOf(item_type))
|
416 |
432 |
|
417 |
433 |
|
|
434 |
def TTupleOf(*val_types):
|
|
435 |
"""Checks if a given value is a list with the proper size and its
|
|
436 |
elements match the given types.
|
|
437 |
|
|
438 |
"""
|
|
439 |
desc = WithDesc("Tuple of %s" % (Parens(val_types), ))
|
|
440 |
return desc(TAnd(TIsLength(len(val_types)), TItems(val_types)))
|
|
441 |
|
|
442 |
|
|
443 |
def TSetOf(val_type):
|
|
444 |
"""Checks if a given value is a list with all elements of the same
|
|
445 |
type and eliminates duplicated elements.
|
|
446 |
|
|
447 |
"""
|
|
448 |
desc = WithDesc("Set of %s" % (Parens(val_type), ))
|
|
449 |
return desc(lambda st: TListOf(val_type)(list(set(st))))
|
|
450 |
|
|
451 |
|
418 |
452 |
def TDictOf(key_type, val_type):
|
419 |
453 |
"""Checks a dict type for the type of its key/values.
|
420 |
454 |
|
... | ... | |
497 |
531 |
|
498 |
532 |
return desc(lambda value: compat.all(check(i)
|
499 |
533 |
for (check, i) in zip(items, value)))
|
|
534 |
|
|
535 |
|
|
536 |
TAllocPolicy = TElemOf(constants.VALID_ALLOC_POLICIES)
|
|
537 |
TCVErrorCode = TElemOf(constants.CV_ALL_ECODES_STRINGS)
|
|
538 |
TQueryResultCode = TElemOf(constants.RS_ALL)
|
|
539 |
TExportTarget = TOr(TNonEmptyString, TList)
|
|
540 |
TExportMode = TElemOf(constants.EXPORT_MODES)
|
|
541 |
TDiskIndex = TAnd(TNonNegativeInt, lambda val: val < constants.MAX_DISKS)
|
|
542 |
TReplaceDisksMode = TElemOf(constants.REPLACE_MODES)
|
|
543 |
TDiskTemplate = TElemOf(constants.DISK_TEMPLATES)
|
|
544 |
TNodeEvacMode = TElemOf(constants.IALLOCATOR_NEVAC_MODES)
|
|
545 |
TIAllocatorTestDir = TElemOf(constants.VALID_IALLOCATOR_DIRECTIONS)
|
|
546 |
TIAllocatorMode = TElemOf(constants.VALID_IALLOCATOR_MODES)
|
|
547 |
|
|
548 |
|
|
549 |
def TSetParamsMods(fn):
|
|
550 |
"""Generates a check for modification lists.
|
|
551 |
|
|
552 |
"""
|
|
553 |
# Old format
|
|
554 |
# TODO: Remove in version 2.11 including support in LUInstanceSetParams
|
|
555 |
old_mod_item_fn = \
|
|
556 |
TAnd(TIsLength(2),
|
|
557 |
TItems([TOr(TElemOf(constants.DDMS_VALUES), TNonNegativeInt), fn]))
|
|
558 |
|
|
559 |
# New format, supporting adding/removing disks/NICs at arbitrary indices
|
|
560 |
mod_item_fn = \
|
|
561 |
TAnd(TIsLength(3), TItems([
|
|
562 |
TElemOf(constants.DDMS_VALUES_WITH_MODIFY),
|
|
563 |
Comment("Device index, can be negative, e.g. -1 for last disk")
|
|
564 |
(TOr(TInt, TString)),
|
|
565 |
fn,
|
|
566 |
]))
|
|
567 |
|
|
568 |
return TOr(Comment("Recommended")(TListOf(mod_item_fn)),
|
|
569 |
Comment("Deprecated")(TListOf(old_mod_item_fn)))
|
|
570 |
|
|
571 |
|
|
572 |
TINicParams = \
|
|
573 |
Comment("NIC parameters")(TDictOf(TElemOf(constants.INIC_PARAMS),
|
|
574 |
TMaybeString))
|
|
575 |
|
|
576 |
TIDiskParams = \
|
|
577 |
Comment("Disk parameters")(TDictOf(TElemOf(constants.IDISK_PARAMS),
|
|
578 |
TOr(TNonEmptyString, TInt)))
|
|
579 |
|
|
580 |
THypervisor = TElemOf(constants.HYPER_TYPES)
|
|
581 |
TMigrationMode = TElemOf(constants.HT_MIGRATION_MODES)
|
|
582 |
TNICMode = TElemOf(constants.NIC_VALID_MODES)
|
|
583 |
TInstCreateMode = TElemOf(constants.INSTANCE_CREATE_MODES)
|
|
584 |
TRebootType = TElemOf(constants.REBOOT_TYPES)
|
|
585 |
TFileDriver = TElemOf(constants.FILE_DRIVER)
|
|
586 |
TOobCommand = TElemOf(constants.OOB_COMMANDS)
|
|
587 |
TQueryTypeOp = TElemOf(constants.QR_VIA_OP)
|
|
588 |
|
|
589 |
TDiskParams = \
|
|
590 |
Comment("Disk parameters")(TDictOf(TNonEmptyString,
|
|
591 |
TOr(TNonEmptyString, TInt)))
|
|
592 |
|
|
593 |
TDiskChanges = \
|
|
594 |
TAnd(TIsLength(2),
|
|
595 |
TItems([Comment("Disk index")(TNonNegativeInt),
|
|
596 |
Comment("Parameters")(TDiskParams)]))
|
|
597 |
|
|
598 |
TRecreateDisksInfo = TOr(TListOf(TNonNegativeInt), TListOf(TDiskChanges))
|
|
599 |
|
|
600 |
|
|
601 |
def TStorageType(val):
|
|
602 |
"""Builds a function that checks if a given value is a valid storage
|
|
603 |
type.
|
|
604 |
|
|
605 |
"""
|
|
606 |
return (val in constants.STORAGE_TYPES)
|
|
607 |
|
|
608 |
|
|
609 |
TTagKind = TElemOf(constants.VALID_TAG_TYPES)
|
|
610 |
TDdmSimple = TElemOf(constants.DDMS_VALUES)
|
|
611 |
TVerifyOptionalChecks = TElemOf(constants.VERIFY_OPTIONAL_CHECKS)
|
|
612 |
|
|
613 |
|
|
614 |
@WithDesc("IPv4 network")
|
|
615 |
def _CheckCIDRNetNotation(value):
|
|
616 |
"""Ensure a given CIDR notation type is valid.
|
|
617 |
|
|
618 |
"""
|
|
619 |
try:
|
|
620 |
ipaddr.IPv4Network(value)
|
|
621 |
except ipaddr.AddressValueError:
|
|
622 |
return False
|
|
623 |
return True
|
|
624 |
|
|
625 |
|
|
626 |
@WithDesc("IPv4 address")
|
|
627 |
def _CheckCIDRAddrNotation(value):
|
|
628 |
"""Ensure a given CIDR notation type is valid.
|
|
629 |
|
|
630 |
"""
|
|
631 |
try:
|
|
632 |
ipaddr.IPv4Address(value)
|
|
633 |
except ipaddr.AddressValueError:
|
|
634 |
return False
|
|
635 |
return True
|
|
636 |
|
|
637 |
|
|
638 |
@WithDesc("IPv6 address")
|
|
639 |
def _CheckCIDR6AddrNotation(value):
|
|
640 |
"""Ensure a given CIDR notation type is valid.
|
|
641 |
|
|
642 |
"""
|
|
643 |
try:
|
|
644 |
ipaddr.IPv6Address(value)
|
|
645 |
except ipaddr.AddressValueError:
|
|
646 |
return False
|
|
647 |
return True
|
|
648 |
|
|
649 |
|
|
650 |
@WithDesc("IPv6 network")
|
|
651 |
def _CheckCIDR6NetNotation(value):
|
|
652 |
"""Ensure a given CIDR notation type is valid.
|
|
653 |
|
|
654 |
"""
|
|
655 |
try:
|
|
656 |
ipaddr.IPv6Network(value)
|
|
657 |
except ipaddr.AddressValueError:
|
|
658 |
return False
|
|
659 |
return True
|
|
660 |
|
|
661 |
|
|
662 |
TIPv4Address = TAnd(TString, _CheckCIDRAddrNotation)
|
|
663 |
TIPv6Address = TAnd(TString, _CheckCIDR6AddrNotation)
|
|
664 |
TIPv4Network = TAnd(TString, _CheckCIDRNetNotation)
|
|
665 |
TIPv6Network = TAnd(TString, _CheckCIDR6NetNotation)
|
|
666 |
|
|
667 |
|
|
668 |
def TObject(val_type):
|
|
669 |
return TDictOf(TAny, val_type)
|
|
670 |
|
|
671 |
|
|
672 |
def TObjectCheck(obj, fields_types):
|
|
673 |
"""Helper to generate type checks for objects.
|
|
674 |
|
|
675 |
@param obj: The object to generate type checks
|
|
676 |
@param fields_types: The fields and their types as a dict
|
|
677 |
@return: A ht type check function
|
|
678 |
|
|
679 |
"""
|
|
680 |
assert set(obj.GetAllSlots()) == set(fields_types.keys()), \
|
|
681 |
"%s != %s" % (set(obj.GetAllSlots()), set(fields_types.keys()))
|
|
682 |
return TStrictDict(True, True, fields_types)
|
|
683 |
|
|
684 |
|
|
685 |
TQueryFieldDef = \
|
|
686 |
TObjectCheck(objects.QueryFieldDefinition, {
|
|
687 |
"name": TNonEmptyString,
|
|
688 |
"title": TNonEmptyString,
|
|
689 |
"kind": TElemOf(constants.QFT_ALL),
|
|
690 |
"doc": TNonEmptyString
|
|
691 |
})
|
|
692 |
|
|
693 |
TQueryRow = \
|
|
694 |
TListOf(TAnd(TIsLength(2),
|
|
695 |
TItems([TElemOf(constants.RS_ALL), TAny])))
|
|
696 |
|
|
697 |
TQueryResult = TListOf(TQueryRow)
|
|
698 |
|
|
699 |
TQueryResponse = \
|
|
700 |
TObjectCheck(objects.QueryResponse, {
|
|
701 |
"fields": TListOf(TQueryFieldDef),
|
|
702 |
"data": TQueryResult
|
|
703 |
})
|
|
704 |
|
|
705 |
TQueryFieldsResponse = \
|
|
706 |
TObjectCheck(objects.QueryFieldsResponse, {
|
|
707 |
"fields": TListOf(TQueryFieldDef)
|
|
708 |
})
|
|
709 |
|
|
710 |
TJobIdListItem = \
|
|
711 |
TAnd(TIsLength(2),
|
|
712 |
TItems([Comment("success")(TBool),
|
|
713 |
Comment("Job ID if successful, error message"
|
|
714 |
" otherwise")(TOr(TString, TJobId))]))
|
|
715 |
|
|
716 |
TJobIdList = TListOf(TJobIdListItem)
|
|
717 |
|
|
718 |
TJobIdListOnly = TStrictDict(True, True, {
|
|
719 |
constants.JOB_IDS_KEY: Comment("List of submitted jobs")(TJobIdList)
|
|
720 |
})
|
|
721 |
|
|
722 |
TInstanceMultiAllocResponse = \
|
|
723 |
TStrictDict(True, True, {
|
|
724 |
constants.JOB_IDS_KEY: Comment("List of submitted jobs")(TJobIdList),
|
|
725 |
ALLOCATABLE_KEY: TListOf(TNonEmptyString),
|
|
726 |
FAILED_KEY: TListOf(TNonEmptyString)
|
|
727 |
})
|