def test_node_set_snapshot_current(self, mock_conn):
        xml_fuzzy = factories.fuzzy_string()
        xml = '''<domainsnapshot>
  <name>{0}</name>
  <domain>
    <cpu mode="host-model" />
  </domain>
</domainsnapshot>'''.format(xml_fuzzy)
        snapshot = mock.Mock()
        snapshot.getXMLDesc.return_value = xml
        domain = mock.Mock()
        domain.isActive.return_value = False
        domain.snapshotCreateXML.return_value = True
        domain.snapshotCurrent.return_value = snapshot
        domain.snapshotLookupByName.return_value = snapshot
        mock_conn.return_value.lookupByUUIDString.return_value = domain
        node = mock.Mock(uuid='test_node')
        snapshot_name = factories.fuzzy_string()

        dd = DevopsDriver()
        dd.node_set_snapshot_current(node, snapshot_name)

        domain.snapshotCreateXML.assert_called_with(
            xml, libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
            libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)
    def test_node_delete_snapshot_external_has_children(
            self, mock_conn, mock_delete_snapshot_files):
        snapshot_xml = '''<domainsnapshot>
  <memory snapshot="external"/>
  <domain>
    <cpu mode='host-model'/>
  </domain>
</domainsnapshot>'''
        snapshot = mock.Mock()
        snapshot.numChildren.return_value = 1
        snapshot.getXMLDesc.return_value = snapshot_xml
        snapshot.delete.return_value = True
        domain = mock.Mock()
        domain.isActive.return_value = False
        domain.snapshotCreateXML.return_value = True
        domain.snapshotCurrent.return_value = snapshot
        domain.snapshotLookupByName.return_value = snapshot
        mock_conn.return_value.lookupByUUIDString.return_value = domain
        node = mock.Mock(uuid='test_node')

        dd = DevopsDriver()
        dd.node_delete_snapshot(node, 'snapname')

        self.assertEqual(snapshot.numChildren.called, True)
        self.assertEqual(domain.isActive.called, False)
        self.assertEqual(snapshot.delete.called, False)
    def test_node_create_snapshot_external_domain_not_active(
            self, mock_conn, mock_os, mock_set_snapshot_current,
            mock_get_snapshots, mock_snapshot_exists, mock_snapshot_xml):
        mock_snapshot_exists.return_value = False
        mock_get_snapshots.return_value = [mock.Mock(get_type='external')]
        node = mock.Mock(uuid='test_node')
        mock_os.path.exists.return_value = False

        domain = mock.Mock()
        domain.isActive.return_value = False
        domain.snapshotCreateXML.return_value = True
        mock_conn.return_value.lookupByUUIDString.return_value = domain

        snapshot_name = factories.fuzzy_string()
        description = factories.fuzzy_string('description_')
        xml_fuzzy = factories.fuzzy_string()
        xml = '<{0}/>'.format(xml_fuzzy)
        mock_snapshot_xml.return_value = xml
        disk_only = False
        external = True

        dd = DevopsDriver()
        dd.node_create_snapshot(node, name=snapshot_name, disk_only=disk_only,
                                description=description, external=external)

        mock_snapshot_xml.assert_called_with(snapshot_name, description, node,
                                             disk_only, external, '/path/snap')
        self.assertEqual(mock_os.makedirs.called, True)
        self.assertEqual(domain.snapshotCreateXML.called, True)
        domain.snapshotCreateXML.assert_called_with(
            xml, libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
            libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT)
        mock_set_snapshot_current.assert_called_with(node, snapshot_name)
    def test_node_create_snapshot_if_exists(self, mock_conn,
                                            mock_snapshot_exists):
        mock_snapshot_exists.return_value = True
        mock_conn.return_value.lookupByUUIDString.return_value = mock.Mock()

        dd = DevopsDriver()
        dd.node_create_snapshot('node')

        self.assertEqual(mock_conn.lookupByUUIDString.called, False)
    def test_node_create_snapshot_external_if_internal_exists(
            self, mock_conn, mock_get_snapshots,
            mock_snapshot_exists, mock_snapshot_xml):
        mock_snapshot_exists.return_value = False
        mock_get_snapshots.return_value = [mock.Mock(get_type='internal')]
        mock_conn.return_value.lookupByUUIDString.return_value = mock.Mock()
        node = mock.Mock(uuid='test_node')

        dd = DevopsDriver()
        dd.node_create_snapshot(node, external=True)

        self.assertEqual(mock_snapshot_xml.called, False)
    def test_node_revert_snapshot_shutoff(
            self, mock_conn, mock_set_snapshot_current,
            mock_node_active, mock_node_destroy):
        snapshot_name = factories.fuzzy_string('name_')
        domain_name = factories.fuzzy_string('domain_')
        disk1_path = factories.fuzzy_string('/path/to/')
        snapshot1_path = factories.fuzzy_string('/path/to/')
        domain_xml_tmpl = '''  <domain>
    <name>{0}</name>
    <cpu mode='host-model'/>
    <devices>
      <disk type='file' device='disk' snapshot='external'>
        <driver name='qemu' type='raw'/>
        <source file='{1}'/>
        <target dev='vda' bus='virtio'/>
      </disk>
    </devices>
  </domain>'''
        domain_xml = domain_xml_tmpl.format(domain_name, disk1_path)
        snapshot_xml = '''<domainsnapshot>
  <name>{0}</name>
  <state>shutoff</state>
  <memory snapshot='no'/>
  <disks>
    <disk name='vda' snapshot='external'>
      <driver type='qcow2'/>
      <source file='{1}'/>
    </disk>
  </disks>
  {2}
</domainsnapshot>'''.format(snapshot_name, snapshot1_path, domain_xml)
        snapshot = mock.Mock()
        snapshot.numChildren.return_value = 0
        snapshot.getXMLDesc.return_value = snapshot_xml
        domain = mock.Mock()
        domain.snapshotCreateXML.return_value = True
        domain.snapshotCurrent.return_value = snapshot
        domain.snapshotLookupByName.return_value = snapshot
        mock_conn.return_value.lookupByUUIDString.return_value = domain
        node = mock.Mock(uuid='test_node')
        mock_node_active.return_value = False

        dd = DevopsDriver()
        dd.node_revert_snapshot(node, snapshot_name)

        domain_xml_expected = domain_xml_tmpl.format(domain_name,
                                                     snapshot1_path)

        self.assertEqual(mock_node_destroy.called, False)
        mock_conn().defineXML.assert_called_with(
            '{0}\n'.format(ET.tostring(ET.fromstring(domain_xml_expected))))
        mock_set_snapshot_current.assert_called_with(node, snapshot_name)
    def test_node_delete_snapshot_external(self, mock_conn,
                                           mock_delete_snapshot_files):
        domain_xml = '''<domain>
    <name>{0}</name>
    <cpu mode='host-model'/>
    <devices>
      <disk type='file' device='disk' snapshot='external'>
        <driver name='qemu' type='raw'/>
        <source file='{1}'/>
        <target dev='vda' bus='virtio'/>
      </disk>
      <disk type='file' device='disk' snapshot='external'>
        <driver name='qemu' type='raw'/>
        <source file='{2}'/>
        <target dev='vdb' bus='virtio'/>
      </disk>
    </devices>
  </domain>'''.format(factories.fuzzy_string('name_'),
                      factories.fuzzy_string('/path/to/'),
                      factories.fuzzy_string('/path/to/'))
        snapshot_xml = '''<domainsnapshot>
  <memory snapshot="external"/>
  <disks/>
  {0}
</domainsnapshot>'''.format(domain_xml)
        snapshot = mock.Mock()
        snapshot.numChildren.return_value = 0
        snapshot.getXMLDesc.return_value = snapshot_xml
        snapshot.delete.return_value = True
        domain = mock.Mock()
        domain.isActive.return_value = True
        domain.snapshotCreateXML.return_value = True
        domain.snapshotCurrent.return_value = snapshot
        domain.snapshotLookupByName.return_value = snapshot
        mock_conn.return_value.lookupByUUIDString.return_value = domain
        mock_conn.return_value.defineXML.return_value = True
        node = mock.Mock(uuid='test_node')

        dd = DevopsDriver()
        dd.node_delete_snapshot(node, 'snapname')

        self.assertEqual(domain.destroy.called, True)
        mock_delete_snapshot_files.assert_called_with(snapshot)
        snapshot.delete.assert_called_with(2)
        mock_conn().defineXML.assert_called_with(
            '{0}\n'.format(ET.tostring(ET.fromstring(domain_xml))))
    def test_delete_snapshot_files_internal(self, mock_os, mock_conn):
        mock_os.path.isfile.return_value = True
        mock_os.remove.return_value = True

        snapshot_xml = '''<domainsnapshot>
  <memory snapshot="internal"/>
  <domain>
    <cpu mode='host-model'/>
  </domain>
</domainsnapshot>'''
        snapshot = mock.Mock()
        snapshot.getXMLDesc.return_value = snapshot_xml

        dd = DevopsDriver()
        dd._delete_snapshot_files(snapshot)

        self.assertEqual(mock_os.remove.called, False)
    def test_delete_snapshot_files(self, mock_os, mock_conn):
        mock_os.path.isfile.return_value = True
        mock_os.remove.return_value = True

        memory_file = factories.fuzzy_string('/path/to/')
        snapshot_xml = '''<domainsnapshot>
  <memory file="{0}" snapshot="external"/>
  <domain>
    <cpu mode='host-model'/>
  </domain>
</domainsnapshot>'''.format(memory_file)
        snapshot = mock.Mock()
        snapshot.getXMLDesc.return_value = snapshot_xml

        dd = DevopsDriver()
        dd._delete_snapshot_files(snapshot)

        mock_os.remove.assert_called_with(memory_file)
    def test_node_set_snapshot_current_host_passthrough(self, mock_conn):
        xml_fuzzy = factories.fuzzy_string()
        cpu_model = factories.fuzzy_string()
        domain_cpu = '''<cpu mode="host-passthrough">
<model>{0}</model>
<vendor>Intel</vendor>
</cpu>'''.format(cpu_model)
        domain_xml = '''<domain>
{0}
</domain>'''.format(domain_cpu)
        snapshot_cpu = '<cpu mode="host-passthrough" />'
        snapshot_xml_tmpl = '''<domainsnapshot>
<name>{0}</name>
<domain>
{1}
</domain>
</domainsnapshot>'''
        snapshot_xml = snapshot_xml_tmpl.format(xml_fuzzy, snapshot_cpu)
        snapshot = mock.Mock()
        snapshot.getXMLDesc.return_value = snapshot_xml
        domain = mock.Mock()
        domain.isActive.return_value = False
        domain.snapshotCreateXML.return_value = True
        domain.snapshotCurrent.return_value = snapshot
        domain.snapshotLookupByName.return_value = snapshot
        domain.XMLDesc.return_value = domain_xml
        mock_conn.return_value.lookupByUUIDString.return_value = domain
        snapshot.getDomain.return_value = domain
        node = mock.Mock(uuid='test_node')
        snapshot_name = factories.fuzzy_string()

        dd = DevopsDriver()
        dd.node_set_snapshot_current(node, snapshot_name)

        domain.snapshotCreateXML.assert_called_with(
            snapshot_xml_tmpl.format(xml_fuzzy, domain_cpu),
            libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
            libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)
    def test_node_revert_snapshot_recreate_disks_has_children(self, mock_conn):
        snapshot_xml = '''<domainsnapshot>
  <memory snapshot="external"/>
  <domain>
    <cpu mode='host-model'/>
  </domain>
</domainsnapshot>'''
        snapshot = mock.Mock()
        snapshot.children_num = 1
        snapshot.getXMLDesc.return_value = snapshot_xml
        domain = mock.Mock()
        domain.isActive.return_value = True
        domain.snapshotCreateXML.return_value = True
        domain.snapshotCurrent.return_value = snapshot
        domain.snapshotLookupByName.return_value = snapshot
        mock_conn.return_value.lookupByUUIDString.return_value = domain
        mock_conn.return_value.storageVolLookupByKey.return_value = mock.Mock()
        node = mock.Mock(uuid='test_node')

        dd = DevopsDriver()
        dd.node_revert_snapshot_recreate_disks(node, 'snapname')

        self.assertEqual(mock_conn.storageVolLookupByKey.called, False)
    def test_node_revert_snapshot_internal(self, mock_conn,
                                           mock_set_snapshot_current):
        snapshot_xml = '''<domainsnapshot>
  <state>running</state>
  <memory snapshot="internal"/>
  <disks/>
  <domain>
    <cpu mode='host-model'/>
  </domain>
</domainsnapshot>'''
        snapshot = mock.Mock()
        snapshot.getXMLDesc.return_value = snapshot_xml
        domain = mock.Mock()
        domain.snapshotCreateXML.return_value = True
        domain.snapshotCurrent.return_value = snapshot
        domain.snapshotLookupByName.return_value = snapshot
        mock_conn.return_value.lookupByUUIDString.return_value = domain
        node = mock.Mock(uuid='test_node')

        dd = DevopsDriver()
        dd.node_revert_snapshot(node, 'snapname')

        self.assertEqual(mock_set_snapshot_current.called, False)
        domain.revertToSnapshot.assert_called_with(snapshot, 0)
    def test_node_revert_snapshot_has_children(
            self, mock_conn, mock_set_snapshot_current,
            mock_node_active, mock_node_destroy):
        snapshot_name = factories.fuzzy_string('name_')
        domain_name = factories.fuzzy_string('domain_')
        memory_snapshot_path = factories.fuzzy_string('/path/to/')
        disk1_path = factories.fuzzy_string('/path/to/')
        disk2_path = factories.fuzzy_string('/path/to/')
        snapshot1_path = factories.fuzzy_string('/path/to/')
        snapshot2_path = factories.fuzzy_string('/path/to/')
        domain_xml_tmpl = '''  <domain>
    <name>{0}</name>
    <cpu mode='host-model'/>
    <devices>
      <disk type='file' device='disk' snapshot='external'>
        <driver name='qemu' type='raw'/>
        <source file='{1}'/>
        <target dev='vda' bus='virtio'/>
      </disk>
      <disk type='file' device='disk' snapshot='external'>
        <driver name='qemu' type='raw'/>
        <source file='{2}'/>
        <target dev='vdb' bus='virtio'/>
      </disk>
    </devices>
  </domain>'''
        domain_xml = domain_xml_tmpl.format(
            domain_name, disk1_path, disk2_path)
        snapshot_xml = '''<domainsnapshot>
  <name>{0}</name>
  <description>Snapshot of OS install and updates</description>
  <state>running</state>
  <creationTime>1270477159</creationTime>
  <parent>
    <name>bare-os-install</name>
  </parent>
  <memory file='{1}' snapshot='external'/>
  <disks>
    <disk name='vda' snapshot='external'>
      <driver type='qcow2'/>
      <source file='{2}'/>
    </disk>
    <disk name='vdb' snapshot='external'>
      <driver type='qcow2'/>
      <source file='{3}'/>
    </disk>
  </disks>
  {4}
</domainsnapshot>'''.format(snapshot_name, memory_snapshot_path,
                            snapshot1_path, snapshot2_path, domain_xml)
        snapshot = mock.Mock()
        snapshot.numChildren.return_value = 1
        snapshot.getXMLDesc.return_value = snapshot_xml
        domain = mock.Mock()
        domain.isActive.return_value = True
        domain.snapshotCreateXML.return_value = True
        domain.snapshotCurrent.return_value = snapshot
        domain.snapshotLookupByName.return_value = snapshot
        mock_conn.return_value.lookupByUUIDString.return_value = domain
        node = mock.Mock(uuid='test_node')
        mock_node_active.return_value = True

        dd = DevopsDriver()
        dd.node_revert_snapshot(node, snapshot_name)

        mock_node_destroy.assert_called_with(node)
        mock_conn().restoreFlags.assert_called_with(
            memory_snapshot_path,
            dxml='{0}\n'.format(ET.tostring(ET.fromstring(domain_xml))),
            flags=libvirt.VIR_DOMAIN_SAVE_PAUSED)
        mock_set_snapshot_current.assert_called_with(node, snapshot_name)
    def test_node_revert_snapshot_recreate_disks(self, mock_conn):
        disk1_file = factories.fuzzy_string('/var/lib/libvirt/images/')
        disk2_file = factories.fuzzy_string('/var/lib/libvirt/images/')
        snapshot_xml = '''<domainsnapshot>
  <memory snapshot="no"/>
  <disks>
    <disk name='vda' snapshot='external'>
      <source file='{0}'/>
    </disk>
    <disk name='vdb' snapshot='external'>
      <source file='{1}'/>
    </disk>
  </disks>
  <domain>
    <cpu mode='host-model'/>
  </domain>
</domainsnapshot>'''.format(disk1_file, disk2_file)
        snapshot = mock.Mock()
        snapshot.getXMLDesc.return_value = snapshot_xml
        snapshot.numChildren.return_value = 0

        domain = mock.Mock()
        domain.isActive.return_value = True
        domain.snapshotCreateXML.return_value = True
        domain.snapshotCurrent.return_value = False
        domain.snapshotLookupByName.return_value = snapshot
        mock_conn.return_value.lookupByUUIDString.return_value = domain

        pool = mock.Mock()
        pool.createXML.return_value = mock.Mock()

        def define_volume(*args):
            volume_xml = '<{0}/>'.format(args[0])
            volume = mock.Mock()
            volume.XMLDesc.return_value = volume_xml
            volume.storagePoolLookupByVolume.return_value = pool
            volume.detele.return_value = True
            return volume

        volume1 = define_volume(disk1_file)
        volume2 = define_volume(disk2_file)

        def return_volume(*args):
            if args[0] == disk1_file:
                return volume1
            elif args[0] == disk2_file:
                return volume2

        mock_conn.return_value.storageVolLookupByKey.side_effect = \
            return_volume
        node = mock.Mock(uuid='test_node')

        dd = DevopsDriver()
        dd.node_revert_snapshot_recreate_disks(node, 'snapname')

        self.assertEqual(volume1.delete.called, True)
        self.assertEqual(volume2.delete.called, True)
        mock_conn().storageVolLookupByKey.assert_has_calls(
            [mock.call(disk1_file), mock.call(disk2_file)],
            any_order=True)
        pool.createXML.assert_has_calls(
            [mock.call(volume1.XMLDesc()),
                mock.call(volume2.XMLDesc())],
            any_order=True)