def create_node(vm_): """ Build and submit the XML to create a node """ # Start the tree content = ET.Element("ve") # Name of the instance name = ET.SubElement(content, "name") name.text = vm_["name"] # Description, defaults to name desc = ET.SubElement(content, "description") desc.text = config.get_config_value("desc", vm_, __opts__, default=vm_["name"], search_global=False) # How many CPU cores, and how fast they are cpu = ET.SubElement(content, "cpu") cpu.attrib["number"] = config.get_config_value("cpu_number", vm_, __opts__, default="1", search_global=False) cpu.attrib["power"] = config.get_config_value("cpu_power", vm_, __opts__, default="1000", search_global=False) # How many megabytes of RAM ram = ET.SubElement(content, "ram-size") ram.text = config.get_config_value("ram", vm_, __opts__, default="256", search_global=False) # Bandwidth available, in kbps bandwidth = ET.SubElement(content, "bandwidth") bandwidth.text = config.get_config_value("bandwidth", vm_, __opts__, default="100", search_global=False) # How many public IPs will be assigned to this instance ip_num = ET.SubElement(content, "no-of-public-ip") ip_num.text = config.get_config_value("ip_num", vm_, __opts__, default="1", search_global=False) # Size of the instance disk disk = ET.SubElement(content, "ve-disk") disk.attrib["local"] = "true" disk.attrib["size"] = config.get_config_value("disk_size", vm_, __opts__, default="10", search_global=False) # Attributes for the image vm_image = config.get_config_value("image", vm_, __opts__, search_global=False) image = show_image({"image": vm_image}, call="function") platform = ET.SubElement(content, "platform") template = ET.SubElement(platform, "template-info") template.attrib["name"] = vm_image os_info = ET.SubElement(platform, "os-info") os_info.attrib["technology"] = image[vm_image]["technology"] os_info.attrib["type"] = image[vm_image]["osType"] # Username and password admin = ET.SubElement(content, "admin") admin.attrib["login"] = config.get_config_value("ssh_username", vm_, __opts__, default="root") admin.attrib["password"] = config.get_config_value("password", vm_, __opts__, search_global=False) data = ET.tostring(content, encoding="UTF-8") salt.cloud.utils.fire_event( "event", "requesting instance", "salt/cloud/{0}/requesting".format(vm_["name"]), {"kwargs": data} ) node = query(action="ve", method="POST", data=data) return node
def append_to_XMLDesc(mocked, fragment): """ Append an XML fragment at the end of the mocked XMLDesc return_value of mocked. """ xml_doc = ET.fromstring(mocked.XMLDesc()) xml_fragment = ET.fromstring(fragment) xml_doc.append(xml_fragment) mocked.XMLDesc.return_value = ET.tostring(xml_doc)
def test_strip_spaces(): xml_str = """<domain> <name>test01</name> <memory unit="MiB" >1024</memory> </domain> """ expected_str = ( b'<domain><name>test01</name><memory unit="MiB">1024</memory></domain>' ) node = ET.fromstring(xml_str) assert expected_str == ET.tostring(xml.strip_spaces(node))
def test_gen_xml_hostdev_pf(): """ Test the virt._gen_net_xml() function for a hostdev forward mode with physical function """ xml_data = virt._gen_net_xml("network", "virbr0", "hostdev", None, physical_function="eth0") root = ET.fromstring(xml_data) expected_forward = strip_xml(""" <forward mode='hostdev' managed='yes'> <pf dev='eth0'/> </forward> """) actual_forward = ET.tostring(xmlutil.strip_spaces(root.find("./forward"))) assert expected_forward == actual_forward
def test_init_hostdev_usb(make_capabilities, make_mock_device): """ Test virt.init with USB host device passed through """ make_capabilities() make_mock_device(""" <device> <name>usb_3_1_3</name> <path>/sys/devices/pci0000:00/0000:00:1d.6/0000:06:00.0/0000:07:02.0/0000:3e:00.0/usb3/3-1/3-1.3</path> <devnode type='dev'>/dev/bus/usb/003/004</devnode> <parent>usb_3_1</parent> <driver> <name>usb</name> </driver> <capability type='usb_device'> <bus>3</bus> <device>4</device> <product id='0x6006'>AUKEY PC-LM1E Camera</product> <vendor id='0x0458'>KYE Systems Corp. (Mouse Systems)</vendor> </capability> </device> """) with patch.dict(virt.os.__dict__, { "chmod": MagicMock(), "makedirs": MagicMock() }): with patch.dict(virt.__salt__, {"cmd.run": MagicMock()}): virt.init("test_vm", 2, 2048, host_devices=["usb_3_1_3"], start=False) define_mock = virt.libvirt.openAuth().defineXML setxml = ET.fromstring(define_mock.call_args[0][0]) expected_xml = strip_xml(""" <hostdev mode='subsystem' type='usb'> <source> <vendor id='0x0458'/> <product id='0x6006'/> </source> </hostdev> """) assert expected_xml == strip_xml( ET.tostring(setxml.find("./devices/hostdev")))
def test_init_hostdev_pci(make_capabilities, make_mock_device): """ Test virt.init with PCI host device passed through """ make_capabilities() make_mock_device(""" <device> <name>pci_1002_71c4</name> <parent>pci_8086_27a1</parent> <capability type='pci'> <class>0xffffff</class> <domain>0</domain> <bus>1</bus> <slot>0</slot> <function>0</function> <product id='0x71c4'>M56GL [Mobility FireGL V5200]</product> <vendor id='0x1002'>ATI Technologies Inc</vendor> <numa node='1'/> </capability> </device> """) with patch.dict(virt.os.__dict__, { "chmod": MagicMock(), "makedirs": MagicMock() }): with patch.dict(virt.__salt__, {"cmd.run": MagicMock()}): virt.init("test_vm", 2, 2048, host_devices=["pci_1002_71c4"], start=False) define_mock = virt.libvirt.openAuth().defineXML setxml = ET.fromstring(define_mock.call_args[0][0]) expected_xml = strip_xml(""" <hostdev mode='subsystem' type='pci' managed='yes'> <source> <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> """) assert expected_xml == strip_xml( ET.tostring(setxml.find("./devices/hostdev")))
def create_node(vm_): """ Build and submit the XML to create a node """ # Start the tree content = ET.Element("ve") # Name of the instance name = ET.SubElement(content, "name") name.text = vm_["name"] # Description, defaults to name desc = ET.SubElement(content, "description") desc.text = config.get_cloud_config_value( "desc", vm_, __opts__, default=vm_["name"], search_global=False ) # How many CPU cores, and how fast they are cpu = ET.SubElement(content, "cpu") cpu.attrib["number"] = config.get_cloud_config_value( "cpu_number", vm_, __opts__, default="1", search_global=False ) cpu.attrib["power"] = config.get_cloud_config_value( "cpu_power", vm_, __opts__, default="1000", search_global=False ) # How many megabytes of RAM ram = ET.SubElement(content, "ram-size") ram.text = config.get_cloud_config_value( "ram", vm_, __opts__, default="256", search_global=False ) # Bandwidth available, in kbps bandwidth = ET.SubElement(content, "bandwidth") bandwidth.text = config.get_cloud_config_value( "bandwidth", vm_, __opts__, default="100", search_global=False ) # How many public IPs will be assigned to this instance ip_num = ET.SubElement(content, "no-of-public-ip") ip_num.text = config.get_cloud_config_value( "ip_num", vm_, __opts__, default="1", search_global=False ) # Size of the instance disk disk = ET.SubElement(content, "ve-disk") disk.attrib["local"] = "true" disk.attrib["size"] = config.get_cloud_config_value( "disk_size", vm_, __opts__, default="10", search_global=False ) # Attributes for the image vm_image = config.get_cloud_config_value( "image", vm_, __opts__, search_global=False ) image = show_image({"image": vm_image}, call="function") platform = ET.SubElement(content, "platform") template = ET.SubElement(platform, "template-info") template.attrib["name"] = vm_image os_info = ET.SubElement(platform, "os-info") os_info.attrib["technology"] = image[vm_image]["technology"] os_info.attrib["type"] = image[vm_image]["osType"] # Username and password admin = ET.SubElement(content, "admin") admin.attrib["login"] = config.get_cloud_config_value( "ssh_username", vm_, __opts__, default="root" ) admin.attrib["password"] = config.get_cloud_config_value( "password", vm_, __opts__, search_global=False ) data = ET.tostring(content, encoding="UTF-8") __utils__["cloud.fire_event"]( "event", "requesting instance", "salt/cloud/{0}/requesting".format(vm_["name"]), args={ "kwargs": __utils__["cloud.filter_event"]("requesting", data, list(data)), }, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) node = query(action="ve", method="POST", data=data) return node
def create_node(vm_): ''' Build and submit the XML to create a node ''' # Start the tree content = ET.Element('ve') # Name of the instance name = ET.SubElement(content, 'name') name.text = vm_['name'] # Description, defaults to name desc = ET.SubElement(content, 'description') desc.text = config.get_cloud_config_value('desc', vm_, __opts__, default=vm_['name'], search_global=False) # How many CPU cores, and how fast they are cpu = ET.SubElement(content, 'cpu') cpu.attrib['number'] = config.get_cloud_config_value('cpu_number', vm_, __opts__, default='1', search_global=False) cpu.attrib['power'] = config.get_cloud_config_value('cpu_power', vm_, __opts__, default='1000', search_global=False) # How many megabytes of RAM ram = ET.SubElement(content, 'ram-size') ram.text = config.get_cloud_config_value('ram', vm_, __opts__, default='256', search_global=False) # Bandwidth available, in kbps bandwidth = ET.SubElement(content, 'bandwidth') bandwidth.text = config.get_cloud_config_value('bandwidth', vm_, __opts__, default='100', search_global=False) # How many public IPs will be assigned to this instance ip_num = ET.SubElement(content, 'no-of-public-ip') ip_num.text = config.get_cloud_config_value('ip_num', vm_, __opts__, default='1', search_global=False) # Size of the instance disk disk = ET.SubElement(content, 've-disk') disk.attrib['local'] = 'true' disk.attrib['size'] = config.get_cloud_config_value('disk_size', vm_, __opts__, default='10', search_global=False) # Attributes for the image vm_image = config.get_cloud_config_value('image', vm_, __opts__, search_global=False) image = show_image({'image': vm_image}, call='function') platform = ET.SubElement(content, 'platform') template = ET.SubElement(platform, 'template-info') template.attrib['name'] = vm_image os_info = ET.SubElement(platform, 'os-info') os_info.attrib['technology'] = image[vm_image]['technology'] os_info.attrib['type'] = image[vm_image]['osType'] # Username and password admin = ET.SubElement(content, 'admin') admin.attrib['login'] = config.get_cloud_config_value('ssh_username', vm_, __opts__, default='root') admin.attrib['password'] = config.get_cloud_config_value( 'password', vm_, __opts__, search_global=False) data = ET.tostring(content, encoding='UTF-8') salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), {'kwargs': data}, ) node = query(action='ve', method='POST', data=data) return node
def strip_xml(xml_str): """ Remove all spaces and formatting from an XML string """ return ET.tostring(xmlutil.strip_spaces(ET.fromstring(xml_str)))
def create_node(vm_): ''' Build and submit the XML to create a node ''' # Start the tree content = ET.Element('ve') # Name of the instance name = ET.SubElement(content, 'name') name.text = vm_['name'] # Description, defaults to name desc = ET.SubElement(content, 'description') desc.text = config.get_cloud_config_value( 'desc', vm_, __opts__, default=vm_['name'], search_global=False ) # How many CPU cores, and how fast they are cpu = ET.SubElement(content, 'cpu') cpu.attrib['number'] = config.get_cloud_config_value( 'cpu_number', vm_, __opts__, default='1', search_global=False ) cpu.attrib['power'] = config.get_cloud_config_value( 'cpu_power', vm_, __opts__, default='1000', search_global=False ) # How many megabytes of RAM ram = ET.SubElement(content, 'ram-size') ram.text = config.get_cloud_config_value( 'ram', vm_, __opts__, default='256', search_global=False ) # Bandwidth available, in kbps bandwidth = ET.SubElement(content, 'bandwidth') bandwidth.text = config.get_cloud_config_value( 'bandwidth', vm_, __opts__, default='100', search_global=False ) # How many public IPs will be assigned to this instance ip_num = ET.SubElement(content, 'no-of-public-ip') ip_num.text = config.get_cloud_config_value( 'ip_num', vm_, __opts__, default='1', search_global=False ) # Size of the instance disk disk = ET.SubElement(content, 've-disk') disk.attrib['local'] = 'true' disk.attrib['size'] = config.get_cloud_config_value( 'disk_size', vm_, __opts__, default='10', search_global=False ) # Attributes for the image vm_image = config.get_cloud_config_value( 'image', vm_, __opts__, search_global=False ) image = show_image({'image': vm_image}, call='function') platform = ET.SubElement(content, 'platform') template = ET.SubElement(platform, 'template-info') template.attrib['name'] = vm_image os_info = ET.SubElement(platform, 'os-info') os_info.attrib['technology'] = image[vm_image]['technology'] os_info.attrib['type'] = image[vm_image]['osType'] # Username and password admin = ET.SubElement(content, 'admin') admin.attrib['login'] = config.get_cloud_config_value( 'ssh_username', vm_, __opts__, default='root' ) admin.attrib['password'] = config.get_cloud_config_value( 'password', vm_, __opts__, search_global=False ) data = ET.tostring(content, encoding='UTF-8') salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), {'kwargs': data}, transport=__opts__['transport'] ) node = query(action='ve', method='POST', data=data) return node
def test_gen_xml_nat(): """ Test virt._get_net_xml() in a nat setup """ xml_data = virt._gen_net_xml( "network", "main", "nat", None, ip_configs=[ { "cidr": "192.168.2.0/24", "dhcp_ranges": [ { "start": "192.168.2.10", "end": "192.168.2.25" }, { "start": "192.168.2.110", "end": "192.168.2.125" }, ], "hosts": { "192.168.2.10": { "mac": "00:16:3e:77:e2:ed", "name": "foo.example.com", }, }, "bootp": { "file": "pxeboot.img", "server": "192.168.2.1" }, "tftp": "/path/to/tftp", }, { "cidr": "2001:db8:ca2:2::/64", "hosts": { "2001:db8:ca2:2:3::1": { "name": "paul" }, "2001:db8:ca2:2:3::2": { "id": "0:3:0:1:0:16:3e:11:22:33", "name": "ralph", }, }, }, ], nat={ "address": { "start": "1.2.3.4", "end": "1.2.3.10" }, "port": { "start": 500, "end": 1000 }, }, domain={ "name": "acme.lab", "localOnly": True }, mtu=9000, ) root = ET.fromstring(xml_data) assert "network" == root.find("name").text assert "main" == root.find("bridge").attrib["name"] assert "nat" == root.find("forward").attrib["mode"] expected_ipv4 = ET.fromstring(""" <ip family='ipv4' address='192.168.2.1' prefix='24'> <dhcp> <range start='192.168.2.10' end='192.168.2.25'/> <range start='192.168.2.110' end='192.168.2.125'/> <host ip='192.168.2.10' mac='00:16:3e:77:e2:ed' name='foo.example.com'/> <bootp file='pxeboot.img' server='192.168.2.1'/> </dhcp> <tftp root='/path/to/tftp'/> </ip> """) assert_xml_equals(expected_ipv4, root.find("./ip[@address='192.168.2.1']")) expected_ipv6 = ET.fromstring(""" <ip family='ipv6' address='2001:db8:ca2:2::1' prefix='64'> <dhcp> <host ip='2001:db8:ca2:2:3::1' name='paul'/> <host ip='2001:db8:ca2:2:3::2' id='0:3:0:1:0:16:3e:11:22:33' name='ralph'/> </dhcp> </ip> """) assert_xml_equals(expected_ipv6, root.find("./ip[@address='2001:db8:ca2:2::1']")) actual_nat = ET.tostring(xmlutil.strip_spaces(root.find("./forward/nat"))) expected_nat = strip_xml(""" <nat> <address start='1.2.3.4' end='1.2.3.10'/> <port start='500' end='1000'/> </nat> """) assert expected_nat == actual_nat assert { "name": "acme.lab", "localOnly": "yes" } == root.find("./domain").attrib assert "9000" == root.find("mtu").get("size")
def test_update_hostdev_changes(running, live, make_mock_device, make_mock_vm, test): """ Test the virt.update function with host device changes """ xml_def = """ <domain type='kvm'> <name>my_vm</name> <memory unit='KiB'>524288</memory> <currentMemory unit='KiB'>524288</currentMemory> <vcpu placement='static'>1</vcpu> <os> <type arch='x86_64'>hvm</type> </os> <on_reboot>restart</on_reboot> <devices> <hostdev mode='subsystem' type='pci' managed='yes'> <source> <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </hostdev> </devices> </domain>""" domain_mock = make_mock_vm(xml_def, running) make_mock_device(""" <device> <name>usb_3_1_3</name> <path>/sys/devices/pci0000:00/0000:00:1d.6/0000:06:00.0/0000:07:02.0/0000:3e:00.0/usb3/3-1/3-1.3</path> <devnode type='dev'>/dev/bus/usb/003/004</devnode> <parent>usb_3_1</parent> <driver> <name>usb</name> </driver> <capability type='usb_device'> <bus>3</bus> <device>4</device> <product id='0x6006'>AUKEY PC-LM1E Camera</product> <vendor id='0x0458'>KYE Systems Corp. (Mouse Systems)</vendor> </capability> </device> """) make_mock_device(""" <device> <name>pci_1002_71c4</name> <parent>pci_8086_27a1</parent> <capability type='pci'> <class>0xffffff</class> <domain>0</domain> <bus>1</bus> <slot>0</slot> <function>0</function> <product id='0x71c4'>M56GL [Mobility FireGL V5200]</product> <vendor id='0x1002'>ATI Technologies Inc</vendor> <numa node='1'/> </capability> </device> """) ret = virt.update("my_vm", host_devices=["usb_3_1_3"], test=test, live=live) define_mock = virt.libvirt.openAuth().defineXML assert_called(define_mock, not test) # Test that the XML is updated with the proper devices usb_device_xml = strip_xml(""" <hostdev mode="subsystem" type="usb"> <source> <vendor id="0x0458" /> <product id="0x6006" /> </source> </hostdev> """) if not test: set_xml = ET.fromstring(define_mock.call_args[0][0]) actual_hostdevs = [ ET.tostring(xmlutil.strip_spaces(node)) for node in set_xml.findall("./devices/hostdev") ] assert [usb_device_xml] == actual_hostdevs if not test and live: attach_xml = strip_xml(domain_mock.attachDevice.call_args[0][0]) assert usb_device_xml == attach_xml pci_device_xml = strip_xml(""" <hostdev mode='subsystem' type='pci' managed='yes'> <source> <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </hostdev> """) detach_xml = strip_xml(domain_mock.detachDevice.call_args[0][0]) assert pci_device_xml == detach_xml else: domain_mock.attachDevice.assert_not_called() domain_mock.detachDevice.assert_not_called()