Coverage for nova/objects/fields.py: 99%
806 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-24 11:16 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-04-24 11:16 +0000
1# Copyright 2013 Red Hat, Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
15import os
16import re
18from cursive import signature_utils
19from oslo_serialization import jsonutils
20from oslo_versionedobjects import fields
22from nova import exception
23from nova.i18n import _
24from nova.network import model as network_model
25from nova.virt import arch
28# Import field errors from oslo.versionedobjects
29KeyTypeError = fields.KeyTypeError
30ElementTypeError = fields.ElementTypeError
33# Import fields from oslo.versionedobjects
34BooleanField = fields.BooleanField
35UnspecifiedDefault = fields.UnspecifiedDefault
36IntegerField = fields.IntegerField
37NonNegativeIntegerField = fields.NonNegativeIntegerField
38UUIDField = fields.UUIDField
39FloatField = fields.FloatField
40NonNegativeFloatField = fields.NonNegativeFloatField
41StringField = fields.StringField
42SensitiveStringField = fields.SensitiveStringField
43EnumField = fields.EnumField
44DateTimeField = fields.DateTimeField
45DictOfStringsField = fields.DictOfStringsField
46DictOfNullableStringsField = fields.DictOfNullableStringsField
47DictOfIntegersField = fields.DictOfIntegersField
48ListOfStringsField = fields.ListOfStringsField
49ListOfUUIDField = fields.ListOfUUIDField
50SetOfIntegersField = fields.SetOfIntegersField
51ListOfSetsOfIntegersField = fields.ListOfSetsOfIntegersField
52ListOfDictOfNullableStringsField = fields.ListOfDictOfNullableStringsField
53DictProxyField = fields.DictProxyField
54ObjectField = fields.ObjectField
55ListOfObjectsField = fields.ListOfObjectsField
56VersionPredicateField = fields.VersionPredicateField
57FlexibleBooleanField = fields.FlexibleBooleanField
58DictOfListOfStringsField = fields.DictOfListOfStringsField
59IPAddressField = fields.IPAddressField
60IPV4AddressField = fields.IPV4AddressField
61IPV6AddressField = fields.IPV6AddressField
62IPV4AndV6AddressField = fields.IPV4AndV6AddressField
63IPNetworkField = fields.IPNetworkField
64IPV4NetworkField = fields.IPV4NetworkField
65IPV6NetworkField = fields.IPV6NetworkField
66AutoTypedField = fields.AutoTypedField
67BaseEnumField = fields.BaseEnumField
68MACAddressField = fields.MACAddressField
69ListOfIntegersField = fields.ListOfIntegersField
70PCIAddressField = fields.PCIAddressField
73# NOTE(danms): These are things we need to import for some of our
74# own implementations below, our tests, or other transitional
75# bits of code. These should be removable after we finish our
76# conversion. So do not use these nova fields directly in any new code;
77# instead, use the oslo.versionedobjects fields.
78Enum = fields.Enum
79Field = fields.Field
80FieldType = fields.FieldType
81Set = fields.Set
82Dict = fields.Dict
83List = fields.List
84Object = fields.Object
85IPAddress = fields.IPAddress
86IPV4Address = fields.IPV4Address
87IPV6Address = fields.IPV6Address
88IPNetwork = fields.IPNetwork
89IPV4Network = fields.IPV4Network
90IPV6Network = fields.IPV6Network
93class ResourceClass(fields.StringPattern):
95 PATTERN = r"^[A-Z0-9_]+$"
96 _REGEX = re.compile(PATTERN)
98 @staticmethod
99 def coerce(obj, attr, value):
100 if isinstance(value, str): 100 ↛ 104line 100 didn't jump to line 104 because the condition on line 100 was always true
101 uppered = value.upper()
102 if ResourceClass._REGEX.match(uppered):
103 return uppered
104 raise ValueError(_("Malformed Resource Class %s") % value)
107class ResourceClassField(AutoTypedField):
108 AUTO_TYPE = ResourceClass()
111class SetOfStringsField(AutoTypedField):
112 AUTO_TYPE = Set(fields.String())
115class BaseNovaEnum(Enum):
116 def __init__(self, **kwargs):
117 super(BaseNovaEnum, self).__init__(valid_values=self.__class__.ALL)
120class Architecture(BaseNovaEnum):
121 """Represents CPU architectures.
123 Provides the standard names for all known processor architectures.
124 Many have multiple variants to deal with big-endian vs little-endian
125 modes, as well as 32 vs 64 bit word sizes. These names are chosen to
126 be identical to the architecture names expected by libvirt, so if
127 ever adding new ones then ensure it matches libvirt's expectation.
128 """
130 ALPHA = arch.ALPHA
131 ARMV6 = arch.ARMV6
132 ARMV7 = arch.ARMV7
133 ARMV7B = arch.ARMV7B
135 AARCH64 = arch.AARCH64
136 CRIS = arch.CRIS
137 I686 = arch.I686
138 IA64 = arch.IA64
139 LM32 = arch.LM32
141 M68K = arch.M68K
142 MICROBLAZE = arch.MICROBLAZE
143 MICROBLAZEEL = arch.MICROBLAZEEL
144 MIPS = arch.MIPS
145 MIPSEL = arch.MIPSEL
147 MIPS64 = arch.MIPS64
148 MIPS64EL = arch.MIPS64EL
149 OPENRISC = arch.OPENRISC
150 PARISC = arch.PARISC
151 PARISC64 = arch.PARISC64
153 PPC = arch.PPC
154 PPCLE = arch.PPCLE
155 PPC64 = arch.PPC64
156 PPC64LE = arch.PPC64LE
157 PPCEMB = arch.PPCEMB
159 S390 = arch.S390
160 S390X = arch.S390X
161 SH4 = arch.SH4
162 SH4EB = arch.SH4EB
163 SPARC = arch.SPARC
165 SPARC64 = arch.SPARC64
166 UNICORE32 = arch.UNICORE32
167 X86_64 = arch.X86_64
168 XTENSA = arch.XTENSA
169 XTENSAEB = arch.XTENSAEB
171 ALL = arch.ALL
173 @classmethod
174 def from_host(cls):
175 """Get the architecture of the host OS
177 :returns: the canonicalized host architecture
178 """
180 return cls.canonicalize(os.uname().machine)
182 @classmethod
183 def is_valid(cls, name):
184 """Check if a string is a valid architecture
186 :param name: architecture name to validate
188 :returns: True if @name is valid
189 """
191 return name in cls.ALL
193 @classmethod
194 def canonicalize(cls, name):
195 """Canonicalize the architecture name
197 :param name: architecture name to canonicalize
199 :returns: a canonical architecture name
200 """
202 if name is None:
203 return None
205 newname = name.lower()
207 if newname in ("i386", "i486", "i586"):
208 newname = cls.I686
210 # Xen mistake from Icehouse or earlier
211 if newname in ("x86_32", "x86_32p"):
212 newname = cls.I686
214 if newname == "amd64":
215 newname = cls.X86_64
217 if not cls.is_valid(newname):
218 raise exception.InvalidArchitectureName(arch=name)
220 return newname
222 def coerce(self, obj, attr, value):
223 try:
224 value = self.canonicalize(value)
225 except exception.InvalidArchitectureName:
226 msg = _("Architecture name '%s' is not valid") % value
227 raise ValueError(msg)
228 return super(Architecture, self).coerce(obj, attr, value)
231class BlockDeviceDestinationType(BaseNovaEnum):
232 """Represents possible destination_type values for a BlockDeviceMapping."""
234 LOCAL = 'local'
235 VOLUME = 'volume'
237 ALL = (LOCAL, VOLUME)
240class BlockDeviceSourceType(BaseNovaEnum):
241 """Represents the possible source_type values for a BlockDeviceMapping."""
243 BLANK = 'blank'
244 IMAGE = 'image'
245 SNAPSHOT = 'snapshot'
246 VOLUME = 'volume'
248 ALL = (BLANK, IMAGE, SNAPSHOT, VOLUME)
251class BlockDeviceType(BaseNovaEnum):
252 """Represents possible device_type values for a BlockDeviceMapping."""
254 CDROM = 'cdrom'
255 DISK = 'disk'
256 FLOPPY = 'floppy'
257 FS = 'fs'
258 LUN = 'lun'
260 ALL = (CDROM, DISK, FLOPPY, FS, LUN)
263class BlockDeviceEncryptionFormatType(BaseNovaEnum):
264 PLAIN = 'plain'
265 LUKS = 'luks'
266 LUKSv2 = 'luksv2'
268 ALL = (PLAIN, LUKS, LUKSv2)
271class ConfigDrivePolicy(BaseNovaEnum):
272 OPTIONAL = "optional"
273 MANDATORY = "mandatory"
275 ALL = (OPTIONAL, MANDATORY)
278class CPUAllocationPolicy(BaseNovaEnum):
280 DEDICATED = "dedicated"
281 SHARED = "shared"
282 MIXED = "mixed"
284 ALL = (DEDICATED, SHARED, MIXED)
287class CPUThreadAllocationPolicy(BaseNovaEnum):
289 # prefer (default): The host may or may not have hyperthreads. This
290 # retains the legacy behavior, whereby siblings are preferred when
291 # available. This is the default if no policy is specified.
292 PREFER = "prefer"
293 # isolate: The host may or many not have hyperthreads. If hyperthreads are
294 # present, each vCPU will be placed on a different core and no vCPUs from
295 # other guests will be able to be placed on the same core, i.e. one
296 # thread sibling is guaranteed to always be unused. If hyperthreads are
297 # not present, each vCPU will still be placed on a different core and
298 # there are no thread siblings to be concerned with.
299 ISOLATE = "isolate"
300 # require: The host must have hyperthreads. Each vCPU will be allocated on
301 # thread siblings.
302 REQUIRE = "require"
304 ALL = (PREFER, ISOLATE, REQUIRE)
307class CPUEmulatorThreadsPolicy(BaseNovaEnum):
309 # share (default): Emulator threads float across the pCPUs
310 # associated to the guest.
311 SHARE = "share"
312 # isolate: Emulator threads are isolated on a single pCPU.
313 ISOLATE = "isolate"
315 ALL = (SHARE, ISOLATE)
318class CPUMode(BaseNovaEnum):
320 CUSTOM = 'custom'
321 HOST_MODEL = 'host-model'
322 HOST_PASSTHROUGH = 'host-passthrough'
324 ALL = (CUSTOM, HOST_MODEL, HOST_PASSTHROUGH)
327class CPUMatch(BaseNovaEnum):
329 MINIMUM = 'minimum'
330 EXACT = 'exact'
331 STRICT = 'strict'
333 ALL = (MINIMUM, EXACT, STRICT)
336class CPUFeaturePolicy(BaseNovaEnum):
338 FORCE = 'force'
339 REQUIRE = 'require'
340 OPTIONAL = 'optional'
341 DISABLE = 'disable'
342 FORBID = 'forbid'
344 ALL = (FORCE, REQUIRE, OPTIONAL, DISABLE, FORBID)
347class DiskBus(BaseNovaEnum):
349 # NOTE(aspiers): If you change this, don't forget to update the
350 # docs and metadata for hw_*_bus in glance.
351 # NOTE(lyarwood): Also update the possible values in the api-ref for the
352 # block_device_mapping_v2.disk_bus parameter.
353 FDC = "fdc"
354 IDE = "ide"
355 SATA = "sata"
356 SCSI = "scsi"
357 USB = "usb"
358 VIRTIO = "virtio"
359 XEN = "xen"
360 LXC = "lxc"
361 UML = "uml"
363 ALL = (FDC, IDE, SATA, SCSI, USB, VIRTIO, XEN, LXC, UML)
366class DiskConfig(BaseNovaEnum):
368 MANUAL = "MANUAL"
369 AUTO = "AUTO"
371 ALL = (MANUAL, AUTO)
373 def coerce(self, obj, attr, value):
374 enum_value = DiskConfig.AUTO if value else DiskConfig.MANUAL
375 return super(DiskConfig, self).coerce(obj, attr, enum_value)
378class FirmwareType(BaseNovaEnum):
380 UEFI = "uefi"
381 BIOS = "bios"
383 ALL = (UEFI, BIOS)
386class HVType(BaseNovaEnum):
387 """Represents virtualization types.
389 Provide the standard names for all known guest virtualization
390 types. This is not to be confused with the Nova hypervisor driver
391 types, since one driver may support multiple virtualization types
392 and one virtualization type may be supported by multiple drivers.
393 """
395 BAREMETAL = 'baremetal'
396 BHYVE = 'bhyve'
397 DOCKER = 'docker'
398 FAKE = 'fake'
399 HYPERV = 'hyperv'
400 IRONIC = 'ironic'
401 KQEMU = 'kqemu'
402 KVM = 'kvm'
403 LXC = 'lxc'
404 LXD = 'lxd'
405 OPENVZ = 'openvz'
406 PARALLELS = 'parallels'
407 VIRTUOZZO = 'vz'
408 PHYP = 'phyp'
409 QEMU = 'qemu'
410 TEST = 'test'
411 UML = 'uml'
412 VBOX = 'vbox'
413 VMWARE = 'vmware'
414 XEN = 'xen'
415 ZVM = 'zvm'
416 PRSM = 'prsm'
418 ALL = (BAREMETAL, BHYVE, DOCKER, FAKE, HYPERV, IRONIC, KQEMU, KVM, LXC,
419 LXD, OPENVZ, PARALLELS, PHYP, QEMU, TEST, UML, VBOX, VIRTUOZZO,
420 VMWARE, XEN, ZVM, PRSM)
422 def coerce(self, obj, attr, value):
423 try:
424 value = self.canonicalize(value)
425 except exception.InvalidHypervisorVirtType:
426 msg = _("Hypervisor virt type '%s' is not valid") % value
427 raise ValueError(msg)
429 return super(HVType, self).coerce(obj, attr, value)
431 @classmethod
432 def is_valid(cls, name):
433 """Check if a string is a valid hypervisor type
435 :param name: hypervisor type name to validate
437 :returns: True if @name is valid
438 """
439 return name in cls.ALL
441 @classmethod
442 def canonicalize(cls, name):
443 """Canonicalize the hypervisor type name
445 :param name: hypervisor type name to canonicalize
447 :returns: a canonical hypervisor type name
448 """
449 if name is None:
450 return None
452 newname = name.lower()
454 if newname == 'xapi':
455 newname = cls.XEN
457 if not cls.is_valid(newname):
458 raise exception.InvalidHypervisorVirtType(hv_type=name)
460 return newname
463class ImageSignatureHashType(BaseNovaEnum):
464 # Represents the possible hash methods used for image signing
465 ALL = tuple(sorted(signature_utils.HASH_METHODS.keys()))
468class ImageSignatureKeyType(BaseNovaEnum):
469 # Represents the possible keypair types used for image signing
470 ALL = (
471 'DSA', 'ECC_SECP384R1', 'ECC_SECP521R1', 'ECC_SECT409K1',
472 'ECC_SECT409R1', 'ECC_SECT571K1', 'ECC_SECT571R1', 'RSA-PSS'
473 )
476class InputBus(BaseNovaEnum):
478 USB = 'usb'
479 VIRTIO = 'virtio'
481 ALL = (USB, VIRTIO)
484class MigrationType(BaseNovaEnum):
486 MIGRATION = 'migration' # cold migration
487 RESIZE = 'resize'
488 LIVE_MIGRATION = 'live-migration'
489 EVACUATION = 'evacuation'
491 ALL = (MIGRATION, RESIZE, LIVE_MIGRATION, EVACUATION)
494class OSType(BaseNovaEnum):
496 LINUX = "linux"
497 WINDOWS = "windows"
499 ALL = (LINUX, WINDOWS)
501 def coerce(self, obj, attr, value):
502 # Some code/docs use upper case or initial caps
503 # so canonicalize to all lower case
504 value = value.lower()
505 return super(OSType, self).coerce(obj, attr, value)
508class RNGModel(BaseNovaEnum):
510 # NOTE(kchamart): Along with "virtio", we may need to extend this (if a
511 # good reason shows up) to allow two more values for VirtIO
512 # transitional and non-transitional devices (available since libvirt
513 # 5.2.0):
514 #
515 # - virtio-transitional
516 # - virtio-nontransitional
517 #
518 # This allows one to choose whether you want to have compatibility
519 # with older guest operating systems. The value you select will in
520 # turn decide the kind of PCI topology the guest will get.
521 #
522 # Details:
523 # https://libvirt.org/formatdomain.html#elementsVirtioTransitional
524 VIRTIO = "virtio"
526 ALL = (VIRTIO,)
529class ShareMappingStatus(BaseNovaEnum):
530 """Represents the possible status of a share mapping"""
532 ATTACHING = "attaching"
533 DETACHING = "detaching"
534 ACTIVE = "active"
535 INACTIVE = "inactive"
536 ERROR = "error"
538 ALL = (ATTACHING, DETACHING, ACTIVE, INACTIVE, ERROR)
541class ShareMappingProto(BaseNovaEnum):
542 """Represents the possible protocol used by a share mapping"""
544 NFS = "NFS"
545 CEPHFS = "CEPHFS"
547 ALL = (NFS, CEPHFS)
550class TPMModel(BaseNovaEnum):
552 TIS = "tpm-tis"
553 CRB = "tpm-crb"
555 ALL = (TIS, CRB)
558class TPMVersion(BaseNovaEnum):
559 v1_2 = "1.2"
560 v2_0 = "2.0"
562 ALL = (v1_2, v2_0)
565class MaxPhyAddrMode(BaseNovaEnum):
566 PASSTHROUGH = "passthrough"
567 EMULATE = "emulate"
569 ALL = (PASSTHROUGH, EMULATE)
572class SCSIModel(BaseNovaEnum):
574 BUSLOGIC = "buslogic"
575 IBMVSCSI = "ibmvscsi"
576 LSILOGIC = "lsilogic"
577 LSISAS1068 = "lsisas1068"
578 LSISAS1078 = "lsisas1078"
579 VIRTIO_SCSI = "virtio-scsi"
580 VMPVSCSI = "vmpvscsi"
582 ALL = (BUSLOGIC, IBMVSCSI, LSILOGIC, LSISAS1068,
583 LSISAS1078, VIRTIO_SCSI, VMPVSCSI)
585 def coerce(self, obj, attr, value):
586 # Some compat for strings we'd see in the legacy
587 # vmware_adaptertype image property
588 value = value.lower()
589 if value == "lsilogicsas":
590 value = SCSIModel.LSISAS1068
591 elif value == "paravirtual":
592 value = SCSIModel.VMPVSCSI
594 return super(SCSIModel, self).coerce(obj, attr, value)
597class SecureBoot(BaseNovaEnum):
599 REQUIRED = "required"
600 DISABLED = "disabled"
601 OPTIONAL = "optional"
603 ALL = (REQUIRED, DISABLED, OPTIONAL)
606class VideoModel(BaseNovaEnum):
608 CIRRUS = "cirrus"
609 QXL = "qxl"
610 VGA = "vga"
611 VMVGA = "vmvga"
612 XEN = "xen"
613 VIRTIO = 'virtio'
614 GOP = 'gop'
615 NONE = 'none'
616 BOCHS = 'bochs'
618 ALL = (CIRRUS, QXL, VGA, VMVGA, XEN, VIRTIO, GOP, NONE, BOCHS)
621class VIFModel(BaseNovaEnum):
623 LEGACY_VALUES = {"virtuale1000":
624 network_model.VIF_MODEL_E1000,
625 "virtuale1000e":
626 network_model.VIF_MODEL_E1000E,
627 "virtualpcnet32":
628 network_model.VIF_MODEL_PCNET,
629 "virtualsriovethernetcard":
630 network_model.VIF_MODEL_SRIOV,
631 "virtualvmxnet":
632 network_model.VIF_MODEL_VMXNET,
633 "virtualvmxnet3":
634 network_model.VIF_MODEL_VMXNET3,
635 }
637 ALL = network_model.VIF_MODEL_ALL
639 def coerce(self, obj, attr, value):
640 # Some compat for strings we'd see in the legacy
641 # hw_vif_model image property
642 value = value.lower()
643 value = VIFModel.LEGACY_VALUES.get(value, value)
644 return super(VIFModel, self).coerce(obj, attr, value)
647class VIOMMUModel(BaseNovaEnum):
649 INTEL = 'intel'
650 SMMUV3 = 'smmuv3'
651 VIRTIO = 'virtio'
652 AUTO = 'auto'
654 ALL = (INTEL, SMMUV3, VIRTIO, AUTO)
657class VMMode(BaseNovaEnum):
658 """Represents possible vm modes for instances.
660 Compute instance VM modes represent the host/guest ABI used for the
661 virtual machine or container. Individual hypervisors may support
662 multiple different vm modes per host. Available VM modes for a
663 hypervisor driver may also vary according to the architecture it is
664 running on.
665 """
666 HVM = 'hvm' # Native ABI (aka fully virtualized)
667 XEN = 'xen' # Xen 3.0 paravirtualized
668 UML = 'uml' # User Mode Linux paravirtualized
669 EXE = 'exe' # Executables in containers
671 ALL = (HVM, XEN, UML, EXE)
673 def coerce(self, obj, attr, value):
674 try:
675 value = self.canonicalize(value)
676 except exception.InvalidVirtualMachineMode:
677 msg = _("Virtual machine mode '%s' is not valid") % value
678 raise ValueError(msg)
680 return super(VMMode, self).coerce(obj, attr, value)
682 @classmethod
683 def get_from_instance(cls, instance):
684 """Get the vm mode for an instance
686 :param instance: instance object to query
688 :returns: canonicalized vm mode for the instance
689 """
690 mode = instance.vm_mode
692 return cls.canonicalize(mode)
694 @classmethod
695 def is_valid(cls, name):
696 """Check if a string is a valid vm mode
698 :param name: vm mode name to validate
700 :returns: True if @name is valid
701 """
702 return name in cls.ALL
704 @classmethod
705 def canonicalize(cls, mode):
706 """Canonicalize the vm mode
708 :param name: vm mode name to canonicalize
710 :returns: a canonical vm mode name
711 """
712 if mode is None:
713 return None
715 mode = mode.lower()
717 # For compatibility with pre-Folsom deployments
718 if mode == 'pv':
719 mode = cls.XEN
721 if mode == 'hv':
722 mode = cls.HVM
724 if mode == 'baremetal':
725 mode = cls.HVM
727 if not cls.is_valid(mode):
728 raise exception.InvalidVirtualMachineMode(vmmode=mode)
730 return mode
733class WatchdogAction(BaseNovaEnum):
735 NONE = "none"
736 PAUSE = "pause"
737 POWEROFF = "poweroff"
738 RESET = "reset"
739 DISABLED = "disabled"
741 ALL = (NONE, PAUSE, POWEROFF, RESET, DISABLED)
744class MonitorMetricType(BaseNovaEnum):
746 CPU_FREQUENCY = "cpu.frequency"
747 CPU_USER_TIME = "cpu.user.time"
748 CPU_KERNEL_TIME = "cpu.kernel.time"
749 CPU_IDLE_TIME = "cpu.idle.time"
750 CPU_IOWAIT_TIME = "cpu.iowait.time"
751 CPU_USER_PERCENT = "cpu.user.percent"
752 CPU_KERNEL_PERCENT = "cpu.kernel.percent"
753 CPU_IDLE_PERCENT = "cpu.idle.percent"
754 CPU_IOWAIT_PERCENT = "cpu.iowait.percent"
755 CPU_PERCENT = "cpu.percent"
756 NUMA_MEM_BW_MAX = "numa.membw.max"
757 NUMA_MEM_BW_CURRENT = "numa.membw.current"
759 ALL = (
760 CPU_FREQUENCY,
761 CPU_USER_TIME,
762 CPU_KERNEL_TIME,
763 CPU_IDLE_TIME,
764 CPU_IOWAIT_TIME,
765 CPU_USER_PERCENT,
766 CPU_KERNEL_PERCENT,
767 CPU_IDLE_PERCENT,
768 CPU_IOWAIT_PERCENT,
769 CPU_PERCENT,
770 NUMA_MEM_BW_MAX,
771 NUMA_MEM_BW_CURRENT,
772 )
775class HostStatus(BaseNovaEnum):
777 UP = "UP" # The nova-compute is up.
778 DOWN = "DOWN" # The nova-compute is forced_down.
779 MAINTENANCE = "MAINTENANCE" # The nova-compute is disabled.
780 UNKNOWN = "UNKNOWN" # The nova-compute has not reported.
781 NONE = "" # No host or nova-compute.
783 ALL = (UP, DOWN, MAINTENANCE, UNKNOWN, NONE)
786class PciDeviceStatus(BaseNovaEnum):
788 AVAILABLE = "available"
789 CLAIMED = "claimed"
790 ALLOCATED = "allocated"
791 REMOVED = "removed" # The device has been hot-removed and not yet deleted
792 DELETED = "deleted" # The device is marked not available/deleted.
793 UNCLAIMABLE = "unclaimable"
794 UNAVAILABLE = "unavailable"
796 ALL = (AVAILABLE, CLAIMED, ALLOCATED, REMOVED, DELETED, UNAVAILABLE,
797 UNCLAIMABLE)
800class PciDeviceType(BaseNovaEnum):
802 # NOTE(jaypipes): It's silly that the word "type-" is in these constants,
803 # but alas, these were the original constant strings used...
804 STANDARD = "type-PCI"
805 SRIOV_PF = "type-PF"
806 SRIOV_VF = "type-VF"
807 # NOTE(sean-k-mooney): The DB field is Column(String(8), nullable=False)
808 # type-vdpa is 9 long...and as Jay notes above the prefix is silly so
809 # for the new vdpa value we drop the prefix to avoid a DB migration
810 VDPA = "vdpa"
812 ALL = (STANDARD, SRIOV_PF, SRIOV_VF, VDPA)
815class PCINUMAAffinityPolicy(BaseNovaEnum):
817 REQUIRED = "required"
818 LEGACY = "legacy"
819 PREFERRED = "preferred"
820 SOCKET = "socket"
822 ALL = (REQUIRED, LEGACY, PREFERRED, SOCKET)
825class DiskFormat(BaseNovaEnum):
826 RBD = "rbd"
827 LVM = "lvm"
828 QCOW2 = "qcow2"
829 RAW = "raw"
830 PLOOP = "ploop"
831 VHD = "vhd"
832 VMDK = "vmdk"
833 VDI = "vdi"
834 ISO = "iso"
836 ALL = (RBD, LVM, QCOW2, RAW, PLOOP, VHD, VMDK, VDI, ISO)
839# TODO(stephenfin): Remove the xenapi and hyperv value when we bump the
840# 'Diagnostics' object (the only user of this enum) to 2.0
841class HypervisorDriver(BaseNovaEnum):
842 LIBVIRT = "libvirt"
843 XENAPI = "xenapi"
844 VMWAREAPI = "vmwareapi"
845 IRONIC = "ironic"
846 HYPERV = "hyperv"
848 ALL = (LIBVIRT, XENAPI, VMWAREAPI, IRONIC, HYPERV)
851class PointerModelType(BaseNovaEnum):
853 USBTABLET = "usbtablet"
855 ALL = (USBTABLET,)
858class NotificationPriority(BaseNovaEnum):
859 AUDIT = 'audit'
860 CRITICAL = 'critical'
861 DEBUG = 'debug'
862 INFO = 'info'
863 ERROR = 'error'
864 SAMPLE = 'sample'
865 WARN = 'warn'
867 ALL = (AUDIT, CRITICAL, DEBUG, INFO, ERROR, SAMPLE, WARN)
870class NotificationPhase(BaseNovaEnum):
871 START = 'start'
872 END = 'end'
873 ERROR = 'error'
874 PROGRESS = 'progress'
876 ALL = (START, END, ERROR, PROGRESS)
879class NotificationSource(BaseNovaEnum):
880 """Represents possible nova binary service names in notification envelope.
882 The publisher_id field of the nova notifications consists of the name of
883 the host and the name of the service binary that emits the notification.
884 The below values are the ones that is used in every notification. Please
885 note that on the REST API the nova-api service binary is called
886 nova-osapi_compute. This is not reflected here as notifications always used
887 the name nova-api instead.
888 """
890 COMPUTE = 'nova-compute'
891 API = 'nova-api'
892 CONDUCTOR = 'nova-conductor'
893 SCHEDULER = 'nova-scheduler'
894 # TODO(stephenfin): Remove 'NETWORK' when 'NotificationPublisher' is
895 # updated to version 3.0
896 NETWORK = 'nova-network'
897 # TODO(stephenfin): Remove 'CONSOLEAUTH' when 'NotificationPublisher' is
898 # updated to version 3.0
899 CONSOLEAUTH = 'nova-consoleauth'
900 # TODO(stephenfin): Remove when 'NotificationPublisher' object version is
901 # bumped to 3.0
902 CELLS = 'nova-cells'
903 # TODO(stephenfin): Remove when 'NotificationPublisher' object version is
904 # bumped to 3.0
905 CONSOLE = 'nova-console'
906 METADATA = 'nova-metadata'
908 ALL = (API, COMPUTE, CONDUCTOR, SCHEDULER,
909 NETWORK, CONSOLEAUTH, CELLS, CONSOLE, METADATA)
911 @staticmethod
912 def get_source_by_binary(binary):
913 # nova-osapi_compute binary name needs to be translated to nova-api
914 # notification source enum value.
915 return "nova-api" if binary == "nova-osapi_compute" else binary
918class NotificationAction(BaseNovaEnum):
919 UPDATE = 'update'
920 EXCEPTION = 'exception'
921 DELETE = 'delete'
922 PAUSE = 'pause'
923 UNPAUSE = 'unpause'
924 RESIZE = 'resize'
925 VOLUME_SWAP = 'volume_swap'
926 SUSPEND = 'suspend'
927 POWER_ON = 'power_on'
928 POWER_OFF = 'power_off'
929 REBOOT = 'reboot'
930 SHUTDOWN = 'shutdown'
931 SNAPSHOT = 'snapshot'
932 INTERFACE_ATTACH = 'interface_attach'
933 SHELVE = 'shelve'
934 RESUME = 'resume'
935 RESTORE = 'restore'
936 EXISTS = 'exists'
937 RESCUE = 'rescue'
938 VOLUME_ATTACH = 'volume_attach'
939 VOLUME_DETACH = 'volume_detach'
940 SHARE_ATTACH = 'share_attach'
941 SHARE_DETACH = 'share_detach'
942 CREATE = 'create'
943 IMPORT = 'import'
944 EVACUATE = 'evacuate'
945 RESIZE_FINISH = 'resize_finish'
946 LIVE_MIGRATION_ABORT = 'live_migration_abort'
947 LIVE_MIGRATION_POST_DEST = 'live_migration_post_dest'
948 LIVE_MIGRATION_POST = 'live_migration_post'
949 LIVE_MIGRATION_PRE = 'live_migration_pre'
950 LIVE_MIGRATION_ROLLBACK_DEST = 'live_migration_rollback_dest'
951 LIVE_MIGRATION_ROLLBACK = 'live_migration_rollback'
952 LIVE_MIGRATION_FORCE_COMPLETE = 'live_migration_force_complete'
953 REBUILD = 'rebuild'
954 REBUILD_SCHEDULED = 'rebuild_scheduled'
955 INTERFACE_DETACH = 'interface_detach'
956 RESIZE_CONFIRM = 'resize_confirm'
957 RESIZE_PREP = 'resize_prep'
958 RESIZE_REVERT = 'resize_revert'
959 SELECT_DESTINATIONS = 'select_destinations'
960 SHELVE_OFFLOAD = 'shelve_offload'
961 SOFT_DELETE = 'soft_delete'
962 TRIGGER_CRASH_DUMP = 'trigger_crash_dump'
963 UNRESCUE = 'unrescue'
964 UNSHELVE = 'unshelve'
965 ADD_HOST = 'add_host'
966 REMOVE_HOST = 'remove_host'
967 ADD_MEMBER = 'add_member'
968 UPDATE_METADATA = 'update_metadata'
969 LOCK = 'lock'
970 UNLOCK = 'unlock'
971 UPDATE_PROP = 'update_prop'
972 CONNECT = 'connect'
973 USAGE = 'usage'
974 BUILD_INSTANCES = 'build_instances'
975 MIGRATE_SERVER = 'migrate_server'
976 REBUILD_SERVER = 'rebuild_server'
977 IMAGE_CACHE = 'cache_images'
979 ALL = (UPDATE, EXCEPTION, DELETE, PAUSE, UNPAUSE, RESIZE, VOLUME_SWAP,
980 SUSPEND, POWER_ON, REBOOT, SHUTDOWN, SNAPSHOT, INTERFACE_ATTACH,
981 POWER_OFF, SHELVE, RESUME, RESTORE, EXISTS, RESCUE, VOLUME_ATTACH,
982 VOLUME_DETACH, SHARE_ATTACH, SHARE_DETACH, CREATE, IMPORT, EVACUATE,
983 RESIZE_FINISH, LIVE_MIGRATION_ABORT, LIVE_MIGRATION_POST_DEST,
984 LIVE_MIGRATION_POST, LIVE_MIGRATION_PRE, LIVE_MIGRATION_ROLLBACK,
985 LIVE_MIGRATION_ROLLBACK_DEST, REBUILD, INTERFACE_DETACH,
986 RESIZE_CONFIRM, RESIZE_PREP, RESIZE_REVERT, SHELVE_OFFLOAD,
987 SOFT_DELETE, TRIGGER_CRASH_DUMP, UNRESCUE, UNSHELVE, ADD_HOST,
988 REMOVE_HOST, ADD_MEMBER, UPDATE_METADATA, LOCK, UNLOCK,
989 REBUILD_SCHEDULED, UPDATE_PROP, LIVE_MIGRATION_FORCE_COMPLETE,
990 CONNECT, USAGE, BUILD_INSTANCES, MIGRATE_SERVER, REBUILD_SERVER,
991 SELECT_DESTINATIONS, IMAGE_CACHE)
994# TODO(rlrossit): These should be changed over to be a StateMachine enum from
995# oslo.versionedobjects using the valid state transitions described in
996# nova.compute.vm_states
997class InstanceState(BaseNovaEnum):
998 ACTIVE = 'active'
999 BUILDING = 'building'
1000 PAUSED = 'paused'
1001 SUSPENDED = 'suspended'
1002 STOPPED = 'stopped'
1003 RESCUED = 'rescued'
1004 RESIZED = 'resized'
1005 SOFT_DELETED = 'soft-delete'
1006 DELETED = 'deleted'
1007 ERROR = 'error'
1008 SHELVED = 'shelved'
1009 SHELVED_OFFLOADED = 'shelved_offloaded'
1011 ALL = (ACTIVE, BUILDING, PAUSED, SUSPENDED, STOPPED, RESCUED, RESIZED,
1012 SOFT_DELETED, DELETED, ERROR, SHELVED, SHELVED_OFFLOADED)
1015# TODO(rlrossit): These should be changed over to be a StateMachine enum from
1016# oslo.versionedobjects using the valid state transitions described in
1017# nova.compute.task_states
1018class InstanceTaskState(BaseNovaEnum):
1019 SCHEDULING = 'scheduling'
1020 BLOCK_DEVICE_MAPPING = 'block_device_mapping'
1021 NETWORKING = 'networking'
1022 SPAWNING = 'spawning'
1023 IMAGE_SNAPSHOT = 'image_snapshot'
1024 IMAGE_SNAPSHOT_PENDING = 'image_snapshot_pending'
1025 IMAGE_PENDING_UPLOAD = 'image_pending_upload'
1026 IMAGE_UPLOADING = 'image_uploading'
1027 IMAGE_BACKUP = 'image_backup'
1028 UPDATING_PASSWORD = 'updating_password'
1029 RESIZE_PREP = 'resize_prep'
1030 RESIZE_MIGRATING = 'resize_migrating'
1031 RESIZE_MIGRATED = 'resize_migrated'
1032 RESIZE_FINISH = 'resize_finish'
1033 RESIZE_REVERTING = 'resize_reverting'
1034 RESIZE_CONFIRMING = 'resize_confirming'
1035 REBOOTING = 'rebooting'
1036 REBOOT_PENDING = 'reboot_pending'
1037 REBOOT_STARTED = 'reboot_started'
1038 REBOOTING_HARD = 'rebooting_hard'
1039 REBOOT_PENDING_HARD = 'reboot_pending_hard'
1040 REBOOT_STARTED_HARD = 'reboot_started_hard'
1041 PAUSING = 'pausing'
1042 UNPAUSING = 'unpausing'
1043 SUSPENDING = 'suspending'
1044 RESUMING = 'resuming'
1045 POWERING_OFF = 'powering-off'
1046 POWERING_ON = 'powering-on'
1047 RESCUING = 'rescuing'
1048 UNRESCUING = 'unrescuing'
1049 REBUILDING = 'rebuilding'
1050 REBUILD_BLOCK_DEVICE_MAPPING = "rebuild_block_device_mapping"
1051 REBUILD_SPAWNING = 'rebuild_spawning'
1052 MIGRATING = "migrating"
1053 DELETING = 'deleting'
1054 SOFT_DELETING = 'soft-deleting'
1055 RESTORING = 'restoring'
1056 SHELVING = 'shelving'
1057 SHELVING_IMAGE_PENDING_UPLOAD = 'shelving_image_pending_upload'
1058 SHELVING_IMAGE_UPLOADING = 'shelving_image_uploading'
1059 SHELVING_OFFLOADING = 'shelving_offloading'
1060 UNSHELVING = 'unshelving'
1062 ALL = (SCHEDULING, BLOCK_DEVICE_MAPPING, NETWORKING, SPAWNING,
1063 IMAGE_SNAPSHOT, IMAGE_SNAPSHOT_PENDING, IMAGE_PENDING_UPLOAD,
1064 IMAGE_UPLOADING, IMAGE_BACKUP, UPDATING_PASSWORD, RESIZE_PREP,
1065 RESIZE_MIGRATING, RESIZE_MIGRATED, RESIZE_FINISH, RESIZE_REVERTING,
1066 RESIZE_CONFIRMING, REBOOTING, REBOOT_PENDING, REBOOT_STARTED,
1067 REBOOTING_HARD, REBOOT_PENDING_HARD, REBOOT_STARTED_HARD, PAUSING,
1068 UNPAUSING, SUSPENDING, RESUMING, POWERING_OFF, POWERING_ON,
1069 RESCUING, UNRESCUING, REBUILDING, REBUILD_BLOCK_DEVICE_MAPPING,
1070 REBUILD_SPAWNING, MIGRATING, DELETING, SOFT_DELETING, RESTORING,
1071 SHELVING, SHELVING_IMAGE_PENDING_UPLOAD, SHELVING_IMAGE_UPLOADING,
1072 SHELVING_OFFLOADING, UNSHELVING)
1075class InstancePowerState(Enum):
1076 _UNUSED = '_unused'
1077 NOSTATE = 'pending'
1078 RUNNING = 'running'
1079 PAUSED = 'paused'
1080 SHUTDOWN = 'shutdown'
1081 CRASHED = 'crashed'
1082 SUSPENDED = 'suspended'
1083 # The order is important here. If you make changes, only *append*
1084 # values to the end of the list.
1085 ALL = (
1086 NOSTATE,
1087 RUNNING,
1088 _UNUSED,
1089 PAUSED,
1090 SHUTDOWN,
1091 _UNUSED,
1092 CRASHED,
1093 SUSPENDED,
1094 )
1096 def __init__(self):
1097 super(InstancePowerState, self).__init__(
1098 valid_values=InstancePowerState.ALL)
1100 def coerce(self, obj, attr, value):
1101 try:
1102 value = int(value)
1103 value = self.from_index(value)
1104 except (ValueError, KeyError):
1105 pass
1106 return super(InstancePowerState, self).coerce(obj, attr, value)
1108 @classmethod
1109 def index(cls, value):
1110 """Return an index into the Enum given a value."""
1111 return cls.ALL.index(value)
1113 @classmethod
1114 def from_index(cls, index):
1115 """Return the Enum value at a given index."""
1116 return cls.ALL[index]
1119class NetworkModel(FieldType):
1120 @staticmethod
1121 def coerce(obj, attr, value):
1122 if isinstance(value, network_model.NetworkInfo):
1123 return value
1124 elif isinstance(value, str):
1125 # Hmm, do we need this?
1126 return network_model.NetworkInfo.hydrate(value)
1127 else:
1128 raise ValueError(_('A NetworkModel is required in field %s') %
1129 attr)
1131 @staticmethod
1132 def to_primitive(obj, attr, value):
1133 return value.json()
1135 @staticmethod
1136 def from_primitive(obj, attr, value):
1137 return network_model.NetworkInfo.hydrate(value)
1139 def stringify(self, value):
1140 return 'NetworkModel(%s)' % (
1141 ','.join([str(vif['id']) for vif in value]))
1143 def get_schema(self):
1144 return {'type': ['string']}
1147class NetworkVIFModel(FieldType):
1148 """Represents a nova.network.model.VIF object, which is a dict of stuff."""
1150 @staticmethod
1151 def coerce(obj, attr, value):
1152 if isinstance(value, network_model.VIF):
1153 return value
1154 elif isinstance(value, str):
1155 return NetworkVIFModel.from_primitive(obj, attr, value)
1156 else:
1157 raise ValueError(_('A nova.network.model.VIF object is required '
1158 'in field %s') % attr)
1160 @staticmethod
1161 def to_primitive(obj, attr, value):
1162 return jsonutils.dumps(value)
1164 @staticmethod
1165 def from_primitive(obj, attr, value):
1166 return network_model.VIF.hydrate(jsonutils.loads(value))
1168 def get_schema(self):
1169 return {'type': ['string']}
1172class AddressBase(FieldType):
1173 @staticmethod
1174 def coerce(obj, attr, value):
1175 if re.match(obj.PATTERN, str(value)):
1176 return str(value)
1177 else:
1178 raise ValueError(_('Value must match %s') % obj.PATTERN)
1180 def get_schema(self):
1181 return {'type': ['string'], 'pattern': self.PATTERN}
1184class USBAddress(AddressBase):
1185 PATTERN = '[a-f0-9]+:[a-f0-9]+'
1187 @staticmethod
1188 def coerce(obj, attr, value):
1189 return AddressBase.coerce(USBAddress, attr, value)
1192class SCSIAddress(AddressBase):
1193 PATTERN = '[a-f0-9]+:[a-f0-9]+:[a-f0-9]+:[a-f0-9]+'
1195 @staticmethod
1196 def coerce(obj, attr, value):
1197 return AddressBase.coerce(SCSIAddress, attr, value)
1200class IDEAddress(AddressBase):
1201 PATTERN = '[0-1]:[0-1]'
1203 @staticmethod
1204 def coerce(obj, attr, value):
1205 return AddressBase.coerce(IDEAddress, attr, value)
1208class XenAddress(AddressBase):
1209 PATTERN = '(00[0-9]{2}00)|[1-9][0-9]+'
1211 @staticmethod
1212 def coerce(obj, attr, value):
1213 return AddressBase.coerce(XenAddress, attr, value)
1216class USBAddressField(AutoTypedField):
1217 AUTO_TYPE = USBAddress()
1220class SCSIAddressField(AutoTypedField):
1221 AUTO_TYPE = SCSIAddress()
1224class IDEAddressField(AutoTypedField):
1225 AUTO_TYPE = IDEAddress()
1228class XenAddressField(AutoTypedField):
1229 AUTO_TYPE = XenAddress()
1232class ArchitectureField(BaseEnumField):
1233 AUTO_TYPE = Architecture()
1236class BlockDeviceDestinationTypeField(BaseEnumField):
1237 AUTO_TYPE = BlockDeviceDestinationType()
1240class BlockDeviceSourceTypeField(BaseEnumField):
1241 AUTO_TYPE = BlockDeviceSourceType()
1244class BlockDeviceTypeField(BaseEnumField):
1245 AUTO_TYPE = BlockDeviceType()
1248class BlockDeviceEncryptionFormatTypeField(BaseEnumField):
1249 AUTO_TYPE = BlockDeviceEncryptionFormatType()
1252class ConfigDrivePolicyField(BaseEnumField):
1253 AUTO_TYPE = ConfigDrivePolicy()
1256class CPUAllocationPolicyField(BaseEnumField):
1257 AUTO_TYPE = CPUAllocationPolicy()
1260class CPUThreadAllocationPolicyField(BaseEnumField):
1261 AUTO_TYPE = CPUThreadAllocationPolicy()
1264class CPUEmulatorThreadsPolicyField(BaseEnumField):
1265 AUTO_TYPE = CPUEmulatorThreadsPolicy()
1268class CPUModeField(BaseEnumField):
1269 AUTO_TYPE = CPUMode()
1272class CPUMatchField(BaseEnumField):
1273 AUTO_TYPE = CPUMatch()
1276class CPUFeaturePolicyField(BaseEnumField):
1277 AUTO_TYPE = CPUFeaturePolicy()
1280class DiskBusField(BaseEnumField):
1281 AUTO_TYPE = DiskBus()
1284class DiskConfigField(BaseEnumField):
1285 AUTO_TYPE = DiskConfig()
1288class FirmwareTypeField(BaseEnumField):
1289 AUTO_TYPE = FirmwareType()
1292class HVTypeField(BaseEnumField):
1293 AUTO_TYPE = HVType()
1296class ImageSignatureHashTypeField(BaseEnumField):
1297 AUTO_TYPE = ImageSignatureHashType()
1300class ImageSignatureKeyTypeField(BaseEnumField):
1301 AUTO_TYPE = ImageSignatureKeyType()
1304class InputBusField(BaseEnumField):
1305 AUTO_TYPE = InputBus()
1308class MaxPhysAddrModeField(BaseEnumField):
1309 AUTO_TYPE = MaxPhyAddrMode()
1312class MigrationTypeField(BaseEnumField):
1313 AUTO_TYPE = MigrationType()
1316class OSTypeField(BaseEnumField):
1317 AUTO_TYPE = OSType()
1320class RNGModelField(BaseEnumField):
1321 AUTO_TYPE = RNGModel()
1324class ShareMappingStatusField(BaseEnumField):
1325 AUTO_TYPE = ShareMappingStatus()
1328class ShareMappingProtoField(BaseEnumField):
1329 AUTO_TYPE = ShareMappingProto()
1332class TPMModelField(BaseEnumField):
1333 AUTO_TYPE = TPMModel()
1336class TPMVersionField(BaseEnumField):
1337 AUTO_TYPE = TPMVersion()
1340class SCSIModelField(BaseEnumField):
1341 AUTO_TYPE = SCSIModel()
1344class SecureBootField(BaseEnumField):
1345 AUTO_TYPE = SecureBoot()
1348class VideoModelField(BaseEnumField):
1349 AUTO_TYPE = VideoModel()
1352class VIFModelField(BaseEnumField):
1353 AUTO_TYPE = VIFModel()
1356class VIOMMUModelField(BaseEnumField):
1357 AUTO_TYPE = VIOMMUModel()
1360class VMModeField(BaseEnumField):
1361 AUTO_TYPE = VMMode()
1364class WatchdogActionField(BaseEnumField):
1365 AUTO_TYPE = WatchdogAction()
1368class MonitorMetricTypeField(BaseEnumField):
1369 AUTO_TYPE = MonitorMetricType()
1372class PciDeviceStatusField(BaseEnumField):
1373 AUTO_TYPE = PciDeviceStatus()
1376class PciDeviceTypeField(BaseEnumField):
1377 AUTO_TYPE = PciDeviceType()
1380class PCINUMAAffinityPolicyField(BaseEnumField):
1381 AUTO_TYPE = PCINUMAAffinityPolicy()
1384class DiskFormatField(BaseEnumField):
1385 AUTO_TYPE = DiskFormat()
1388class HypervisorDriverField(BaseEnumField):
1389 AUTO_TYPE = HypervisorDriver()
1392class PointerModelField(BaseEnumField):
1393 AUTO_TYPE = PointerModelType()
1396class NotificationPriorityField(BaseEnumField):
1397 AUTO_TYPE = NotificationPriority()
1400class NotificationPhaseField(BaseEnumField):
1401 AUTO_TYPE = NotificationPhase()
1404class NotificationActionField(BaseEnumField):
1405 AUTO_TYPE = NotificationAction()
1408class NotificationSourceField(BaseEnumField):
1409 AUTO_TYPE = NotificationSource()
1412class InstanceStateField(BaseEnumField):
1413 AUTO_TYPE = InstanceState()
1416class InstanceTaskStateField(BaseEnumField):
1417 AUTO_TYPE = InstanceTaskState()
1420class InstancePowerStateField(BaseEnumField):
1421 AUTO_TYPE = InstancePowerState()
1424class NetworkModelField(AutoTypedField):
1425 AUTO_TYPE = NetworkModel()
1428class NetworkVIFModelField(AutoTypedField):
1429 AUTO_TYPE = NetworkVIFModel()
1432class ListOfListsOfStringsField(AutoTypedField):
1433 AUTO_TYPE = List(List(fields.String()))
1436class DictOfSetOfIntegersField(AutoTypedField):
1437 AUTO_TYPE = Dict(Set(fields.Integer()))