Skip to content

Commit

Permalink
Add edit-hardware --network-descriptions option
Browse files Browse the repository at this point in the history
  • Loading branch information
glennmatthews committed Jun 7, 2016
1 parent 3df7506 commit 8dc0157
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 25 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ This project adheres to `Semantic Versioning`_.
`Unreleased`_
-------------

**Added**

- ``cot edit-hardware --network-descriptions`` option, to specify the
descriptive string(s) associated with each network definition.

**Fixed**

- `#48`_ - NIC type not set when adding NICs to an OVF that had none before.
Expand Down
82 changes: 63 additions & 19 deletions COT/edit_hardware.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

from .data_validation import canonicalize_ide_subtype, canonicalize_nic_subtype
from .data_validation import canonicalize_scsi_subtype
from .data_validation import natural_sort, no_whitespace, mac_address
from .data_validation import no_whitespace, mac_address
from .data_validation import non_negative_int, positive_int, InvalidInputError
from .submodule import COTSubmodule

Expand All @@ -57,6 +57,7 @@ class COTEditHardware(COTSubmodule):
:attr:`mac_addresses_list`,
:attr:`nic_networks`,
:attr:`nic_names`,
:attr:`network_descriptions`,
:attr:`serial_ports`,
:attr:`serial_connectivity`,
:attr:`scsi_subtypes`,
Expand Down Expand Up @@ -85,6 +86,11 @@ def __init__(self, UI):
self.nic_names = None
"""List of NIC name strings.
Can use wildcards as described in :meth:`expand_list_wildcard`.
"""
self.network_descriptions = None
"""List of network description strings.
Can use wildcards as described in :meth:`expand_list_wildcard`.
"""
self._serial_ports = None
Expand Down Expand Up @@ -293,6 +299,7 @@ def ready_to_run(self):
self.mac_addresses_list is None and
self.nic_networks is None and
self.nic_names is None and
self.network_descriptions is None and
self.serial_ports is None and
self.serial_connectivity is None and
self.scsi_subtypes is None and
Expand All @@ -310,12 +317,20 @@ def run(self):
"""
super(COTEditHardware, self).run()

if self.profiles is not None and self.virtual_system_type is not None:
self.UI.confirm_or_die(
"VirtualSystemType is not filtered by configuration profile. "
"Requested system type(s) '{0}' will be set for ALL profiles, "
"not just profile(s) {1}. Continue?"
.format(" ".join(self.virtual_system_type), self.profiles))
# Warn user about non-profile-aware properties when setting profiles
if self.profiles is not None:
if self.virtual_system_type is not None:
self.UI.confirm_or_die(
"VirtualSystemType is not filtered by configuration"
" profile. Requested system type(s) '{0}' will be set for"
" ALL profiles, not just profile(s) {1}. Continue?"
.format(" ".join(self.virtual_system_type), self.profiles))
if self.network_descriptions is not None:
self.UI.confirm_or_die(
"Network descriptions are not filtered by configuration"
" profile. Requested network descriptions will be set for"
" networks across ALL profiles, not just profile(s) {0}."
" Continue?".format(self.profiles))

vm = self.vm

Expand Down Expand Up @@ -381,19 +396,39 @@ def run(self):
nics_dict = vm.get_nic_count(self.profiles)
max_nics = max(nics_dict.values())

if self.network_descriptions is None:
new_descs = []
else:
new_descs = self.expand_list_wildcard(self.network_descriptions,
max_nics)
if self.nic_networks is None:
# Just rename existing networks, instead of making new ones
for network, desc in zip(vm.networks, new_descs):
# Despite the name, create_network can also be used to
# update an existing network.
vm.create_network(network, desc)

if self.nic_networks is not None:
existing_networks = vm.networks
new_networks = self.expand_list_wildcard(self.nic_networks,
max_nics)
# Convert nic_networks to a set to merge duplicate entries
for network in natural_sort(set(new_networks)):
for network in new_networks:
if new_descs:
new_desc = new_descs.pop(0)
else:
new_desc = None

if network not in existing_networks:
self.UI.confirm_or_die(
"Network {0} is not currently defined. "
"Create it?".format(network))
desc = self.UI.get_input(
"Please enter a description for this network", network)
vm.create_network(network, desc)
if not new_desc:
new_desc = self.UI.get_input(
"Please enter a description for this network",
network)
# create or update
vm.create_network(network, new_desc)

vm.set_nic_networks(new_networks, self.profiles)

if self.mac_addresses_list is not None:
Expand Down Expand Up @@ -454,11 +489,12 @@ def create_subparser(self):
help="Edit virtual machine hardware properties of an OVF",
description="Edit hardware properties of the specified OVF or OVA",
epilog=("Notes:\n" + wrapper.fill(
"The --nic-names and --nic-networks options support the use"
" of a wildcard value to automatically generate a series of"
" consecutively numbered names. The syntax for the wildcard"
" option is '{' followed by a number to start incrementing"
" from, followed by '}'. See examples below."
"The --nic-names, --nic-networks, and --network-descriptions"
" options support the use of a wildcard value to"
" automatically generate a series of consecutively numbered"
" strings. The syntax for the wildcard option is '{' followed"
" by a number to start incrementing from, followed by '}'."
" See examples below."
) + "\n\n" + self.UI.fill_examples([
('Create a new profile named "1CPU-8GB" with 1 CPU and 8'
' gigabytes of RAM',
Expand All @@ -468,10 +504,13 @@ def create_subparser(self):
" defined in the input OVA, rename all of the NICs in the"
" output OVA as 'Ethernet0/10', 'Ethernet0/11',"
" 'Ethernet0/12', etc., and map them to networks"
" 'Ethernet0_10', 'Ethernet0_11', 'Ethernet0_12', etc.",
" 'Ethernet0_10', 'Ethernet0_11', 'Ethernet0_12', etc.,"
" which are described as 'Data network 1', 'Data network 2',"
" etc.",
'cot edit-hardware input.ova -o output.ova'
' --nic-names "Ethernet0/{10}"'
' --nic-networks "Ethernet0_{10}"'),
' --nic-networks "Ethernet0_{10}"'
' --network-descriptions "Data network {1}"'),
("Combination of fixed and wildcarded names - rename the NICs"
" in the output OVA as 'mgmt', 'eth0', 'eth1', 'eth2'...",
'cot edit-hardware input.ova -o output.ova'
Expand Down Expand Up @@ -523,6 +562,11 @@ def create_subparser(self):
metavar=('NETWORK', 'NETWORK2'),
help="Specify a series of one or more network names "
"or patterns to map NICs to. See Notes.")
g.add_argument('--network-descriptions', nargs='+',
metavar=('NAME1', 'NAME2'),
help="Specify a list of one or more network "
"descriptions or patterns to apply to the networks. "
"See Notes.")
g.add_argument('-M', '--mac-addresses-list', type=mac_address,
metavar=('MAC1', 'MAC2'), action='append', nargs='+',
help="Specify a list of MAC addresses for the NICs. "
Expand Down
2 changes: 2 additions & 0 deletions COT/ovf.py
Original file line number Diff line number Diff line change
Expand Up @@ -1296,6 +1296,8 @@ def set_nic_count(self, count, profile_list):
def create_network(self, label, description):
"""Define a new network with the given label and description.
Also serves to update the description of an existing network label.
:param str label: Brief label for the network
:param str description: Verbose description of the network
"""
Expand Down
30 changes: 24 additions & 6 deletions COT/tests/test_edit_hardware.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,14 +510,15 @@ def test_set_nic_network_one_profile(self):
# This involves splitting the existing NIC into two items
self.instance.package = self.input_ovf
self.instance.nic_networks = ['UT']
self.instance.network_descriptions = ['Unit test network']
self.instance.profiles = ['2CPU-2GB-1NIC']
self.instance.run()
self.instance.finished()
self.check_diff("""
<ovf:Description>VM Network</ovf:Description>
+ </ovf:Network>
+ <ovf:Network ovf:name="UT">
+ <ovf:Description>UT</ovf:Description>
+ <ovf:Description>Unit test network</ovf:Description>
</ovf:Network>
...
</ovf:Item>
Expand Down Expand Up @@ -572,10 +573,13 @@ def test_set_nic_network_all_profiles(self):
def test_set_nic_network_list_expansion(self):
"""Specify fewer networks than NICs to test implicit NIC assignment.
Also specify fewer network descriptions than networks.
Remaining networks get the last description in the list.
Remaining NICs get the last network in the list.
"""
self.instance.package = self.input_ovf
self.instance.nic_networks = ['UT1', 'UT2']
self.instance.network_descriptions = ['First UT']
self.instance.run()
self.instance.finished()
self.assertLogged(**self.REMOVING_NETWORK)
Expand All @@ -584,10 +588,10 @@ def test_set_nic_network_list_expansion(self):
- <ovf:Network ovf:name="VM Network">
- <ovf:Description>VM Network</ovf:Description>
+ <ovf:Network ovf:name="UT1">
+ <ovf:Description>UT1</ovf:Description>
+ <ovf:Description>First UT</ovf:Description>
+ </ovf:Network>
+ <ovf:Network ovf:name="UT2">
+ <ovf:Description>UT2</ovf:Description>
+ <ovf:Description>First UT</ovf:Description>
</ovf:Network>
...
<rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
Expand All @@ -613,6 +617,7 @@ def test_set_nic_network_list_pattern(self):
"""Use wildcard expansion to create multiple networks as needed."""
self.instance.package = self.input_ovf
self.instance.nic_networks = ["UT_{20}_network"]
self.instance.network_descriptions = ['First network', '#{2} Network']
self.instance.run()
self.instance.finished()
self.assertLogged(**self.REMOVING_NETWORK)
Expand All @@ -621,13 +626,13 @@ def test_set_nic_network_list_pattern(self):
- <ovf:Network ovf:name="VM Network">
- <ovf:Description>VM Network</ovf:Description>
+ <ovf:Network ovf:name="UT_20_network">
+ <ovf:Description>UT_20_network</ovf:Description>
+ <ovf:Description>First network</ovf:Description>
+ </ovf:Network>
+ <ovf:Network ovf:name="UT_21_network">
+ <ovf:Description>UT_21_network</ovf:Description>
+ <ovf:Description>#2 Network</ovf:Description>
+ </ovf:Network>
+ <ovf:Network ovf:name="UT_22_network">
+ <ovf:Description>UT_22_network</ovf:Description>
+ <ovf:Description>#3 Network</ovf:Description>
</ovf:Network>
...
<rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
Expand All @@ -649,6 +654,19 @@ def test_set_nic_network_list_pattern(self):
</rasd:Description>
""")

def test_set_network_description_only(self):
"""Set network descriptions without changing network names."""
self.instance.package = self.input_ovf
self.instance.network_descriptions = ['Network 1', 'Network 2']
self.instance.run()
self.instance.finished()
self.check_diff("""
<ovf:Network ovf:name="VM Network">
- <ovf:Description>VM Network</ovf:Description>
+ <ovf:Description>Network 1</ovf:Description>
</ovf:Network>
""")

def test_set_nic_mac_address_single_all_profiles(self):
"""Set a single MAC address on all NICs on all profiles."""
self.instance.package = self.input_ovf
Expand Down
2 changes: 2 additions & 0 deletions COT/vm_description.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,8 @@ def set_nic_count(self, count, profile_list):
def create_network(self, label, description):
"""Define a new network with the given label and description.
Also serves to update the description of an existing network label.
:param str label: Brief label for the network
:param str description: Verbose description of the network
"""
Expand Down

0 comments on commit 8dc0157

Please sign in to comment.