# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import collections
from lxml import etree
from oslo_utils import units
from nova.objects.fields import Architecture
from nova.virt.libvirt import config
def fake_kvm_guest():
obj = config.LibvirtConfigGuest()
obj.virt_type = "kvm"
obj.memory = 100 * units.Mi
obj.vcpus = 2
obj.cpuset = set([0, 1, 3, 4, 5])
obj.cputune = config.LibvirtConfigGuestCPUTune()
obj.cputune.shares = 100
obj.cputune.quota = 50000
obj.cputune.period = 25000
obj.membacking = config.LibvirtConfigGuestMemoryBacking()
page1 = config.LibvirtConfigGuestMemoryBackingPage()
page1.size_kb = 2048
page1.nodeset = [0, 1, 2, 3, 5]
page2 = config.LibvirtConfigGuestMemoryBackingPage()
page2.size_kb = 1048576
page2.nodeset = [4]
obj.membacking.hugepages.append(page1)
obj.membacking.hugepages.append(page2)
obj.memtune = config.LibvirtConfigGuestMemoryTune()
obj.memtune.hard_limit = 496
obj.memtune.soft_limit = 672
obj.memtune.swap_hard_limit = 1638
obj.memtune.min_guarantee = 2970
obj.numatune = config.LibvirtConfigGuestNUMATune()
numamemory = config.LibvirtConfigGuestNUMATuneMemory()
numamemory.mode = "preferred"
numamemory.nodeset = [0, 1, 2, 3, 8]
obj.numatune.memory = numamemory
numamemnode0 = config.LibvirtConfigGuestNUMATuneMemNode()
numamemnode0.cellid = 0
numamemnode0.mode = "preferred"
numamemnode0.nodeset = [0, 1]
numamemnode1 = config.LibvirtConfigGuestNUMATuneMemNode()
numamemnode1.cellid = 1
numamemnode1.mode = "preferred"
numamemnode1.nodeset = [2, 3]
numamemnode2 = config.LibvirtConfigGuestNUMATuneMemNode()
numamemnode2.cellid = 2
numamemnode2.mode = "preferred"
numamemnode2.nodeset = [8]
obj.numatune.memnodes.extend([numamemnode0,
numamemnode1,
numamemnode2])
obj.name = "demo"
obj.uuid = "b38a3f43-4be2-4046-897f-b67c2f5e0147"
obj.os_type = "linux"
obj.os_boot_dev = ["hd", "cdrom", "fd"]
obj.os_smbios = config.LibvirtConfigGuestSMBIOS()
obj.features = [
config.LibvirtConfigGuestFeatureACPI(),
config.LibvirtConfigGuestFeatureAPIC(),
config.LibvirtConfigGuestFeatureKvmHidden()
]
obj.sysinfo = config.LibvirtConfigGuestSysinfo()
obj.sysinfo.bios_vendor = "Acme"
obj.sysinfo.system_version = "1.0.0"
# obj.devices[0]
disk = config.LibvirtConfigGuestDisk()
disk.source_type = "file"
disk.source_path = "/tmp/disk-img"
disk.target_dev = "vda"
disk.target_bus = "virtio"
obj.add_device(disk)
# obj.devices[1]
disk = config.LibvirtConfigGuestDisk()
disk.source_device = "cdrom"
disk.source_type = "file"
disk.source_path = "/tmp/cdrom-img"
disk.target_dev = "sda"
disk.target_bus = "sata"
obj.add_device(disk)
# obj.devices[2]
intf = config.LibvirtConfigGuestInterface()
intf.net_type = "network"
intf.mac_addr = "52:54:00:f6:35:8f"
intf.model = "virtio"
intf.source_dev = "virbr0"
obj.add_device(intf)
# obj.devices[3]
balloon = config.LibvirtConfigMemoryBalloon()
balloon.model = 'virtio'
balloon.period = 11
obj.add_device(balloon)
# obj.devices[4]
mouse = config.LibvirtConfigGuestInput()
mouse.type = "mouse"
mouse.bus = "virtio"
obj.add_device(mouse)
# obj.devices[5]
gfx = config.LibvirtConfigGuestGraphics()
gfx.type = "vnc"
gfx.autoport = True
gfx.keymap = "en_US"
gfx.listen = "127.0.0.1"
obj.add_device(gfx)
# obj.devices[6]
video = config.LibvirtConfigGuestVideo()
video.type = 'virtio'
obj.add_device(video)
# obj.devices[7]
serial = config.LibvirtConfigGuestSerial()
serial.type = "file"
serial.source_path = "/tmp/vm.log"
obj.add_device(serial)
# obj.devices[8]
rng = config.LibvirtConfigGuestRng()
rng.backend = '/dev/urandom'
rng.rate_period = '12'
rng.rate_bytes = '34'
obj.add_device(rng)
# obj.devices[9]
controller = config.LibvirtConfigGuestController()
controller.type = 'scsi'
controller.model = 'virtio-scsi' # usually set from image meta
controller.index = 0
obj.add_device(controller)
return obj
FAKE_KVM_GUEST = """
b38a3f43-4be2-4046-897f-b67c2f5e0147
demo
104857600
496
672
1638
2970
2
Acme
1.0.0
linux
100
50000
25000
/dev/urandom
0x0033
47
1
"""
CAPABILITIES_HOST_X86_64_TEMPLATE = """
cef19ce0-0ca2-11df-855d-b19fbce37686
x86_64
Penryn
Intel
tcp
%(topology)s
apparmor
0
"""
# NOTE(stephenfin): This is incomplete
CAPABILITIES_HOST_I686_TEMPLATE = """
cef19ce0-0ca2-11df-855d-b19fbce37686
i686
"""
CAPABILITIES_HOST_AARCH64_TEMPLATE = """
cef19ce0-0ca2-11df-855d-b19fbce37686
aarch64
host
tcp
rdma
%(topology)s
apparmor
0
dac
0
+0:+0
+0:+0
"""
# NOTE(stephenfin): This is incomplete
CAPABILITIES_HOST_ARMV7_TEMPLATE = """
armv7l
"""
# NOTE(stephenfin): This is incomplete
CAPABILITIES_HOST_PPC_TEMPLATE = """
cef19ce0-0ca2-11df-855d-b19fbce37686
ppc
"""
# NOTE(stephenfin): This is incomplete
CAPABILITIES_HOST_PPC64_TEMPLATE = """
cef19ce0-0ca2-11df-855d-b19fbce37686
ppc64
"""
# NOTE(stephenfin): This is incomplete
CAPABILITIES_HOST_PPC64LE_TEMPLATE = """
cef19ce0-0ca2-11df-855d-b19fbce37686
ppc64le
"""
# NOTE(stephenfin): This is incomplete
CAPABILITIES_HOST_S390X_TEMPLATE = """
cef19ce0-0ca2-11df-855d-b19fbce37686
s390x
"""
CAPABILITIES_HOST_TEMPLATES = {
Architecture.X86_64: CAPABILITIES_HOST_X86_64_TEMPLATE,
Architecture.I686: CAPABILITIES_HOST_I686_TEMPLATE,
Architecture.AARCH64: CAPABILITIES_HOST_AARCH64_TEMPLATE,
Architecture.ARMV7: CAPABILITIES_HOST_ARMV7_TEMPLATE,
Architecture.PPC: CAPABILITIES_HOST_PPC_TEMPLATE,
Architecture.PPC64: CAPABILITIES_HOST_PPC64_TEMPLATE,
Architecture.PPC64LE: CAPABILITIES_HOST_PPC64LE_TEMPLATE,
Architecture.S390X: CAPABILITIES_HOST_S390X_TEMPLATE,
}
# NOTE(aspiers): HostTestCase has tests which assert that for any
# given (arch, domain) listed in the guest capabilities here, all
# canonical machine types (e.g. 'pc' or 'q35') must be a substring of
# the expanded machine type returned in the element of the
# corresponding fake getDomainCapabilities response for that (arch,
# domain, canonical_machine_type) combination. Those responses are
# defined by the DOMCAPABILITIES_* variables below. While
# DOMCAPABILITIES_X86_64_TEMPLATE can return multiple values for the
# element, DOMCAPABILITIES_I686 is fixed to fake a response
# of the 'pc-i440fx-2.11' machine type, therefore
# CAPABILITIES_GUEST['i686'] should return 'pc' as the only canonical
# machine type.
#
# CAPABILITIES_GUEST does not include canonical machine types for
# other non-x86 architectures, so these test assertions on apply to
# x86.
CAPABILITIES_GUEST = {
'i686': '''
hvm
32
/usr/bin/qemu-system-i386
pc-i440fx-2.11
pc
isapc
pc-1.1
pc-1.2
pc-1.3
pc-i440fx-2.8
pc-1.0
pc-i440fx-2.9
pc-i440fx-2.6
pc-i440fx-2.7
xenfv
pc-i440fx-2.3
pc-i440fx-2.4
pc-i440fx-2.5
pc-i440fx-2.1
pc-i440fx-2.2
pc-i440fx-2.0
pc-q35-2.11
q35
xenpv
pc-q35-2.10
pc-i440fx-1.7
pc-q35-2.9
pc-0.15
pc-i440fx-1.5
pc-q35-2.7
pc-i440fx-1.6
pc-q35-2.8
pc-0.13
pc-0.14
pc-q35-2.4
pc-q35-2.5
pc-q35-2.6
pc-i440fx-1.4
pc-i440fx-2.10
pc-0.11
pc-0.12
pc-0.10
/usr/bin/qemu-kvm
pc-i440fx-2.11
pc
isapc
pc-1.1
pc-1.2
pc-1.3
pc-i440fx-2.8
pc-1.0
pc-i440fx-2.9
pc-i440fx-2.6
pc-i440fx-2.7
xenfv
pc-i440fx-2.3
pc-i440fx-2.4
pc-i440fx-2.5
pc-i440fx-2.1
pc-i440fx-2.2
pc-i440fx-2.0
pc-q35-2.11
q35
xenpv
pc-q35-2.10
pc-i440fx-1.7
pc-q35-2.9
pc-0.15
pc-i440fx-1.5
pc-q35-2.7
pc-i440fx-1.6
pc-q35-2.8
pc-0.13
pc-0.14
pc-q35-2.4
pc-q35-2.5
pc-q35-2.6
pc-i440fx-1.4
pc-i440fx-2.10
pc-0.11
pc-0.12
pc-0.10
''',
'x86_64': '''
hvm
64
/usr/bin/qemu-system-x86_64
pc-i440fx-2.11
pc
isapc
pc-1.1
pc-1.2
pc-1.3
pc-i440fx-2.8
pc-1.0
pc-i440fx-2.9
pc-i440fx-2.6
pc-i440fx-2.7
xenfv
pc-i440fx-2.3
pc-i440fx-2.4
pc-i440fx-2.5
pc-i440fx-2.1
pc-i440fx-2.2
pc-i440fx-2.0
pc-q35-2.11
q35
xenpv
pc-q35-2.10
pc-i440fx-1.7
pc-q35-2.9
pc-0.15
pc-i440fx-1.5
pc-q35-2.7
pc-i440fx-1.6
pc-q35-2.8
pc-0.13
pc-0.14
pc-q35-2.4
pc-q35-2.5
pc-q35-2.6
pc-i440fx-1.4
pc-i440fx-2.10
pc-0.11
pc-0.12
pc-0.10
/usr/bin/qemu-kvm
pc-i440fx-2.11
pc
isapc
pc-1.1
pc-1.2
pc-1.3
pc-i440fx-2.8
pc-1.0
pc-i440fx-2.9
pc-i440fx-2.6
pc-i440fx-2.7
xenfv
pc-i440fx-2.3
pc-i440fx-2.4
pc-i440fx-2.5
pc-i440fx-2.1
pc-i440fx-2.2
pc-i440fx-2.0
pc-q35-2.11
q35
xenpv
pc-q35-2.10
pc-i440fx-1.7
pc-q35-2.9
pc-0.15
pc-i440fx-1.5
pc-q35-2.7
pc-i440fx-1.6
pc-q35-2.8
pc-0.13
pc-0.14
pc-q35-2.4
pc-q35-2.5
pc-q35-2.6
pc-i440fx-1.4
pc-i440fx-2.10
pc-0.11
pc-0.12
pc-0.10
''',
'aarch64': '''
hvm
64
/usr/bin/qemu-system-aarch64
integratorcp
ast2600-evb
borzoi
spitz
virt-2.7
nuri
mcimx7d-sabre
romulus-bmc
virt-3.0
virt-5.0
virt-2.10
virt-2.8
musca-b1
realview-pbx-a9
versatileab
kzm
musca-a
virt-3.1
mcimx6ul-evk
virt-5.1
virt
smdkc210
sx1
raspi2
virt-2.11
imx25-pdk
virt-2.9
orangepi-pc
z2
xilinx-zynq-a9
xlnx-zcu102
raspi3
tosa
virt-2.12
mps2-an521
sabrelite
mps2-an511
canon-a1100
realview-eb
emcraft-sf2
realview-pb-a8
sbsa-ref
virt-4.0
palmetto-bmc
sx1-v1
n810
tacoma-bmc
n800
virt-4.1
versatilepb
terrier
mainstone
realview-eb-mpcore
virt-4.2
witherspoon-bmc
swift-bmc
vexpress-a9
midway
musicpal
lm3s811evb
lm3s6965evb
microbit
mps2-an505
mps2-an385
cubieboard
verdex
netduino2
xlnx-versal-virt
vexpress-a15
sonorapass-bmc
cheetah
virt-2.6
ast2500-evb
highbank
akita
connex
netduinoplus2
collie
''',
'armv7l': '''
hvm
32
/usr/bin/qemu-system-arm
integratorcp
vexpress-a9
syborg
musicpal
mainstone
n800
n810
n900
cheetah
sx1
sx1-v1
beagle
beaglexm
tosa
akita
spitz
borzoi
terrier
connex
verdex
lm3s811evb
lm3s6965evb
realview-eb
realview-eb-mpcore
realview-pb-a8
realview-pbx-a9
versatilepb
versatileab
''',
'mips': '''
hvm
32
/usr/bin/qemu-system-mips
malta
mipssim
magnum
pica61
mips
''',
'mipsel': '''
hvm
32
/usr/bin/qemu-system-mipsel
malta
mipssim
magnum
pica61
mips
''',
'sparc': '''
hvm
32
/usr/bin/qemu-system-sparc
SS-5
leon3_generic
SS-10
SS-600MP
SS-20
Voyager
LX
SS-4
SPARCClassic
SPARCbook
SS-1000
SS-2000
SS-2
''',
'ppc': '''
hvm
32
/usr/bin/qemu-system-ppc
g3beige
virtex-ml507
mpc8544ds
bamboo-0.13
bamboo-0.12
ref405ep
taihu
mac99
prep
'''
}
DOMCAPABILITIES_SPARC = """
/usr/bin/qemu-system-sparc
qemu
SS-5
sparc
rom
pflash
yes
no
yes
no
disk
cdrom
floppy
lun
fdc
scsi
virtio
sdl
vnc
spice
subsystem
default
mandatory
requisite
optional
usb
pci
scsi
"""
DOMCAPABILITIES_ARMV7 = """
/usr/bin/qemu-system-arm
qemu
virt-2.11
armv7l
rom
pflash
yes
no
yes
no
pxa262
pxa270-a0
arm1136
cortex-a15
pxa260
arm1136-r2
pxa261
pxa255
arm926
arm11mpcore
pxa250
ti925t
sa1110
arm1176
sa1100
pxa270-c5
cortex-a9
cortex-a8
pxa270-c0
cortex-a7
arm1026
pxa270-b1
cortex-m3
cortex-m4
pxa270-b0
arm946
cortex-r5
pxa270-a1
pxa270
disk
cdrom
floppy
lun
fdc
scsi
virtio
usb
sata
sdl
vnc
spice
subsystem
default
mandatory
requisite
optional
usb
pci
scsi
2
3
"""
DOMCAPABILITIES_AARCH64 = """
/usr/bin/qemu-system-aarch64
qemu
virt-5.1
aarch64
efi
/usr/share/AAVMF/AAVMF_CODE.fd
rom
pflash
yes
no
no
yes
pxa270-c0
cortex-a15
pxa270-b0
cortex-a57
cortex-m4
pxa270-a0
arm1176
pxa270-b1
cortex-a7
pxa270-a1
cortex-a8
cortex-r5
ti925t
cortex-r5f
arm1026
cortex-a9
cortex-m7
pxa270
pxa260
pxa250
pxa270-c5
pxa261
pxa262
sa1110
sa1100
max
cortex-a53
cortex-m0
cortex-m33
cortex-a72
arm946
pxa255
arm11mpcore
arm926
arm1136
arm1136-r2
cortex-m3
disk
cdrom
floppy
lun
fdc
scsi
virtio
usb
sata
virtio
virtio-transitional
virtio-non-transitional
sdl
vnc
spice
subsystem
default
mandatory
requisite
optional
usb
pci
scsi
virtio
virtio-transitional
virtio-non-transitional
random
egd
builtin
2
3
"""
DOMCAPABILITIES_PPC = """
/usr/bin/qemu-system-ppc
qemu
g3beige
ppc
rom
pflash
yes
no
yes
no
disk
cdrom
floppy
lun
ide
fdc
scsi
virtio
usb
sata
sdl
vnc
spice
subsystem
default
mandatory
requisite
optional
usb
pci
scsi
"""
DOMCAPABILITIES_MIPS = """
/usr/bin/qemu-system-mips
qemu
malta
mips
rom
pflash
yes
no
yes
no
disk
cdrom
floppy
lun
ide
fdc
scsi
virtio
usb
sata
sdl
vnc
spice
subsystem
default
mandatory
requisite
optional
usb
pci
scsi
"""
DOMCAPABILITIES_MIPSEL = """
/usr/bin/qemu-system-mipsel
qemu
malta
mipsel
rom
pflash
yes
no
yes
no
disk
cdrom
floppy
lun
ide
fdc
scsi
virtio
usb
sata
sdl
vnc
spice
subsystem
default
mandatory
requisite
optional
usb
pci
scsi
"""
# NOTE(sean-k-mooney): yes i686 is actually the i386 emulator
# the qemu-system-i386 binary is used for all 32bit x86
# instruction sets.
DOMCAPABILITIES_I686 = """
/usr/bin/qemu-system-i386
kvm
pc-i440fx-2.11
i686
rom
pflash
yes
no
yes
no
Skylake-Client-IBRS
Intel
qemu64
qemu32
phenom
pentium3
pentium2
pentium
n270
kvm64
kvm32
coreduo
core2duo
athlon
Westmere
Westmere-IBRS
Skylake-Server
Skylake-Server-IBRS
Skylake-Client
Skylake-Client-IBRS
SandyBridge
SandyBridge-IBRS
Penryn
Opteron_G5
Opteron_G4
Opteron_G3
Opteron_G2
Opteron_G1
Nehalem
Nehalem-IBRS
IvyBridge
IvyBridge-IBRS
Haswell-noTSX
Haswell-noTSX-IBRS
Haswell
Haswell-IBRS
EPYC
EPYC-IBPB
Conroe
Broadwell-noTSX
Broadwell-noTSX-IBRS
Broadwell
Broadwell-IBRS
486
disk
cdrom
floppy
lun
ide
fdc
scsi
virtio
usb
sata
sdl
vnc
spice
subsystem
default
mandatory
requisite
optional
usb
pci
scsi
"""
STATIC_DOMCAPABILITIES = {
Architecture.ARMV7: DOMCAPABILITIES_ARMV7,
Architecture.AARCH64: DOMCAPABILITIES_AARCH64,
Architecture.SPARC: DOMCAPABILITIES_SPARC,
Architecture.PPC: DOMCAPABILITIES_PPC,
Architecture.MIPS: DOMCAPABILITIES_MIPS,
Architecture.MIPSEL: DOMCAPABILITIES_MIPSEL,
Architecture.I686: DOMCAPABILITIES_I686
}
# NOTE(aspiers): see the above note for CAPABILITIES_GUEST which
# explains why the element here needs to be parametrised.
#
# The element needs to be parametrised for emulating
# environments with and without the SEV feature.
DOMCAPABILITIES_X86_64_TEMPLATE = """
/usr/bin/qemu-kvm
kvm
%(mtype)s
x86_64
efi
/usr/share/edk2/ovmf/OVMF_CODE.fd
/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd
rom
pflash
yes
no
yes
no
EPYC-IBPB
AMD
qemu64
qemu32
phenom
pentium3
pentium2
pentium
n270
kvm64
kvm32
coreduo
core2duo
athlon
Westmere
Westmere-IBRS
Skylake-Server
Skylake-Server-IBRS
Skylake-Client
Skylake-Client-IBRS
SandyBridge
SandyBridge-IBRS
Penryn
Opteron_G5
Opteron_G4
Opteron_G3
Opteron_G2
Opteron_G1
Nehalem
Nehalem-IBRS
IvyBridge
IvyBridge-IBRS
Haswell
Haswell-noTSX
Haswell-noTSX-IBRS
Haswell-IBRS
EPYC
EPYC-IBPB
Conroe
Broadwell
Broadwell-noTSX
Broadwell-noTSX-IBRS
Broadwell-IBRS
486
disk
cdrom
floppy
lun
ide
fdc
scsi
virtio
usb
sata
sdl
vnc
spice
subsystem
default
mandatory
requisite
optional
usb
pci
scsi
default
vfio
%(features)s
"""
_fake_NodeDevXml = {
"pci_0000_04_00_3": """
pci_0000_04_00_3
pci_0000_00_01_1
igb
0
4
0
3
I350 Gigabit Network Connection
Intel Corporation
""",
"pci_0000_04_10_7": """
pci_0000_04_10_7
pci_0000_04_00_3
igbvf
0
4
16
7
I350 Ethernet Controller Virtual Function
Intel Corporation
""",
"pci_0000_04_11_7": """
pci_0000_04_11_7
pci_0000_04_00_3
igbvf
0
4
17
7
I350 Ethernet Controller Virtual Function
Intel Corporation
""",
"pci_0000_04_00_1": """
pci_0000_04_00_1
/sys/devices/pci0000:00/0000:00:02.0/0000:04:00.1
pci_0000_00_02_0
mlx5_core
0
4
0
1
MT27700 Family [ConnectX-4]
Mellanox Technologies
""",
# libvirt >= 1.3.0 nodedev-dumpxml
"pci_0000_03_00_0": """
pci_0000_03_00_0
/sys/devices/pci0000:00/0000:00:02.0/0000:03:00.0
pci_0000_00_02_0
mlx5_core
0
3
0
0
MT27700 Family [ConnectX-4]
Mellanox Technologies
""",
"pci_0000_03_00_1": """
pci_0000_03_00_1
/sys/devices/pci0000:00/0000:00:02.0/0000:03:00.1
pci_0000_00_02_0
mlx5_core
0
3
0
1
MT27700 Family [ConnectX-4]
Mellanox Technologies
""",
"net_enp2s1_02_9a_a1_37_be_54": """
net_enp2s1_02_9a_a1_37_be_54
/sys/devices/pci0000:00/0000:04:00.3/0000:04:10.7/net/enp2s1
pci_0000_04_10_7
enp2s1
02:9a:a1:37:be:54
""",
"net_enp2s2_02_9a_a1_37_be_54": """
net_enp2s2_02_9a_a1_37_be_54
/sys/devices/pci0000:00/0000:00:02.0/0000:02:02.0/net/enp2s2
pci_0000_04_11_7
enp2s2
02:9a:a1:37:be:54
""",
"pci_0000_06_00_0": """
pci_0000_06_00_0
/sys/devices/pci0000:00/0000:00:06.0
nvidia
0
10
1
5
GRID M60-0B
Nvidia
GRID M60-0B
vfio-pci
16
""",
"pci_0000_06_00_1": """
pci_0000_06_00_1
/sys/devices/pci0000:00/0000:00:06.1
i915
0
6
0
1
HD Graphics P630
Intel Corporation
vfio-pci
2
""",
"mdev_4b20d080_1b54_4048_85b3_a6a62d165c01": """
mdev_4b20d080_1b54_4048_85b3_a6a62d165c01
/sys/devices/pci0000:00/0000:00:02.0/4b20d080-1b54-4048-85b3-a6a62d165c01
pci_0000_00_02_0
vfio_mdev
""",
}
_fake_NodeDevXml_parents = {
name: etree.fromstring(xml).find("parent").text
for name, xml in _fake_NodeDevXml.items()
}
_fake_NodeDevXml_children = collections.defaultdict(list)
for key, val in _fake_NodeDevXml_parents.items():
_fake_NodeDevXml_children[val].append(key)