From a85634527c2d69f992f2c64d98ba8e1be99913dc Mon Sep 17 00:00:00 2001 From: Yaniv Kaul Date: Sun, 23 Oct 2016 19:58:34 +0300 Subject: [PATCH] Ensure consistent load order of domains and networks. By processing JSON or YAML files via Ordered dicts., we ensure that domains are processed in the order they are specified in the relevant configuration files. --- lago/prefix.py | 2 +- lago/utils.py | 18 +++++++++++++++++- lago/virt.py | 19 ++++++++++++------- .../fixtures/status/prefix_skel/expected.yaml | 4 ++-- 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/lago/prefix.py b/lago/prefix.py index 3bcf3f2e..bfe35ff6 100644 --- a/lago/prefix.py +++ b/lago/prefix.py @@ -742,7 +742,7 @@ def _ova_to_spec(self, filename): "template_type": "qcow2", "format": "qcow2", "dev": "vda", - "name": "root", + # "name": "root", "name": os.path.basename(image_file), "path": ova_extracted_dir + "/images/" + image_file, diff --git a/lago/utils.py b/lago/utils.py index b885eefe..f0acb288 100644 --- a/lago/utils.py +++ b/lago/utils.py @@ -421,6 +421,10 @@ def deepcopy(original_obj): """ if isinstance(original_obj, list): return list(deepcopy(item) for item in original_obj) + elif isinstance(original_obj, collections.OrderedDict): + return collections.OrderedDict( + (key, deepcopy(val)) for key, val in original_obj.items() + ) elif isinstance(original_obj, dict): return dict((key, deepcopy(val)) for key, val in original_obj.items()) else: @@ -439,9 +443,21 @@ def load_virt_stream(virt_fd): dict: Loaded virt config """ try: - virt_conf = json.load(virt_fd) + virt_conf = json.load( + virt_fd, object_pairs_hook=collections.OrderedDict + ) except ValueError: virt_fd.seek(0) + + # Ensure ordered dict loading from YAML. Based on + # http://stackoverflow.com/questions/5121931/in-python-how-can-you-load-yaml-mappings-as-ordereddicts + _mapping_tag = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG + + def dict_constructor(loader, node): + return collections.OrderedDict(loader.construct_pairs(node)) + + yaml.add_constructor(_mapping_tag, dict_constructor) + virt_conf = yaml.load(virt_fd) return deepcopy(virt_conf) diff --git a/lago/virt.py b/lago/virt.py index 9b610fb6..089553a6 100644 --- a/lago/virt.py +++ b/lago/virt.py @@ -23,6 +23,7 @@ import logging import os import uuid +import collections import lxml.etree @@ -79,11 +80,11 @@ def __init__(self, prefix, vm_specs, net_specs): with open(self.prefix.paths.uuid(), 'r') as uuid_fd: self.uuid = uuid_fd.read().strip() - self._nets = {} + self._nets = collections.OrderedDict() for name, spec in net_specs.items(): self._nets[name] = self._create_net(spec) - self._vms = {} + self._vms = collections.OrderedDict() for name, spec in vm_specs.items(): self._vms[name] = self._create_vm(spec) @@ -233,17 +234,21 @@ def from_prefix(cls, prefix): virt_path = functools.partial(prefix.paths.prefixed, 'virt') with open(virt_path('env'), 'r') as f: - env_dom = json.load(f) + env_dom = json.load(f, object_pairs_hook=collections.OrderedDict) - net_specs = {} + net_specs = collections.OrderedDict() for name in env_dom['nets']: with open(virt_path('net-%s' % name), 'r') as f: - net_specs[name] = json.load(f) + net_specs[name] = json.load( + f, object_pairs_hook=collections.OrderedDict + ) - vm_specs = {} + vm_specs = collections.OrderedDict() for name in env_dom['vms']: with open(virt_path('vm-%s' % name), 'r') as f: - vm_specs[name] = json.load(f) + vm_specs[name] = json.load( + f, object_pairs_hook=collections.OrderedDict + ) return cls(prefix, vm_specs, net_specs) diff --git a/tests/functional/fixtures/status/prefix_skel/expected.yaml b/tests/functional/fixtures/status/prefix_skel/expected.yaml index fb4cfd7b..e2a1fdfa 100644 --- a/tests/functional/fixtures/status/prefix_skel/expected.yaml +++ b/tests/functional/fixtures/status/prefix_skel/expected.yaml @@ -13,7 +13,7 @@ Prefix: eth1: {ip: !!python/unicode '192.168.202.2', network: !!python/unicode 'n1'} VNC port: null distro: !!python/unicode 'cirros' - metadata: {} + metadata: !!python/object/apply:collections.OrderedDict root password: !!python/unicode '123456' snapshots: '' status: down @@ -23,7 +23,7 @@ Prefix: eth1: {ip: !!python/unicode '192.168.202.3', network: !!python/unicode 'n1'} VNC port: null distro: !!python/unicode 'cirros' - metadata: {} + metadata: !!python/object/apply:collections.OrderedDict root password: !!python/unicode 'cubswin:)' snapshots: '' status: down