diff -Nru landscape-client-16.03/debian/changelog landscape-client-16.03/debian/changelog --- landscape-client-16.03/debian/changelog 2018-01-23 16:21:35.000000000 +0000 +++ landscape-client-16.03/debian/changelog 2018-03-26 21:36:50.000000000 +0000 @@ -1,3 +1,10 @@ +landscape-client (16.03-0ubuntu3.17.10.3) artful; urgency=medium + + * debian/patches/detect-cloudstack-kvm-1754073.diff: Detect CloudStack + kvm hypervisor (LP: #1754073) + + -- Simon Poirier Mon, 26 Mar 2018 21:36:50 +0000 + landscape-client (16.03-0ubuntu3.17.10.2) artful; urgency=medium * d/p/set-vm-info-to-kvm-for-aws-C5-instances.patch: diff -Nru landscape-client-16.03/debian/patches/detect-cloudstack-kvm-1754073.diff landscape-client-16.03/debian/patches/detect-cloudstack-kvm-1754073.diff --- landscape-client-16.03/debian/patches/detect-cloudstack-kvm-1754073.diff 1970-01-01 00:00:00.000000000 +0000 +++ landscape-client-16.03/debian/patches/detect-cloudstack-kvm-1754073.diff 2018-03-26 21:36:10.000000000 +0000 @@ -0,0 +1,166 @@ +Description: Detect ApacheCloudstack KVM instances + Extend vm_info detection to other dmi fields. + Scan sys, bios and chassis DMI to detect hypervisor (LP: #1754073) +Author: Simon Poirier +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1754073 +Origin: backport, https://github.com/CanonicalLtd/landscape-client/commit/e08cd1ac06b0c2e1761749e05e10593a4b123317 +Last-Update: 2018-03-26 + +--- a/landscape/lib/tests/test_vm_info.py ++++ b/landscape/lib/tests/test_vm_info.py +@@ -15,11 +15,12 @@ + self.proc_sys_path = self.makeDir( + path=os.path.join(self.proc_path, "sys")) + +- def make_sys_vendor(self, content): +- """Create /sys/class/dmi/id/sys_vendor with the specified content.""" ++ def make_dmi_info(self, name, content): ++ """Create /sys/class/dmi/id/ with the specified content.""" + dmi_path = os.path.join(self.root_path, "sys/class/dmi/id") +- self.makeDir(path=dmi_path) +- self.makeFile(dirname=dmi_path, basename="sys_vendor", content=content) ++ if not os.path.exists(dmi_path): ++ self.makeDir(path=dmi_path) ++ self.makeFile(dirname=dmi_path, basename=name, content=content) + + def test_get_vm_info_empty_when_no_virtualization_is_found(self): + """ +@@ -81,14 +82,32 @@ + get_vm_info should return "kvm" when sys_vendor is "Amazon EC2", + which is the case for C5 instances which are based on KVM. + """ +- self.make_sys_vendor("Amazon EC2") ++ self.make_dmi_info("sys_vendor", "Amazon EC2") + self.assertEqual("kvm", get_vm_info(root_path=self.root_path)) + + def test_get_vm_info_with_digitalocean_sys_vendor(self): + """ + get_vm_info should return "kvm" when sys_vendor is "DigitalOcean". + """ +- self.make_sys_vendor("DigitalOcean") ++ self.make_dmi_info("sys_vendor", "DigitalOcean") ++ self.assertEqual(b"kvm", get_vm_info(root_path=self.root_path)) ++ ++ def test_get_vm_info_with_kvm_bios_vendor(self): ++ """ ++ get_vm_info should return "kvm" when bios_vendor maps to kvm. ++ """ ++ # DigitalOcean is known to set the bios_vendor on their instances. ++ self.make_dmi_info("bios_vendor", "DigitalOcean") ++ self.assertEqual(b"kvm", get_vm_info(root_path=self.root_path)) ++ ++ def test_get_vm_info_with_bochs_chassis_vendor(self): ++ """ ++ get_vm_info should return "kvm" when chassis_vendor is "Bochs". ++ """ ++ # DigitalOcean, AWS and Cloudstack are known to customize sys_vendor ++ # and/or bios_vendor. ++ self.make_dmi_info("sys_vendor", "Apache Software Foundation") ++ self.make_dmi_info("chassis_vendor", "Bochs") + self.assertEqual("kvm", get_vm_info(root_path=self.root_path)) + + def test_get_vm_info_with_bochs_sys_vendor(self): +@@ -96,7 +115,7 @@ + L{get_vm_info} should return "kvm" when we detect the sys_vendor is + Bochs. + """ +- self.make_sys_vendor("Bochs") ++ self.make_dmi_info("sys_vendor", "Bochs") + self.assertEqual("kvm", get_vm_info(root_path=self.root_path)) + + def test_get_vm_info_with_openstack_sys_vendor(self): +@@ -104,7 +123,7 @@ + L{get_vm_info} should return "kvm" when we detect the sys_vendor is + Openstack. + """ +- self.make_sys_vendor("OpenStack Foundation") ++ self.make_dmi_info("sys_vendor", "OpenStack Foundation") + self.assertEqual("kvm", get_vm_info(root_path=self.root_path)) + + def test_get_vm_info_with_qemu_sys_vendor(self): +@@ -112,7 +131,7 @@ + L{get_vm_info} should return "kvm" when we detect the sys_vendor is + QEMU. + """ +- self.make_sys_vendor("QEMU") ++ self.make_dmi_info("sys_vendor", "QEMU") + self.assertEqual("kvm", get_vm_info(root_path=self.root_path)) + + def test_get_vm_info_with_vmware_sys_vendor(self): +@@ -120,7 +139,7 @@ + L{get_vm_info} should return "vmware" when we detect the sys_vendor is + VMware Inc. + """ +- self.make_sys_vendor("VMware, Inc.") ++ self.make_dmi_info("sys_vendor", "VMware, Inc.") + self.assertEqual("vmware", get_vm_info(root_path=self.root_path)) + + def test_get_vm_info_with_virtualbox_sys_vendor(self): +@@ -128,28 +147,28 @@ + L{get_vm_info} should return "virtualbox" when we detect the sys_vendor + is innotek. GmbH. + """ +- self.make_sys_vendor("innotek GmbH") ++ self.make_dmi_info("sys_vendor", "innotek GmbH") + self.assertEqual("virtualbox", get_vm_info(root_path=self.root_path)) + + def test_get_vm_info_with_microsoft_sys_vendor(self): + """ + L{get_vm_info} returns "hyperv" if the sys_vendor is Microsoft. + """ +- self.make_sys_vendor("Microsoft Corporation") ++ self.make_dmi_info("sys_vendor", "Microsoft Corporation") + self.assertEqual("hyperv", get_vm_info(root_path=self.root_path)) + + def test_get_vm_info_with_google_sys_vendor(self): + """ + L{get_vm_info} returns "gce" if the sys_vendor is Google. + """ +- self.make_sys_vendor("Google") ++ self.make_dmi_info("sys_vendor", "Google") + self.assertEqual("gce", get_vm_info(root_path=self.root_path)) + + def test_get_vm_info_matches_insensitive(self): + """ + L{get_vm_info} matches the vendor string in a case-insentive way. + """ +- self.make_sys_vendor("openstack foundation") ++ self.make_dmi_info("sys_vendor", "openstack foundation") + self.assertEqual("kvm", get_vm_info(root_path=self.root_path)) + + def test_get_vm_info_with_kvm_on_other_architecture(self): +@@ -170,7 +189,7 @@ + L{get_vm_info} should return an empty string when the sys_vendor is + unknown. + """ +- self.make_sys_vendor("Some other vendor") ++ self.make_dmi_info("sys_vendor", "Some other vendor") + self.assertEqual("", get_vm_info(root_path=self.root_path)) + + +--- a/landscape/lib/vm_info.py ++++ b/landscape/lib/vm_info.py +@@ -22,11 +22,18 @@ + if _is_vm_xen(root_path): + return "xen" + +- sys_vendor_path = os.path.join(root_path, "sys/class/dmi/id/sys_vendor") +- if os.path.exists(sys_vendor_path): +- return _get_vm_by_vendor(sys_vendor_path) +- else: +- return _get_vm_legacy(root_path) ++ # Iterate through all dmi *_vendors, as clouds can (and will) customize ++ # sysinfo values. (https://libvirt.org/formatdomain.html#elementsSysinfo) ++ dmi_info_path = os.path.join(root_path, "sys/class/dmi/id") ++ for dmi_info_file in ("sys_vendor", "chassis_vendor", "bios_vendor"): ++ dmi_vendor_path = os.path.join(dmi_info_path, dmi_info_file) ++ if not os.path.exists(dmi_vendor_path): ++ continue ++ vendor = _get_vm_by_vendor(dmi_vendor_path) ++ if vendor: ++ return vendor ++ ++ return _get_vm_legacy(root_path) + + + def get_container_info(run_path="/run"): diff -Nru landscape-client-16.03/debian/patches/series landscape-client-16.03/debian/patches/series --- landscape-client-16.03/debian/patches/series 2018-01-23 15:49:18.000000000 +0000 +++ landscape-client-16.03/debian/patches/series 2018-03-26 21:36:10.000000000 +0000 @@ -6,3 +6,4 @@ config-no-reregister-1618483.diff set-vm-info-to-kvm-for-aws-C5-instances.patch set-vm-info-to-kvm-for-digitalocean-instances.patch +detect-cloudstack-kvm-1754073.diff