From 06c021465372820b135410e6d815b960be917d88 Mon Sep 17 00:00:00 2001 From: Glenn Matthews Date: Wed, 29 Nov 2017 17:03:25 -0500 Subject: [PATCH] Ensure that cloned Items always have higher InstanceID than parent Item. Fixes #70 --- CHANGELOG.rst | 3 + COT/commands/tests/test_edit_hardware.py | 40 +++ COT/tests/cot_testcase.py | 4 +- COT/tests/csr1000v_2017.ovf | 316 +++++++++++++++++++++++ COT/vm_description/ovf/hardware.py | 9 +- COT/vm_description/ovf/ovf.py | 5 +- 6 files changed, 372 insertions(+), 5 deletions(-) create mode 100644 COT/tests/csr1000v_2017.ovf diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 45efced..65102a2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,8 @@ This project adheres to `Semantic Versioning`_. **Fixed** +- COT now ensures that cloned Items have a higher InstanceID than the Item + they were cloned from, avoiding unexpected out-of-order behavior (`#70`_). - COT now produces valid manifests for OVF 2.x files (which use SHA256 instead of SHA1 as in OVF 0.x and 1.x). @@ -799,6 +801,7 @@ Initial public release. .. _#65: https://github.com/glennmatthews/cot/issues/65 .. _#66: https://github.com/glennmatthews/cot/issues/66 .. _#67: https://github.com/glennmatthews/cot/issues/67 +.. _#70: https://github.com/glennmatthews/cot/issues/70 .. _Semantic Versioning: http://semver.org/ .. _`PEP 8`: https://www.python.org/dev/peps/pep-0008/ diff --git a/COT/commands/tests/test_edit_hardware.py b/COT/commands/tests/test_edit_hardware.py index 0f68e91..d6a69a9 100644 --- a/COT/commands/tests/test_edit_hardware.py +++ b/COT/commands/tests/test_edit_hardware.py @@ -567,6 +567,46 @@ def test_set_nic_count_add_smart_networks(self): + """, file1=self.csr_ovf) + def test_set_nic_count_add_nonconsecutive_instances(self): + """Add additional NICs to an OVF with non-consecutive InstanceIDs.""" + self.command.package = self.csr_ovf_2017 + self.command.nics = 5 + self.command.run() + self.command.finished() + self.check_diff(""" + Data network 3 ++ ++ ++ Data network 4 ++ ++ ++ Data network 5 + +... + ++ 14 ++ true ++ GigabitEthernet4 ++ NIC representing GigabitEthernet4 ++ GigabitEthernet4 ++ 14 ++ VMXNET3 ++ 10 ++ ++ ++ 15 ++ true ++ GigabitEthernet5 ++ NIC representing GigabitEthernet5 ++ GigabitEthernet5 ++ 15 ++ VMXNET3 ++ 10 ++ ++ + 0 + """, file1=self.csr_ovf_2017) + def test_set_nic_count_named_nics_and_networks(self): """Add more NICs and explicitly named networks across all profiles. diff --git a/COT/tests/cot_testcase.py b/COT/tests/cot_testcase.py index 2d29fb8..d24041f 100644 --- a/COT/tests/cot_testcase.py +++ b/COT/tests/cot_testcase.py @@ -223,8 +223,10 @@ class COTTestCase(unittest.TestCase): # noqa: N801 minimal_ovf = _localfile("minimal.ovf") # IOSv OVF iosv_ovf = _localfile("iosv.ovf") - # CSR1000V OVF + # CSR1000V OVF - legacy csr_ovf = _localfile("csr1000v.ovf") + # CSR1000V OVF as of 2017 + csr_ovf_2017 = _localfile("csr1000v_2017.ovf") # v0.9 OVF v09_ovf = _localfile("v0.9.ovf") # v2.0 OVF from VirtualBox diff --git a/COT/tests/csr1000v_2017.ovf b/COT/tests/csr1000v_2017.ovf new file mode 100644 index 0000000..f669a51 --- /dev/null +++ b/COT/tests/csr1000v_2017.ovf @@ -0,0 +1,316 @@ + + + + + + + + Virtual disk information + + + + The list of logical networks + + Data network 1 + + + Data network 2 + + + Data network 3 + + + + Configuration Profiles + + Small + Minimal hardware profile - 1 vCPU, 4 GB RAM + + + Medium + Medium hardware profile - 2 vCPUs, 4 GB RAM + + + Large + Large hardware profile - 4 vCPUs, 4 GB RAM + + + Large + DRAM Upgrade + Large hardware profile (requires purchase of DRAM upgrade SKU) - 4 vCPUs, 8 GB RAM + + + + A virtual machine + Cisco CSR 1000V Cloud Services Router + + The kind of installed guest operating system + Cisco IOS-XE Software + + + Virtual hardware requirements + + Virtual Hardware Family + 0 + vmx-10 vmx-11 vmx-13 + + + hertz * 10^6 + Number of Virtual CPUs + 1 virtual CPU(s) + 1 + 3 + 1 + DMTF:x86:64 + DMTF:x86:SSE2 DMTF:x86:SSE3 DMTF:x86:SSSE3 + 1 + + + hertz * 10^6 + Number of Virtual CPUs + 2 virtual CPU(s) + 1 + 3 + 2 + DMTF:x86:64 + DMTF:x86:SSE2 DMTF:x86:SSE3 DMTF:x86:SSSE3 + 1 + + + hertz * 10^6 + Number of Virtual CPUs + 4 virtual CPU(s) + 1 + 3 + 4 + DMTF:x86:64 + DMTF:x86:SSE2 DMTF:x86:SSE3 DMTF:x86:SSSE3 + 1 + + + byte * 2^20 + Memory Size + 4096MB of memory + 2 + 4 + 4096 + + + byte * 2^20 + Memory Size + 8192MB of memory + 2 + 4 + 8192 + + + 0 + SCSI Controller + SCSI Controller 0 + 3 + VirtualSCSI + 6 + + + 1 + IDE Controller + VirtualIDEController 0 + 4 + 5 + + + 11 + true + GigabitEthernet1 + NIC representing GigabitEthernet1 + GigabitEthernet1 + 11 + VMXNET3 + 10 + + + 12 + true + GigabitEthernet2 + NIC representing GigabitEthernet2 + GigabitEthernet2 + 12 + VMXNET3 + 10 + + + 13 + true + GigabitEthernet3 + NIC representing GigabitEthernet3 + GigabitEthernet3 + 13 + VMXNET3 + 10 + + + 0 + Hard Drive + ovf:/disk/vmdisk1 + 3001 + 3 + 17 + + + 0 + true + CD-ROM 1 + ovf:/file/csr1000v.iso + 4001 + 4 + 15 + + + 1 + false + CD-ROM 2 + 4002 + 4 + 15 + + + + + + + + + + + + + + + + + + + + + Information about the installed software + Cisco CSR 1000V Cloud Services Router + Cisco Systems, Inc. + DEV + DEVELOPMENT IMAGE + http://www.cisco.com/en/US/products/ps12559/index.html + http://www.cisco.com + + DO NOT CHANGE THIS VALUE + + 1. Bootstrap Properties + + Router Name + Hostname of this router + + + Login Username + Username for remote login + + + Login Password + Password for remote login. +WARNING: While this password will be stored securely within IOS, the plain-text password will be recoverable from the OVF descriptor file. + + + Management Interface + Management interface (such as "GigabitEthernet1" or "GigabitEthernet1.100") + + + Management VLAN + Management dot1Q VLAN (requires specifying a subinterface such as "GigabitEthernet1.100" for the Management Interface) + + + Management Interface IPv4 Address/Mask + IPv4 address and mask for management interface (such as "192.0.2.100/24" or "192.0.2.100 255.255.255.0"), or "dhcp" to configure via DHCP + + + Management IPv4 Gateway + IPv4 gateway address (such as "192.0.2.1") for management interface, or "dhcp" to configure via DHCP + + + Management IPv4 Network + IPv4 Network (such as "192.168.2.0/24" or "192.168.2.0 255.255.255.0") that the management gateway should route to. + + + PNSC IPv4 Address + IPv4 address without mask (such as "192.0.2.110") of PNSC service controller + + + PNSC Agent Local Port + PNSC service agent SSL port (on local CSR) to receive policies from service manager. +The port shall be in the range of [55001, 61000] if shared IP is used, i.e., Remote Management IPv4 Address is not configured. + + + + PNSC Shared Secret Key + PNSC service controller shared secret key (8-64 characters) for PNSC agent to get SSL certificate from the controller. +WARNING: While this password will be stored securely within IOS, the plain-text password will be recoverable from the OVF descriptor file. + + + Remote Management IPv4 Address (optional, deprecated) + Secondary IPv4 address without mask (such as "192.0.2.101") for access to remote management features (REST API, etc.). This should be in the same IP subnet as the Management Interface IPv4 Address entered above. +Warning: THIS IS A DEPRECATED OPTION IN THIS RELEASE. + + 2. Features + + Enable SCP Server + Enable IOS SCP server feature + + + Enable SSH Login and Disable Telnet Login + Enable remote login via SSH and disable remote login via telnet. Requires login-username and login-password to be set! + + 3. Additional Configuration Properties + + Enable Password + Password for privileged (enable) access. +WARNING: While this password will be stored securely within IOS, the plain-text password will be recoverable from the OVF descriptor file. + + + Domain Name + Network domain name (such as "cisco.com") + + + License boot level + Configure license boot level(such as ax, security, appx, ipbase, lite, vacs) + + + Resource template + Configure Resource template(service_plane_medium, service_plane_heavy or default) + + 4. Intercloud Configuration Properties + + Intercloud Mode + Set to "intercloud" to enable intercloud mode. If intercloud mode is not enabled, all the following properties will be ignored. + + + Intercloud Mode Management Key + Set the intercloud mode management-key (max 64 chars). + + + Intercloud Control Port + Port in range of 1-65535. + + + Intercloud Tunnel Port + Port in range of 1-65535. + + + Intercloud Tunnel Header Size + Specify the tunnel header size to calculate management interface MTU setting. Maximum size is limited to 512 bytes. + + + Intercloud Tunnel Interface IPv4 Address + IPv4 address and mask for intercloud tunnel interface (such as "192.0.2.100/24" or "192.0.2.100 255.255.255.0"), or "dhcp" to configure via DHCP. + + + Intercloud Tunnel Interface Gateway IPv4 Address + IPv4 gateway address such as 192.168.0.2; ignored if "dhcp" is configured for Intercloud Tunnel Interface IPv4 Address. + + + + diff --git a/COT/vm_description/ovf/hardware.py b/COT/vm_description/ovf/hardware.py index faa4f5c..1168dd4 100644 --- a/COT/vm_description/ovf/hardware.py +++ b/COT/vm_description/ovf/hardware.py @@ -143,13 +143,16 @@ def update_xml(self): len(self.ovf.virtual_hw_section.findall(self.ovf.ITEM)), len(self.item_dict)) - def find_unused_instance_id(self): + def find_unused_instance_id(self, start=1): """Find the first available ``InstanceID`` number. + Args: + start (int): First InstanceID value to consider (disregarding all + lower InstanceIDs, even if available). Returns: str: An instance ID that is not yet in use. """ - instance = 1 + instance = int(start) while str(instance) in self.item_dict.keys(): instance += 1 logger.debug("Found unused InstanceID %d", instance) @@ -204,7 +207,7 @@ def clone_item(self, parent_item, profile_list): Returns: tuple: ``(instance_id, ovfitem)`` """ - instance = self.find_unused_instance_id() + instance = self.find_unused_instance_id(start=parent_item.instance_id) logger.spam("Cloning existing Item %s with new instance ID %s", parent_item, instance) ovfitem = copy.deepcopy(parent_item) diff --git a/COT/vm_description/ovf/ovf.py b/COT/vm_description/ovf/ovf.py index 7fc8b00..7272375 100644 --- a/COT/vm_description/ovf/ovf.py +++ b/COT/vm_description/ovf/ovf.py @@ -44,7 +44,7 @@ from COT.utilities import pretty_bytes, tar_entry_size from ..vm_description import VMDescription, VMInitError -from .name_helper import name_helper +from .name_helper import name_helper, CIM_URI from .hardware import OVFHardware, OVFHardwareDataError from .item import list_union from .utilities import ( @@ -203,6 +203,9 @@ def __init__(self, input_file, output_file): ET.register_namespace('vmw', "http://www.vmware.com/schema/ovf") ET.register_namespace('vbox', "http://www.virtualbox.org/ovf/machine") + ET.register_namespace( + 'pasd', + CIM_URI + "/cim-schema/2/CIM_ProcessorAllocationSettingData") # Go ahead and set pointers to some of the most useful XML sections self.envelope = self.root