From 23268be5a8200269c472f03dbb8458caf215bbe8 Mon Sep 17 00:00:00 2001
From: Kevin Howell <khowell@redhat.com>
Date: Fri, 18 Oct 2019 09:54:54 -0400
Subject: [PATCH] Remove AHV support
---
tests/test_ahv.py | 566 ---------------------
virtwho/config.py | 4 +-
virtwho/parser.py | 4 +-
virtwho/virt/ahv/__init__.py | 6 -
virtwho/virt/ahv/ahv.py | 258 ----------
virtwho/virt/ahv/ahv_constants.py | 21 -
virtwho/virt/ahv/ahv_interface.py | 804 ------------------------------
virtwho/virt/virt.py | 1 -
8 files changed, 3 insertions(+), 1661 deletions(-)
delete mode 100644 tests/test_ahv.py
delete mode 100644 virtwho/virt/ahv/__init__.py
delete mode 100644 virtwho/virt/ahv/ahv.py
delete mode 100644 virtwho/virt/ahv/ahv_constants.py
delete mode 100644 virtwho/virt/ahv/ahv_interface.py
diff --git a/tests/test_ahv.py b/tests/test_ahv.py
deleted file mode 100644
index d8ccbc8..0000000
--- a/tests/test_ahv.py
+++ /dev/null
@@ -1,566 +0,0 @@
-from __future__ import print_function
-
-import six
-
-from base import TestBase
-from mock import patch, call, ANY, MagicMock
-from requests import Session
-from six.moves.queue import Queue
-from threading import Event
-
-from virtwho import DefaultInterval
-from virtwho.datastore import Datastore
-from virtwho.virt.ahv.ahv import AhvConfigSection
-from virtwho.virt import Virt, VirtError, Guest, Hypervisor
-
-
-
-MY_SECTION_NAME = 'test-ahv'
-DefaultUpdateInterval = 1800
-# Values used for testing AhvConfigSection.
-PE_SECTION_VALUES = {
- 'type': 'ahv',
- 'server': '10.10.10.10',
- 'username': 'root',
- 'password': 'root_password',
- 'owner': 'nutanix',
- 'hypervisor_id': 'uuid',
- 'is_hypervisor': True,
- 'internal_debug': False,
- 'update_interval': 60
-}
-
-HOST_UVM_MAP = \
- {u'08469de5-be42-43e6-8c32-20167d3b58f7':
- {u'oplog_disk_pct': 3.4,
- u'memory_capacity_in_bytes': 135009402880,
- u'has_csr': False,
- u'default_vm_storage_container_uuid': None,
- u'hypervisor_username': u'root',
- u'key_management_device_to_certificate_status': {},
- u'service_vmnat_ip': None,
- u'hypervisor_key': u'10.53.97.188',
- u'acropolis_connection_state': u'kConnected',
- u'management_server_name': u'10.53.97.188',
- u'failover_cluster_fqdn': None,
- u'serial': u'OM155S016008',
- u'bmc_version': u'01.92',
- u'hba_firmwares_list':
- [{u'hba_model': u'LSI Logic SAS3008',
- u'hba_version': u'MPTFW-06.00.00.00-IT'}],
- u'hypervisor_state': u'kAcropolisNormal',
- u'num_cpu_threads': 32,
- u'monitored': True,
- u'uuid': u'08469de5-be42-43e6-8c32-20167d3b58f7',
- u'reboot_pending': False,
- u'cpu_capacity_in_hz': 38384000000,
- u'num_cpu_sockets': 2,
- u'host_maintenance_mode_reason': None,
- u'hypervisor_address': u'10.53.97.188',
- u'host_gpus': None,
- u'failover_cluster_node_state': None,
- u'state': u'NORMAL',
- u'num_cpu_cores': 16,
- 'guest_list':
- [{u'vm_features':
- {u'AGENT_VM': False,
- u'VGA_CONSOLE': True},
- u'name': u'am2', u'num_cores_per_vcpu': 1,
- u'gpus_assigned': False, u'num_vcpus': 2,
- u'memory_mb': 4096,
- u'power_state': u'on',
- u'ha_priority': 0,
- u'allow_live_migrate': True,
- u'timezone': u'America/Los_Angeles',
- u'vm_logical_timestamp': 48,
- u'host_uuid': u'08469de5-be42-43e6-8c32-20167d3b58f7',
- u'uuid': u'01dcfc0b-3092-4f1b-94fb-81b44ed352be'},
- {u'vm_features':
- {u'AGENT_VM': False, u'VGA_CONSOLE': True},
- u'name': u'am3',
- u'num_cores_per_vcpu': 1,
- u'gpus_assigned': False,
- u'num_vcpus': 2, u'memory_mb': 4096,
- u'power_state': u'on',
- u'ha_priority': 0,
- u'allow_live_migrate': True,
- u'timezone': u'America/Los_Angeles',
- u'vm_logical_timestamp': 3,
- u'host_uuid': u'08469de5-be42-43e6-8c32-20167d3b58f7',
- u'uuid': u'422f9171-db1f-48b0-a3de-b0bb92a8f559'},
- {u'vm_features':
- {u'AGENT_VM': False,
- u'VGA_CONSOLE': True},
- u'name': u'win_vm',
- u'num_cores_per_vcpu': 1,
- u'gpus_assigned': False,
- u'num_vcpus': 2,
- u'memory_mb': 4096,
- u'power_state': u'on',
- u'ha_priority': 0,
- u'allow_live_migrate': True,
- u'timezone': u'America/Los_Angeles',
- u'vm_logical_timestamp': 3,
- u'host_uuid': u'08469de5-be42-43e6-8c32-20167d3b58f7',
- u'uuid': u'98839f35-bd62-4255-a7cd-7668bc143554'}],
- u'cpu_model': u'Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz',
- u'ipmi_username': u'ADMIN',
- u'service_vmid': u'0005809e-62e4-75c7-611b-0cc47ac3b354::7',
- u'bmc_model': u'X10_ATEN',
- u'host_nic_ids': [],
- u'cluster_uuid': u'0005809e-62e4-75c7-611b-0cc47ac3b354',
- u'ipmi_password': None,
- u'cpu_frequency_in_hz': 2399000000,
- u'stats':
- {u'num_read_io': u'8',
- u'controller_read_io_bandwidth_kBps': u'0',
- u'content_cache_hit_ppm': u'1000000',
- },
- u'num_vms': 4, u'default_vm_storage_container_id': None,
- u'metadata_store_status': u'kNormalMode',
- u'name': u'foyt-4', u'hypervisor_password': None,
- u'service_vmnat_port': None,
- u'hypervisor_full_name': u'Nutanix 20180802.100874',
- u'is_degraded': False, u'host_type': u'HYPER_CONVERGED',
- u'default_vhd_storage_container_uuid': None,
- u'block_serial': u'15SM60250038',
- u'disk_hardware_configs':
- {u'1':
- {
- u'mount_path': u'/home/nutanix/data/stargate-storage/disks/BTHC506101XL480MGN',
- },
- u'3':
- {
- u'mount_path': u'/home/nutanix/data/stargate-storage/disks/9XG8E6QE',
- },
- u'2':
- {
- u'mount_path': u'/home/nutanix/data/stargate-storage/disks/BTHC50610246480MGN',
- },
- u'5':
- {
- u'mount_path': u'/home/nutanix/data/stargate-storage/disks/9XG8E835',
- },
- u'4': {
- u'mount_path': u'/home/nutanix/data/stargate-storage/disks/9XG8E8B1',
- },
- u'6': {
- u'mount_path': u'/home/nutanix/data/stargate-storage/disks/9XG8E7B3',
- }},
- u'ipmi_address': u'10.49.27.28', u'bios_model': u'0824',
- u'default_vm_location': None, u'hypervisor_type': u'kKvm',
- u'service_vmexternal_ip': u'10.53.97.192',
- u'controller_vm_backplane_ip': u'10.53.97.192'},
- u'54830446-b55e-4f16-aa74-7b6a9ac9a7a4':
- {u'oplog_disk_pct': 3.4,
- u'memory_capacity_in_bytes': 135009402880, u'has_csr': False,
- u'default_vm_storage_container_uuid': None,
- u'hypervisor_username': u'root',
- u'service_vmnat_ip': None, u'hypervisor_key': u'10.53.97.187',
- u'acropolis_connection_state': u'kConnected',
- u'hypervisor_state': u'kAcropolisNormal',
- u'num_cpu_threads': 32, u'monitored': True,
- u'uuid': u'54830446-b55e-4f16-aa74-7b6a9ac9a7a4',
- u'reboot_pending': False, u'cpu_capacity_in_hz': 38384000000,
- u'num_cpu_sockets': 2, u'host_maintenance_mode_reason': None,
- u'hypervisor_address': u'10.53.97.187', u'host_gpus': None,
- u'failover_cluster_node_state': None, u'state': u'NORMAL',
- u'num_cpu_cores': 16, u'block_model': u'UseLayout',
- 'guest_list':
- [{u'vm_features':
- {u'AGENT_VM': False, u'VGA_CONSOLE': True},
- u'name': u'PC', u'num_cores_per_vcpu': 1,
- u'gpus_assigned': False, u'num_vcpus': 4,
- u'memory_mb': 16384, u'power_state': u'on',
- u'ha_priority': 0, u'allow_live_migrate': True,
- u'timezone': u'UTC', u'vm_logical_timestamp': 10,
- u'host_uuid': u'54830446-b55e-4f16-aa74-7b6a9ac9a7a4',
- u'uuid': u'd90b5443-97f0-47eb-986d-f14e062448d4'},
- {u'vm_features':
- {u'AGENT_VM': False, u'VGA_CONSOLE': True},
- u'name': u'am1', u'num_cores_per_vcpu': 1,
- u'gpus_assigned': False, u'num_vcpus': 2,
- u'memory_mb': 4096, u'power_state': u'on',
- u'ha_priority': 0, u'allow_live_migrate': True,
- u'timezone': u'America/Los_Angeles',
- u'vm_logical_timestamp': 14,
- u'host_uuid': u'54830446-b55e-4f16-aa74-7b6a9ac9a7a4',
- u'uuid': u'0af0a010-0ad0-4fba-aa33-7cc3d0b6cb7e'}],
- u'cpu_model': u'Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz',
- u'ipmi_username': u'ADMIN',
- u'service_vmid': u'0005809e-62e4-75c7-611b-0cc47ac3b354::6',
- u'bmc_model': u'X10_ATEN', u'host_nic_ids': [],
- u'cluster_uuid': u'0005809e-62e4-75c7-611b-0cc47ac3b354',
- u'stats':
- {u'num_read_io': u'27',
- u'controller_read_io_bandwidth_kBps': u'0',
- u'content_cache_hit_ppm': u'1000000',
- }, u'backplane_ip': None,
- u'vzone_name': u'', u'default_vhd_location': None,
- u'metadata_store_status_message': u'Metadata store enabled on the node',
- u'num_vms': 3, u'default_vm_storage_container_id': None,
- u'metadata_store_status': u'kNormalMode', u'name': u'foyt-3',
- u'hypervisor_password': None, u'service_vmnat_port': None,
- u'hypervisor_full_name': u'Nutanix 20180802.100874',
- u'is_degraded': False, u'host_type': u'HYPER_CONVERGED',
- u'default_vhd_storage_container_uuid': None,
- u'block_serial': u'15SM60250038',
- u'disk_hardware_configs':
- {u'1':
- {
- u'mount_path': u'/home/nutanix/data/stargate-storage/disks/BTHC506101ST480MGN',
- },
- u'3':
- {
- u'mount_path': u'/home/nutanix/data/stargate-storage/disks/9XG8DXYY',
- },
- u'2': {
- u'mount_path': u'/home/nutanix/data/stargate-storage/disks/BTHC506101D4480MGN',
- },
- u'5': {
- u'mount_path': u'/home/nutanix/data/stargate-storage/disks/9XG8DQRM',
- },
- u'4': {
- u'mount_path': u'/home/nutanix/data/stargate-storage/disks/9XG8DJ7E',
- },
- u'6': {
- u'mount_path': u'/home/nutanix/data/stargate-storage/disks/9XG8DVGG',
- }},
- u'ipmi_address': u'10.49.27.27', u'bios_model': u'0824',
- u'hypervisor_type': u'kKvm',
- u'service_vmexternal_ip': u'10.53.97.191',
- u'controller_vm_backplane_ip': u'10.53.97.191'
- },
- u'acc819fe-e0ff-4963-93a4-5a0e1d3c77d3':
- {u'oplog_disk_pct': 3.4,
- u'memory_capacity_in_bytes': 270302969856, u'has_csr': False,
- u'default_vm_storage_container_uuid': None,
- u'hypervisor_username': u'root',
- u'key_management_device_to_certificate_status': {},
- u'service_vmnat_ip': None, u'hypervisor_key': u'10.53.96.75',
- u'acropolis_connection_state': u'kConnected',
- u'management_server_name': u'10.53.96.75',
- u'failover_cluster_fqdn': None, u'serial': u'ZM162S002621',
- u'bmc_version': u'01.97',
- u'hba_firmwares_list':
- [{u'hba_model': u'LSI Logic SAS3008',
- u'hba_version': u'MPTFW-10.00.03.00-IT'}],
- u'hypervisor_state': u'kAcropolisNormal',
- u'num_cpu_threads': 32, u'monitored': True,
- u'uuid': u'acc819fe-e0ff-4963-93a4-5a0e1d3c77d3',
- u'num_cpu_sockets': 2, u'host_maintenance_mode_reason': None,
- u'hypervisor_address': u'10.53.96.75',
- 'guest_list':
- [{u'vm_features': {u'AGENT_VM': False, u'VGA_CONSOLE': True},
- u'name': u'am_RH_satellite', u'num_cores_per_vcpu': 2,
- u'gpus_assigned': False, u'num_vcpus': 4, u'memory_mb': 16384,
- u'power_state': u'on', u'ha_priority': 0,
- u'allow_live_migrate': True, u'timezone': u'America/Los_Angeles',
- u'vm_logical_timestamp': 5,
- u'host_uuid': u'acc819fe-e0ff-4963-93a4-5a0e1d3c77d3',
- u'uuid': u'e30f381d-d4bc-4958-a88c-79448efe5112'},
- {u'vm_features': {u'AGENT_VM': False, u'VGA_CONSOLE': True},
- u'name': u'am4', u'num_cores_per_vcpu': 1,
- u'gpus_assigned': False, u'num_vcpus': 2, u'memory_mb': 4096,
- u'power_state': u'on', u'ha_priority': 0,
- u'allow_live_migrate': True, u'timezone': u'America/Los_Angeles',
- u'vm_logical_timestamp': 2,
- u'host_uuid': u'acc819fe-e0ff-4963-93a4-5a0e1d3c77d3',
- u'uuid': u'f1e3362b-0377-4d70-bccd-63d2a1c09225'}],
- u'dynamic_ring_changing_node': None,
- u'cpu_model': u'Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz',
- u'ipmi_username': u'ADMIN',
- u'cluster_uuid': u'0005809e-62e4-75c7-611b-0cc47ac3b354',
- u'ipmi_password': None, u'cpu_frequency_in_hz': 2400000000,
- u'stats': {u'num_read_io': u'47',
- u'controller_read_io_bandwidth_kBps': u'0',
- u'content_cache_hit_ppm': u'1000000',
- }, u'backplane_ip': None,
- u'num_vms': 3,
- u'name': u'watermelon02-4', u'hypervisor_password': None,
- u'hypervisor_full_name': u'Nutanix 20180802.100874',
- u'is_degraded': False, u'host_type': u'HYPER_CONVERGED',
- u'default_vhd_storage_container_uuid': None,
- u'block_serial': u'16AP60170033', u'usage_stats': {
- },
- u'disk_hardware_configs': {
- u'1': {
- u'mount_path': u'/home/nutanix/data/stargate-storage/disks/BTHC549209M3480MGN',
- },
- u'3': {
- u'mount_path': u'/home/nutanix/data/stargate-storage/disks/9XG9TRZQ'},
- u'2': {
- u'mount_path': u'/home/nutanix/data/stargate-storage/disks/BTHC550503XF480MGN',
- },
- u'5': {
- u'mount_path': u'/home/nutanix/data/stargate-storage/disks/9XG9TS0N',
- },
- u'4': {
- u'mount_path': u'/home/nutanix/data/stargate-storage/disks/9XG9TSF7',
- },
- u'6': {
- u'mount_path': u'/home/nutanix/data/stargate-storage/disks/9XG9TREW',
- }}, u'ipmi_address': u'10.49.26.188',
- u'bios_model': u'0824', u'default_vm_location': None,
- u'hypervisor_type': u'kKvm',
- u'position': {u'ordinal': 4, u'physical_position': None,
- u'name': u''},
- u'service_vmexternal_ip': u'10.53.96.79',
- u'controller_vm_backplane_ip': u'10.53.96.79'}}
-
-
-class TestAhvConfigSection(TestBase):
- """
- Test base for testing class AhvConfigSection.
- """
-
- def __init__(self, *args, **kwargs):
- super(TestAhvConfigSection, self).__init__(*args, **kwargs)
- self.ahv_config = None
-
- def init_virt_config_section(self, is_pc=False):
- """
- Method executed before each unit test.
- """
- self.ahv_config = AhvConfigSection(MY_SECTION_NAME, None)
- if is_pc:
- self.ahv_config['prism_central'] = True
- # We need to set values using this way, because we need
- # to trigger __setitem__ of virt_config.
- for key, value in PE_SECTION_VALUES.items():
- self.ahv_config[key] = value
-
- def test_validate_ahv_PE_config(self):
- """
- Test validation of ahv section.
- """
- # PE validation.
- self.init_virt_config_section()
- result = self.ahv_config.validate()
- self.assertEqual(len(result), 0)
-
- # PC validation.
- self.init_virt_config_section(is_pc=True)
- result = self.ahv_config.validate()
- self.assertEqual(len(result), 0)
-
- def test_validate_ahv_invalid_server_ip(self):
- """
- Test validation of ahv config. Invalid server IP.
- """
- self.init_virt_config_section()
- self.ahv_config['server'] = '10.0.0.'
- result = self.ahv_config.validate()
- expected_result = ['Invalid server IP address provided']
- six.assertCountEqual(self, expected_result, result)
-
- def test_validate_ahv_config_missing_username_password(self):
- """
- Test validation of ahv config. Username and password is required.
- """
- self.init_virt_config_section()
- del self.ahv_config['username']
- del self.ahv_config['password']
- result = self.ahv_config.validate()
- expected_result = [
- ('error', 'Required option: "username" not set.'),
- ('error', 'Required option: "password" not set.')
- ]
- six.assertCountEqual(self, expected_result, result)
-
- def test_validate_ahv_config_invalid_internal_debug_flag(self):
- """
- Test validation of ahv config. If update_interval and internal debug
- are not set then we get a warning message for each flag.
- """
- self.init_virt_config_section()
- self.ahv_config['update_interval'] = 40
- result = self.ahv_config.validate()
- message = "Interval value can't be lower than {min} seconds. " \
- "Default value of {min} " \
- "seconds will be used.".format(min=DefaultUpdateInterval)
- expected_result = [("warning", message)]
- six.assertCountEqual(self, expected_result, result)
-
-
-class TestAhv(TestBase):
-
- @staticmethod
- def create_config(name, wrapper, **kwargs):
- config = AhvConfigSection(name, wrapper)
- config.update(**kwargs)
- config.validate()
- return config
-
- def setUp(self, is_pc=False):
- config = self.create_config(name='test', wrapper=None, type='ahv',
- server='10.10.10.10', username='username',
- password='password', owner='owner',
- prism_central=is_pc)
- self.ahv = Virt.from_config(self.logger, config, Datastore(),
- interval=DefaultInterval)
-
- @patch('virtwho.virt.ahv.ahv_interface.AhvInterface._progressbar')
- def run_once(self, queue=None):
- """Run AHV in oneshot mode."""
- self.ahv._oneshot = True
- self.ahv.dest = queue or Queue()
- self.ahv._terminate_event = Event()
- self.ahv._oneshot = True
- self.ahv._interval = 0
- self.ahv._run()
-
- @patch.object(Session, 'get')
- def test_connect_PE(self, mock_get):
- mock_get.return_value.status_code = 200
- self.run_once()
-
- self.assertEqual(mock_get.call_count, 3)
- call_list = [
- call('https://10.10.10.10:9440/api/nutanix/v2.0/clusters',
- data=ANY, headers=ANY, timeout=ANY, verify=ANY),
- call('https://10.10.10.10:9440/api/nutanix/v2.0/vms',
- data=ANY, headers=ANY, timeout=ANY, verify=ANY),
- call('https://10.10.10.10:9440/api/nutanix/v2.0/hosts',
- data=ANY, headers=ANY, timeout=ANY, verify=ANY)
- ]
- mock_get.assert_has_calls(call_list, any_order=True)
-
- @patch.object(Session, 'post')
- def test_connect_PC(self, mock_post):
- self.setUp(is_pc=True)
-
- mock_post.return_value.status_code = 200
- self.run_once()
-
- self.assertEqual(mock_post.call_count, 3)
- call_list = [
- call('https://10.10.10.10:9440/api/nutanix/v3/clusters/list',
- data=ANY, headers=ANY, timeout=ANY, verify=ANY),
- call('https://10.10.10.10:9440/api/nutanix/v3/vms/list',
- data=ANY, headers=ANY, timeout=ANY, verify=ANY),
- call('https://10.10.10.10:9440/api/nutanix/v3/hosts/list',
- data=ANY, headers=ANY, timeout=ANY, verify=ANY)
- ]
- mock_post.assert_has_calls(call_list, any_order=True)
-
- @patch.object(Session, 'get')
- def test_invalid_login_PE(self, mock_get):
- mock_get.return_value.ok = False
- mock_get.return_value.status_code = 401
- self.assertRaises(VirtError, self.run_once)
-
- mock_get.return_value.status_code = 403
- self.assertRaises(VirtError, self.run_once)
-
- @patch.object(Session, 'post')
- def test_invalid_login_PC(self, mock_post):
- self.setUp(is_pc=True)
- mock_post.return_value.ok = False
- mock_post.return_value.status_code = 401
- self.assertRaises(VirtError, self.run_once)
-
- mock_post.return_value.status_code = 403
- self.assertRaises(VirtError, self.run_once)
-
- @patch.object(Session, 'get')
- def test_connection_conflict_PE(self, mock_get):
- mock_get.return_value.ok = False
- mock_get.return_value.status_code = 409
- self.assertRaises(VirtError, self.run_once)
-
- @patch.object(Session, 'post')
- def test_connection_conflict_PC(self, mock_post):
- self.setUp(is_pc=True)
- mock_post.return_value.ok = False
- mock_post.return_value.status_code = 409
- self.assertRaises(VirtError, self.run_once)
-
- @patch('virtwho.virt.ahv.ahv_interface.AhvInterface.get_vm', return_value=None)
- @patch.object(Session, 'get')
- def test_no_retry_http_erros_PE(self, mock_get, mock_get_vm):
- mock_get.return_value.ok = False
- mock_get.return_value.status_code = 400
- mock_get.return_value.text = 'Bad Request'
- self.assertEqual(mock_get_vm.return_value, None)
-
- mock_get.return_value.status_code = 404
- mock_get.return_value.text = 'Not Found Error'
- self.assertEqual(mock_get_vm.return_value, None)
-
- mock_get.return_value.status_code = 500
- mock_get.return_value.text = 'Internal Server Error'
- self.assertEqual(mock_get_vm.return_value, None)
-
- mock_get.return_value.status_code = 502
- mock_get.return_value.tex = 'Bad Gateway'
- self.assertEqual(mock_get_vm.return_value, None)
-
- mock_get.return_value.status_code = 503
- mock_get.return_value.text = 'Service Unavailable '
- self.assertEqual(mock_get_vm.return_value, None)
-
- @patch('virtwho.virt.ahv.ahv_interface.AhvInterface.get_vm', return_value=None)
- @patch.object(Session, 'post')
- def test_no_retry_http_erros_PC(self, mock_post, mock_get_vm):
- self.setUp(is_pc=True)
- mock_post.return_value.ok = False
- mock_post.return_value.status_code = 400
- mock_post.return_value.text = 'Bad Request'
- self.assertEqual(mock_get_vm.return_value, None)
-
- mock_post.return_value.status_code = 404
- mock_post.return_value.text = 'Not Found Error'
- self.assertEqual(mock_get_vm.return_value, None)
-
- mock_post.return_value.status_code = 500
- mock_post.return_value.text = 'Internal Server Error'
- self.assertEqual(mock_get_vm.return_value, None)
-
- mock_post.return_value.status_code = 502
- mock_post.return_value.tex = 'Bad Gateway'
- self.assertEqual(mock_get_vm.return_value, None)
-
- mock_post.return_value.status_code = 503
- mock_post.return_value.text = 'Service Unavailable '
- self.assertEqual(mock_get_vm.return_value, None)
-
- @patch('virtwho.virt.ahv.ahv_interface.AhvInterface.build_host_to_uvm_map')
- def test_getHostGuestMapping(self, host_to_uvm_map):
- host_to_uvm_map.return_value = HOST_UVM_MAP
-
- expected_result = []
-
- for host_uuid in HOST_UVM_MAP:
- host = HOST_UVM_MAP[host_uuid]
- hypervisor_id = host_uuid
- host_name = host['name']
- cluster_uuid = host['cluster_uuid']
- guests = []
- for guest_vm in host['guest_list']:
- state = guest_vm['power_state']
- guests.append(Guest(guest_vm['uuid'], self.ahv.CONFIG_TYPE,
- state))
-
- facts = {
- Hypervisor.CPU_SOCKET_FACT: '2',
- Hypervisor.HYPERVISOR_TYPE_FACT: u'kKvm',
- Hypervisor.HYPERVISOR_VERSION_FACT: 'Nutanix 20180802.100874',
- Hypervisor.HYPERVISOR_CLUSTER: str(cluster_uuid)
- }
-
- expected_result.append(Hypervisor(
- name=host_name,
- hypervisorId=hypervisor_id,
- guestIds=guests,
- facts=facts
- ))
-
- result = self.ahv.getHostGuestMapping()['hypervisors']
-
- self.assertEqual(len(result), len(expected_result), 'lists length '
- 'do not match')
- for index in range(0, len(result)):
- self.assertEqual(expected_result[index].toDict(),
- result[index].toDict())
-
diff --git a/virtwho/config.py b/virtwho/config.py
index 3740e28..fdff5dd 100644
--- a/virtwho/config.py
+++ b/virtwho/config.py
@@ -50,7 +50,7 @@ logger = log.getLogger(name='config', queue=False)
_effective_config = None
VW_CONF_DIR = "/etc/virt-who.d/"
-VW_TYPES = ("libvirt", "esx", "rhevm", "hyperv", "fake", "xen", "kubevirt", "ahv")
+VW_TYPES = ("libvirt", "esx", "rhevm", "hyperv", "fake", "xen", "kubevirt")
VW_GENERAL_CONF_PATH = "/etc/virt-who.conf"
VW_GLOBAL = "global"
VW_VIRT_DEFAULTS_SECTION_NAME = "defaults"
@@ -1151,7 +1151,7 @@ class VirtConfigSection(ConfigSection):
result = None
sm_type = self._values['sm_type']
virt_type = self._values.get('type')
- if sm_type == 'sam' and virt_type in ('esx', 'rhevm', 'hyperv', 'xen', 'ahv'):
+ if sm_type == 'sam' and virt_type in ('esx', 'rhevm', 'hyperv', 'xen'):
if key not in self:
result = (
'warning',
diff --git a/virtwho/parser.py b/virtwho/parser.py
index 6ee26d8..4a8c38f 100644
--- a/virtwho/parser.py
+++ b/virtwho/parser.py
@@ -47,7 +47,6 @@ SAT5_VM_DISPATCHER = {
'rhevm': {'owner': False, 'server': True, 'username': True},
'hyperv': {'owner': False, 'server': True, 'username': True},
'kubevirt': {'owner': False, 'server': False, 'username': False, 'kubeconfig': True, 'kubeversion': False},
- 'ahv' : {'owner': False, 'server': False, 'username': False},
}
SAT6_VM_DISPATCHER = {
@@ -57,7 +56,6 @@ SAT6_VM_DISPATCHER = {
'rhevm': {'owner': True, 'server': True, 'username': True},
'hyperv': {'owner': True, 'server': True, 'username': True},
'kubevirt': {'owner': True, 'server': False, 'username': False, 'kubeconfig': True, 'kubeversion': False},
- 'ahv' : {'owner': False, 'server': False, 'username': False},
}
class OptionError(Exception):
@@ -75,7 +73,7 @@ class StoreGroupArgument(Action):
def __call__(self, parser, namespace, values, option_string=None):
"""
When the argument from group is used, then this argument has to match
- virtualization backend [--libvirt|--esx|--rhevm|--hyperv|--xen|--kubevirt|--ahv]
+ virtualization backend [--libvirt|--esx|--rhevm|--hyperv|--xen|--kubevirt]
"""
options = vars(namespace)
virt_type = options['virt_type']
diff --git a/virtwho/virt/ahv/__init__.py b/virtwho/virt/ahv/__init__.py
deleted file mode 100644
index 01a19f8..0000000
--- a/virtwho/virt/ahv/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import absolute_import, print_function
-
-from .ahv import Ahv
-
-__all__ = ['Ahv']
diff --git a/virtwho/virt/ahv/ahv.py b/virtwho/virt/ahv/ahv.py
deleted file mode 100644
index 47a786d..0000000
--- a/virtwho/virt/ahv/ahv.py
+++ /dev/null
@@ -1,258 +0,0 @@
-import socket
-
-from . import ahv_constants
-from .ahv_interface import AhvInterface, Failure
-from time import time
-from virtwho import virt
-from virtwho.config import VirtConfigSection
-from virtwho.virt import Hypervisor, Guest
-
-DefaultUpdateInterval = 1800
-MinimumUpdateInterval = 60
-
-class Ahv(virt.Virt):
- "AHV Rest client"
- CONFIG_TYPE = "ahv"
- def __init__(self, logger, config, dest, interval=None,
- terminate_event=None, oneshot=False):
- """
- Args:
- logger (Logger): Framework logger.
- config (onfigSection): Virtwho configuration.
- dest (Datastore): Data store for destination.
- interval (Int): Wait interval for continuous run.
- terminate_event (Event): Event on termination.
- one_shot (bool): Flag to run virtwho as onetime or continuously.
- Returns:
- None.
- """
- super(Ahv, self).__init__(logger, config, dest,
- terminate_event=terminate_event,
- interval=interval,
- oneshot=oneshot)
- self.config = config
- self.version = ahv_constants.VERSION_2
- self.is_pc = False
- if 'prism_central' in self.config:
- if self.config['prism_central']:
- self.version = ahv_constants.VERSION_3
- self.is_pc = True
-
- self.port = ahv_constants.DEFAULT_PORT
- self.url = ahv_constants.SERVER_BASE_URIL % (self.config['server'],
- self.port, self.version)
- self.port = ahv_constants.DEFAULT_PORT
- self.username = self.config['username']
- self.password = self.config['password']
- self.update_interval = self.config['update_interval']
- self._interface = AhvInterface(logger, self.url, self.username,
- self.password, self.port,
- internal_debug=self.config['internal_debug'])
-
- def prepare(self):
- """
- Prepare for obtaining information from AHV server.
- Args:
- None
- Returns:
- None
- """
- self.logger.debug("Logging into Acropolis server %s" % self.url)
- self._interface.login(self.version)
-
- def _wait_for_update(self, timeout):
- """
- Wait for an update from AHV.
- Args:
- timeout (int): timeout
- Returns:
- task list (list): List of vm or host related tasks.
- """
- try:
- end_time = time() + timeout
- timestamp = int(time() * 1e6)
- while time() < end_time and not self.is_terminated():
- try:
- response = self._interface.get_tasks(timestamp, self.version,
- self.is_pc)
- if len(response) == 0:
- # No events, continue to wait
- continue
- self.logger.debug('AHV event found: %s\n' % response)
- return response
- except Failure as e:
- if 'timeout' not in e.details:
- raise
- except Exception:
- self.logger.exception("Waiting on AHV events failed: ")
-
- return []
-
- def getHostGuestMapping(self):
- """
- Get a dict of host to uvm mapping.
- Args:
- None.
- Returns:
- None.
- """
- mapping = {'hypervisors': []}
-
- host_uvm_map = self._interface.build_host_to_uvm_map(self.version)
-
- for host_uuid in host_uvm_map:
- host = host_uvm_map[host_uuid]
-
- try:
- if self.config['hypervisor_id'] == 'uuid':
- hypervisor_id = host_uuid
- elif self.config['hypervisor_id'] == 'hostname':
- hypervisor_id = host['name']
-
- except KeyError:
- self.logger.debug("Host '%s' doesn't have hypervisor_id property",
- host_uuid)
- continue
-
- guests = []
- if 'guest_list' in host and len(host['guest_list']) > 0:
- for guest_vm in host['guest_list']:
- try:
- state = guest_vm['power_state']
- except KeyError:
- self.logger.warning("Guest %s is missing power state. Perhaps they"
- " are powered off", guest_vm['uuid'])
- continue
- guests.append(Guest(guest_vm['uuid'], self.CONFIG_TYPE, state))
- else:
- self.logger.debug("Host '%s' doesn't have any vms", host_uuid)
-
- cluster_uuid = self._interface.get_host_cluster_uuid(host)
- host_version = self._interface.get_host_version(host)
- host_name = host['name']
-
- facts = {
- Hypervisor.CPU_SOCKET_FACT: str(host['num_cpu_sockets']),
- Hypervisor.HYPERVISOR_TYPE_FACT: host.get('hypervisor_type', 'AHV'),
- Hypervisor.HYPERVISOR_VERSION_FACT: str(host_version),
- Hypervisor.HYPERVISOR_CLUSTER: str(cluster_uuid)}
-
- mapping['hypervisors'].append(virt.Hypervisor(hypervisorId=hypervisor_id,
- guestIds=guests,
- name=host_name,
- facts=facts))
- return mapping
-
- def _run(self):
- """
- Continuous run loop for virt-who on AHV.
- Args:
- None.
- Returns:
- None.
- """
- self.prepare()
- next_update = time()
- initial = True
- wait_result = None
- while self._oneshot or not self.is_terminated():
-
- delta = next_update - time()
-
- if initial:
- assoc = self.getHostGuestMapping()
- self._send_data(virt.HostGuestAssociationReport(self.config, assoc))
- initial = False
- continue
-
- if delta > 0:
- # Wait for update.
- wait_result = self._wait_for_update(60 if initial else delta)
- if wait_result:
- events = wait_result
- else:
- events = []
- else:
- events = []
-
- if len(events) > 0 or delta > 0:
- assoc = self.getHostGuestMapping()
- self._send_data(virt.HostGuestAssociationReport(self.config, assoc))
-
- if self._oneshot:
- break
- else:
- next_update = time() + self.update_interval
-
-class AhvConfigSection(VirtConfigSection):
- """Class for intializing and processing AHV config"""
- VIRT_TYPE = 'ahv'
- HYPERVISOR_ID = ('uuid', 'hwuuid', 'hostname')
-
- def __init__(self, *args, **kwargs):
- """
- Initialize AHV config and add config keys.
- Args:
- args: args
- kwargs : kwargs
- Returns:
- None.
- """
- super(AhvConfigSection, self).__init__(*args, **kwargs)
- self.add_key('server', validation_method=self._validate_server,
- required=True)
- self.add_key('username', validation_method=self._validate_username,
- required=True)
- self.add_key('password',
- validation_method=self._validate_unencrypted_password,
- required=True)
- self.add_key('is_hypervisor', validation_method=self._validate_str_to_bool,
- default=True)
- self.add_key('prism_central', validation_method=self._validate_str_to_bool,
- default=None)
- self.add_key('internal_debug', validation_method=self._validate_str_to_bool,
- default=False)
- self.add_key('update_interval',
- validation_method=self._validate_update_interval,
- default=DefaultUpdateInterval)
-
- def _validate_server(self, key):
- """
- Validate the server IP address.
- Args:
- key (Str): server Ip address.
- Returns:
- Socket error is returned in case of an invalid ip.
- """
- error = super(AhvConfigSection, self)._validate_server(key)
- try:
- ip = self._values[key]
- socket.inet_aton(ip)
- except socket.error:
- error = 'Invalid server IP address provided'
- return error
-
- def _validate_update_interval(self, key):
- """
- Validate the update internal flag.
- Args:
- key (Int): Update internal value.
- Returns:
- A warning is returned in case interval is not valid.
- """
- result = None
- try:
- self._values[key] = int(self._values[key])
-
- if self._values[key] < MinimumUpdateInterval:
- message = "Interval value can't be lower than {min} seconds. " \
- "Default value of {min} " \
- "seconds will be used.".format(min=DefaultUpdateInterval)
- result = ("warning", message)
- self._values['interval'] = DefaultUpdateInterval
- except KeyError:
- result = ('warning', '%s is missing' % key)
- except (TypeError, ValueError) as e:
- result = (
- 'warning', '%s was not set to a valid integer: %s' % (key, str(e)))
- return result
diff --git a/virtwho/virt/ahv/ahv_constants.py b/virtwho/virt/ahv/ahv_constants.py
deleted file mode 100644
index 95534a0..0000000
--- a/virtwho/virt/ahv/ahv_constants.py
+++ /dev/null
@@ -1,21 +0,0 @@
-SERVER_BASE_URIL = 'https://%s:%d/api/nutanix/%s'
-AHV_HYPERVIRSOR = ['kKvm', 'AHV', 'ahv', 'kvm']
-TASK_COMPLETE_MSG = ['SUCCEEDED', 'Succeeded']
-DEFAULT_PORT = 9440
-VERSION_2 = 'v2.0'
-VERSION_3 = 'v3'
-
-CMN_RST_CMD = {'get_vm': {'url': '/vms/%s', 'method': 'get'},
- 'get_host': {'url': '/hosts/%s', 'method': 'get'},
- 'get_tasks': {'url': '/tasks/list', 'method': 'post'},
- 'get_task': {'url': '/tasks/%s', 'method': 'get'}}
-
-REST_CMD = {VERSION_2: {'list_vms': {'url': '/vms', 'method': 'get'},
- 'list_hosts': {'url': '/hosts', 'method': 'get'},
- 'list_clusters' : {'url': '/clusters',
- 'method': 'get'}},
- VERSION_3: {'list_vms': {'url': '/vms/list', 'method': 'post'},
- 'list_hosts': {'url': '/hosts/list', 'method': 'post'},
- 'list_clusters' : {'url': '/clusters/list',
- 'method': 'post'}}}
-
diff --git a/virtwho/virt/ahv/ahv_interface.py b/virtwho/virt/ahv/ahv_interface.py
deleted file mode 100644
index 8b75cb6..0000000
--- a/virtwho/virt/ahv/ahv_interface.py
+++ /dev/null
@@ -1,804 +0,0 @@
-import json
-import math
-import time
-import sys
-from . import ahv_constants
-from requests import Session
-from requests.exceptions import ConnectionError, ReadTimeout
-from virtwho import virt
-
-class AhvInterface(object):
- """ AHV REST Api interface class"""
- NO_RETRY_HTTP_CODES = [400, 404, 500, 502, 503]
- event_types = ['node', 'vm']
-
- def __init__(self, logger, url, username, password, port, **kwargs):
- """
- Args:
- logger (Log): Logger.
- url (str): Rest server url.
- username (str): Username.
- password (str): Password for rest client.
- port (int): Port number for ssp.
- kwargs(dict): Accepts following arguments:
- timeout(optional, int): Max seconds to wait before HTTP connection
- times-out. Default 30 seconds.
- retries (optional, int): Maximum number of retires. Default: 5.
- retry_interval (optional, int): Time to sleep between retry intervals.
- internal_debug (optional, bool): Detail log of the rest calls.
- Default: 5 seconds.
- """
- self._session = Session()
- self._timeout = kwargs.get('timeout', 30)
- self._retries = kwargs.get('retries', 5)
- self._retry_interval = kwargs.get('retry_interval', 30)
- self._logger = logger
- self._url = url
- self._user = username
- self._password = password
- self._port = port
- self._internal_debug = kwargs.get('internal_debug', False)
- self._create_session(self._user, self._password)
-
- def _create_session(self, user=None, password=None):
- """
- Creates rest session.
- Args:
- user (str): Username.
- password (str): Password for rest session.
- Returns:
- None.
- """
- if user is None:
- user = self._user
- if password is None:
- password = self._password
- self._session.auth = (user, password)
-
- def _make_url(self, uri, *args):
- """
- Creates base url.
- uri would always begin with a slash
- Args:
- uri (str): Uri.
- args (list): Args.
- Returns:
- url (str): Url with uri.
- """
- if not uri.startswith("/"):
- uri = "/%s" % uri
- url = "%s%s" % (self._url, uri)
- for arg in args:
- url += "/%s" % str(arg)
- return url
-
- def _format_response(self, data):
- """
- Format the data based on the response's version.
- Args:
- data (dict): Data dictionary.
- Returns:
- formatted_data (dict): Formatted dictionary.
- """
- if 'entities' in data:
- return self._process_entities_list(data['entities'])
- else:
- return self._process_dict_response(data)
-
- def _process_dict_response(self, data):
- """
- Format the data when we only have a dictionary.
- Args:
- data (dict): Data dictionary.
- Returns:
- formatted_data (dict): Formatted data.
- """
- formatted_data = data
- if 'status' in data and 'metadata' in data:
- formatted_data = dict(data['status'], **data['metadata'])
-
- if 'resources' in formatted_data:
- if 'power_state' in formatted_data['resources']:
- formatted_data['power_state'] = \
- formatted_data['resources']['power_state']
- if 'num_cpu_sockets' in formatted_data['resources']:
- formatted_data['num_cpu_sockets'] = \
- formatted_data['resources']['num_cpu_sockets']
-
- return formatted_data
-
- def _process_entities_list(self, data):
- """
- Format data for the list of entities.
- Args:
- data (list): List of entities dictionary.
- Returns:
- formatted_data (dict): Formatted data after processing list fo entities.
- """
- formatted_data = data
- initial = True
- for entity in data:
- if 'status' in entity and 'metadata' in entity:
- if initial:
- formatted_data = []
- initial = False
- formatted_data.append(dict(entity['status'], **entity['metadata']))
-
- for ent_obj in formatted_data:
- if 'resources' in ent_obj:
- if 'nodes' in ent_obj['resources']:
- nodes = ent_obj['resources']['nodes']
- if 'hypervisor_server_list' in nodes:
- ent_obj['hypervisor_types'] = []
- for server in nodes['hypervisor_server_list']:
- ent_obj['hypervisor_types'].append(server['type'])
-
- if 'kind' in ent_obj:
- if ent_obj['kind'] == 'cluster':
- if 'uuid' in ent_obj:
- ent_obj['cluster_uuid'] = ent_obj['uuid']
-
- return formatted_data
-
- def _progressbar(self, it, prefix="", size=60, file=sys.stdout, total=0, is_pc=False):
- count = total
- cursor = 0
- def show(j):
- x = int(size*j/count)
- file.write("%s[%s%s] %i/%i\r" % (prefix, "#"*x, "."*(size-x), j, count))
- file.flush()
- show(0)
-
- for i, item in enumerate(it):
- if is_pc:
- yield item
- for i in range(20):
- show(cursor+1)
- cursor += 1
- if cursor == count:
- break
- time.sleep(0.1)
- else:
- show(i+1)
-
- yield item
- file.write("\n")
- file.flush()
-
- def login(self, version):
- """
- Login to the rest server and ensure connection succeeds.
- Args:
- version (Str): Interface version.
- Returns:
- None.
- """
- (url, cmd_method) = self.get_diff_ver_url_and_method(
- cmd_key='list_clusters', intf_version=version)
- self.make_rest_call(method=cmd_method, uri=url)
- self._logger.info("Successfully logged into the AHV REST server")
-
- def get_hypervisor_type(self, version, host_entity=None, vm_entity=None):
- """
- Get the hypervisor type of the guest vm.
- Args:
- version (Str): API version.
- host_entity (Dict): Host info dict.
- vm_entity (Dict): Vm info dict.
- Returns:
- hypervisor_type (str): Vm hypervisor type.
- """
- hypervisor_type = None
- if version == 'v2.0':
- if host_entity:
- hypervisor_type = host_entity['hypervisor_type']
- else:
- self._logger.warning("Cannot retrieve the host type. Version:%s"
- % version)
- else:
- if vm_entity:
- if 'resources' in vm_entity:
- if 'hypervisor_type' in vm_entity['resources']:
- hypervisor_type = vm_entity['resources']['hypervisor_type']
- else:
- self._logger.debug("Hypervisor type of the %s is not available"
- % vm_entity['uuid'])
- else:
- self._logger.warning("No vm entity is provided for version %s. "
- "Therefore it's unable to retrieve host type"
- % version)
- return hypervisor_type
-
- def get_common_ver_url_and_method(self, cmd_key):
- """
- Gets the correct cmd name based on its corresponding version.
- Args:
- cmd_key (str): Key name to search for in the command dict.
- Returns:
- (str, str) : Tuple of (command, rest_type).
- """
- return (ahv_constants.CMN_RST_CMD[cmd_key]['url'],
- ahv_constants.CMN_RST_CMD[cmd_key]['method'])
-
- def get_diff_ver_url_and_method(self, cmd_key, intf_version):
- """
- Gets the correct cmd name based on its corresponding version
- Args:
- cmd_key (str): Key name to search for in the command dict.
- intf_version (str): Interface version.
- Returns:
- (str, str) : Tuple of (command, rest_type).
- """
- return (ahv_constants.REST_CMD[intf_version][cmd_key]['url'],
- ahv_constants.REST_CMD[intf_version][cmd_key]['method'])
-
- def get(self, uri, *args, **kwargs):
- """
- Args are appended to the url as components.
- /arg1/arg2/arg3
- Send a get request with kwargs to the server.
- Args:
- uri (str): Uri.
- args (list): Args.
- kwargs (dict): Dictionary of params.
- Returns:
- Response (requests.Response): rsp.
- """
- url = self._make_url(uri, *args)
- return self._send('get', url, **kwargs)
-
- def post(self, uri, **kwargs):
- """
- Send a Post request to the server.
- Body can be either the dict or passed as kwargs
- headers is a dict.
- Args:
- uri (str): Uri.
- kwargs (dict): Dictionary of params.
- Returns:
- Response (requests.Response): rsp.
- """
- url = self._make_url(uri)
- return self._send('post', url, **kwargs)
-
- def make_rest_call(self, method, uri, *args, **kwargs):
- """This method calls the appropriate rest method based on the arguments.
-
- Args:
- method (str): HTTP method.
- uri (str): Relative_uri.
- args(any): Arguments.
- kwargs(dict): Key value pair for the additional args.
-
- Returns:
- rsp (dict): The response content loaded as a JSON.
- """
- func = getattr(self, method)
- return func(uri, *args, **kwargs)
-
- def _send(self, method, url, **kwargs):
- """This private method acting as proxy for all http methods.
- Args:
- method (str): The http method type.
- url (str): The URL to for the Request
- kwargs (dict): Keyword args to be passed to the requests call.
- retries (int): The retry count in case of HTTP errors.
- Except the codes in the list NO_RETRY_HTTP_CODES.
-
- Returns:
- Response (requests.Response): The response object.
- """
- kwargs['verify'] = kwargs.get('verify', False)
- if 'timeout' not in kwargs:
- kwargs['timeout'] = self._timeout
- if 'data' not in kwargs:
- body = {}
- kwargs['data'] = json.dumps(body)
- content_dict = {'content-type': 'application/json'}
- kwargs.setdefault('headers', {})
- kwargs['headers'].update(content_dict)
-
- func = getattr(self._session, method)
- response = None
-
- retries = kwargs.pop("retries", None)
- retry_interval = kwargs.pop("retry_interval", self._retry_interval)
- retry_count = retries if retries else self._retries
- for ii in range(retry_count):
- try:
- response = func(url, **kwargs)
- if self._internal_debug:
- self._logger.debug("%s method The request url sent: %s" % (
- method.upper(), response.request.url))
- self._logger.debug('Response status: %d' % response.status_code)
- self._logger.debug('Response: %s' % json.dumps(response.json(),
- indent=4))
-
- except (ConnectionError, ReadTimeout) as e:
- self._logger.warning("Request failed with error: %s" % e)
- if ii != retry_count - 1:
- time.sleep(retry_interval)
- continue
- finally:
- self._session.close()
- if response.ok:
- return response
- if response.status_code in [401, 403]:
- raise virt.VirtError('HTTP Auth Failed %s %s. \n res: response: %s' %
- (method, url, response))
- elif response.status_code == 409:
- raise virt.VirtError('HTTP conflict with the current state of the '
- 'target resource %s %s. \n res: %s' %
- (method, url, response))
- elif response.status_code in self.NO_RETRY_HTTP_CODES:
- break
- if ii != retry_count - 1:
- time.sleep(retry_interval)
-
- if response is not None:
- msg = 'HTTP %s %s failed: ' % (method, url)
- if hasattr(response, "text") and response.text:
- msg = "\n".join([msg, response.text]).encode('utf-8')
- self._logger.error(msg)
- else:
- self._logger.error("Failed to make the HTTP request (%s, %s)" %
- (method, url))
-
- def get_tasks(self, timestamp, version, is_pc=False):
- """
- Returns a list of AHV tasks which happened after timestamp.
- Args:
- timestamp (int): Current timestamp.
- version (str): Interface version.
- is_pc (bool): Flag to determine f we need to poll for PC tasks.
- Returns:
- Task list (list): list of tasks.
- """
- ahv_clusters = self.get_ahv_cluster_uuids(version)
- (uri, cmd_method) = self.get_common_ver_url_and_method(cmd_key='get_tasks')
- # For task return. Use fv2.0 for now. update the url to use v2.0.
- url = self._url[:(self._url).rfind('v')] + 'v2.0' + uri
-
- res = self._send(method=cmd_method, url=url)
- data = res.json()
-
- if is_pc:
- return self.get_pc_tasks(data, timestamp, ahv_clusters)
- else:
- return self.get_pe_tasks(data, timestamp, ahv_clusters)
-
- def get_pc_tasks(self, data, timestamp, ahv_clusters):
- """
- Returns a list of AHV tasks on PC which happened after timestamp.
- Args:
- data (json): Rest response in json format.
- timestamp (str): Current timestamp.
- ahv_clusters (list): List of ahv clusters uuid.
- Returns:
- task_list (list): list of tasks on PC.
- """
- (uri, cmd_method) = self.get_common_ver_url_and_method(cmd_key='get_task')
- # For task return. Use fv2.0 for now. update the url to use v2.0.
- url = self._url[:(self._url).rfind('v')] + 'v2.0' + uri
-
- task_completed = False
- task_list = []
- if 'entities' in data:
- for task in data['entities']:
- if 'start_time_usecs' in task:
- if task['start_time_usecs'] > timestamp:
-
- if 'progress_status' in task:
- if task['progress_status'] in ahv_constants.TASK_COMPLETE_MSG:
- task_completed = True
- elif 'status' in task:
- if task['status'] in ahv_constants.TASK_COMPLETE_MSG:
- task_completed = True
-
- if task_completed:
- task_completed=False
- if 'subtask_uuid_list' in task:
- for subtask in task['subtask_uuid_list']:
- url = url % subtask
- subtask_resp = self._send(cmd_method, url)
- subtask_data = subtask_resp.json()
-
- if 'progress_status' in subtask_data:
- if subtask_data['progress_status'] in \
- ahv_constants.TASK_COMPLETE_MSG:
-
- if 'cluster_uuid' in subtask_data:
- cluster_uuid = subtask_data['cluster_uuid']
- else:
- # Task does not have any cluster associated with it,
- # skip it.
- continue
-
- if cluster_uuid in ahv_clusters:
- if 'entity_list' in task:
- entity_type_list = task['entity_list']
- else:
- # Task doesn't have any entity list, skip it.
- continue
-
- if entity_type_list:
- for ent_type in entity_type_list:
- if 'entity_type' in ent_type:
- if (str(ent_type['entity_type'])).lower() \
- in self.event_types:
- task_list.append(task)
- task_list.append(subtask_data)
-
- else:
- # Task has not finished or it failed, skip it and continue
- # the loop
- continue
-
- return task_list
-
-
-
- def get_pe_tasks(self, data, timestamp, ahv_clusters):
- """
- Returns a list of AHV tasks on PE which happened after timestamp.
- Args:
- data (json): rest response in json format.
- timestamp (str): Current timestamp.
- ahv_clusters (list): list of ahv clusters uuid.
- Returns:
- task_list (list): list of tasks on PE.
- """
- task_completed = False
- task_list = []
-
- if 'entities' in data:
- for task in data['entities']:
- if 'start_time_usecs' in task:
- if task['start_time_usecs'] > timestamp:
-
- if 'progress_status' in task:
- if task['progress_status'] in ahv_constants.TASK_COMPLETE_MSG:
- task_completed = True
- elif 'status' in task:
- if task['status'] in ahv_constants.TASK_COMPLETE_MSG:
- task_completed = True
-
- if task_completed:
- task_completed = False
- if 'cluster_reference' in task:
- if 'uuid' in task['cluster_reference']:
- cluster_uuid = task['cluster_reference']['uuid']
- elif 'cluster_uuid' in task:
- cluster_uuid = task['cluster_uuid']
- else:
- # Task does not have any cluster associated with it, skip it.
- continue
-
- if cluster_uuid in ahv_clusters:
- if 'entity_list' in task:
- entity_type_list = task['entity_list']
- elif 'entity_reference_list' in task:
- entity_type_list = task['entity_reference_list']
- else:
- # Task doesn't have any entity list, skip it.
- continue
-
- for ent_type in entity_type_list:
- if 'entity_type' in ent_type:
- if (str(ent_type['entity_type'])).lower() \
- in self.event_types:
- task_list.append(task)
- elif 'kind' in ent_type:
- if (str(ent_type['kind'])).lower() in self.event_types:
- task_list.append(task)
- else:
- # Task doesn't have any event type associated to it.
- continue
- return task_list
-
- def get_vms_uuid(self, version):
- """
- Returns the list of vms uuid.
- Args:
- version (str): Interface version.
- Returns:
- vm_uuid_list (list): list of vm's uuid.
- """
- self._logger.info("Getting the list of available vms")
- is_pc=True if version == 'v3' else False
- vm_uuid_list = []
- length = 0
- offset = 0
- total_matches = 0
- count = 1
- current = 0
- (url, cmd_method) = self.get_diff_ver_url_and_method(
- cmd_key='list_vms', intf_version=version)
- res = self.make_rest_call(method=cmd_method, uri=url)
- data = res.json()
- if 'metadata' in data:
- if 'total_matches' in data['metadata'] and 'length' in data['metadata']:
- length = data['metadata']['length']
- total_matches = data['metadata']['total_matches']
- elif 'count' in data['metadata'] and \
- 'grand_total_entities' in data['metadata'] and \
- 'total_entities' in data['metadata']:
-
- total_matches = data['metadata']['grand_total_entities']
- count = data['metadata']['count']
- length = data['metadata']['total_entities']
-
- if length < total_matches:
- self._logger.debug('Number of vms %s returned from REST is less than the total'\
- 'numberr:%s. Adjusting the offset and iterating over all'\
- 'vms until evry vm is returned from the server.' % (length,
- total_matches))
- count = math.ceil(total_matches/float(length))
-
- body = {'length': length, 'offset': offset}
- for i in self._progressbar(range(int(count)), "Finding vms uuid: ", total=int(total_matches), is_pc=is_pc):
- if 'entities' in data:
- for vm_entity in data['entities']:
- if 'metadata' in vm_entity:
- vm_uuid_list.append(vm_entity['metadata']['uuid'])
- elif 'uuid' in vm_entity:
- vm_uuid_list.append(vm_entity['uuid'])
- else:
- self._logger.warning("Cannot access the uuid for the vm %s. "
- "vm object: %s" % (vm_entity['name'],
- vm_entity))
-
- body['offset'] = body['offset'] + length
- body_data = json.dumps(body, indent=4)
- self._logger.debug('next vm list call has this body: %s' % body)
- res = self.make_rest_call(method=cmd_method, uri=url, data=body_data)
- data = res.json()
- current += 1
-
- self._logger.info("Total number of vms uuids found and saved for processing %s" % len(vm_uuid_list))
- return vm_uuid_list
-
- def get_hosts_uuid(self, version):
- """
- Returns the list of host uuid.
- Args:
- version (str): Interface version.
- Returns:
- host_uuid_list (list): list of host's uuid.
- """
- host_uuid_list = []
- (url, cmd_method) = self.get_diff_ver_url_and_method(
- cmd_key='list_hosts', intf_version=version)
-
- res = self.make_rest_call(method=cmd_method, uri=url)
- data = res.json()
- if 'entities' in data:
- for host_entity in data['entities']:
- if 'status' in host_entity and'metadata' in host_entity:
- # Check if a physical host, not a cluster.
- if 'cpu_model' in host_entity['status']:
- host_uuid_list.append(host_entity['metadata']['uuid'])
- elif 'uuid' in host_entity:
- host_uuid_list.append(host_uuid_list['uuid'])
- else:
- self._logger.warning("Cannot access the uuid for the. "
- "host object: %s" % (host_entity))
-
-
- def get_host_cluster_uuid(self, host_info):
- """
- Returns host's cluster UUID.
- Args:
- host_info (dict): Host info dict.
- Returns:
- host_cluster_uuid (uuid): host's cluster uuid.
- """
- if 'cluster_uuid' in host_info:
- return host_info['cluster_uuid']
- elif 'cluster_reference' in host_info:
- return host_info['cluster_reference']['uuid']
-
- def get_ahv_cluster_uuids(self, version):
- """
- Returns list of ahv cluster uuids.
- Args:
- version (str): Interface version.
- Returns:
- ahv_host_cluster_uuids (List): Returns list of ahv cluster uuids.
- """
- ahv_host_cluster_uuids = []
- seen = set(ahv_host_cluster_uuids)
-
- (url, cmd_method) = self.get_diff_ver_url_and_method(
- cmd_key='list_clusters', intf_version=version)
- res = self.make_rest_call(method=cmd_method, uri=url)
- data = res.json()
-
- formatted_data = self._format_response(data)
-
- for cluster in formatted_data:
- if 'hypervisor_types' in cluster and 'cluster_uuid' in cluster:
- for hypevirsor_type in cluster['hypervisor_types']:
- if hypevirsor_type in ahv_constants.AHV_HYPERVIRSOR:
- cluster_uuid = cluster['cluster_uuid']
- if cluster_uuid not in seen:
- seen.add(cluster_uuid)
- ahv_host_cluster_uuids.append(cluster['cluster_uuid'])
- break
-
- return ahv_host_cluster_uuids
-
- def get_host_version(self, host_info):
- """
- Returns host's version.
- Args:
- host_info (dict): Host info dict.
- Returns:
- host_version (Str): Host version if found, None otherwise.
- """
- host_version = None
- if 'resources' in host_info:
- host_resources = host_info['resources']
- if 'hypervisor' in host_resources:
- if 'hypervisor_full_name' in host_resources['hypervisor']:
- host_version = host_resources['hypervisor']['hypervisor_full_name']
- elif 'hypervisor_full_name' in host_info:
- host_version = host_info['hypervisor_full_name']
- else:
- self._logger.warning("Cannot get host version for %s"
- % host_info['uuid'])
-
- return host_version
-
- def get_vm(self, uuid):
- """
- Returns vm information
- Args:
- uuid (str): Vm uuid.
- Return:
- data (dict): Vm information.
- """
- (url, cmd_method) = self.get_common_ver_url_and_method(cmd_key='get_vm')
- url = url % uuid
- res = self.make_rest_call(method=cmd_method, uri=url)
- if res:
- data = res.json()
- return self._format_response(data)
- return None
-
- def get_host(self, uuid):
- """
- Returns host information
- Args:
- uuid (str): Host uuid.
- Return:
- data (dict): Host information.
- """
- (url, cmd_method) = self.get_common_ver_url_and_method(cmd_key='get_host')
- url = url % uuid
- res = self.make_rest_call(method=cmd_method, uri=url)
- if res:
- data = res.json()
- return self._format_response(data)
- else:
- return None
-
- def get_vm_host_uuid_from_vm(self, vm_entity):
- """
- Get the host uuid from the vm_entity response
- Args:
- vm_entity (dict): Vm info.
- Returns:
- host uuid (str): Vm host uuid if found, none otherwise.
- """
- if 'resources' in vm_entity:
- if 'host_reference' in vm_entity['resources']:
- return vm_entity['resources']['host_reference']['uuid']
- else:
- self._logger.warning("Did not find any host information for vm:%s"
- % vm_entity['uuid'])
- elif 'host_uuid' in vm_entity:
- return vm_entity['host_uuid']
- else:
- # Vm is off therefore no host is assigned to it.
- self._logger.debug('Cannot get the host uuid of the vm:%s. '
- 'perhaps the vm is powered off' % vm_entity['uuid'])
- return None
-
- def is_ahv_host(self, version, host_uuid, vm_entity=None):
- """
- Determine if a given host is a AHV host.
- host uuid should match the host uuid in vm_entity.
- Args:
- version (str): API version.
- host_uuid (str): uuid of a host.
- vm_entity (dict): For v3
- Returns:
- bool : True if host is ahv; false otehrwise.
- """
- if version == 'v2.0':
- host = self.get_host(host_uuid)
- if 'hypervisor_type' in host:
- return host['hypervisor_type'] in ahv_constants.AHV_HYPERVIRSOR
- else:
- if 'resources' in vm_entity:
- if 'hypervisor_type' in vm_entity['resources']:
- return vm_entity['resources']['hypervisor_type'] in \
- ahv_constants.AHV_HYPERVIRSOR
- self._logger.debug('Hypervisor type not found. \nversion:%s, '
- '\nhost_uuid:%s, \nvm_entity:%s'
- % (version, host_uuid, vm_entity))
- return False
-
- def build_host_to_uvm_map(self, version):
- """
- Builds a dictionary of every ahv host along with the vms they are hosting
- Args:
- version (Str): API version
- Returns:
- host_uvm_map (dict): Dict of ahv host with its uvms.
- """
- host_uvm_map = {}
- vm_entity = None
- host_uuid = None
- vm_uuids = self.get_vms_uuid(version)
-
- self._logger.info("Processing hosts for each vm.")
- if len(vm_uuids) > 0:
- for vm_uuid in vm_uuids:
- vm_entity = self.get_vm(vm_uuid)
- if vm_entity:
- host_uuid = self.get_vm_host_uuid_from_vm(vm_entity)
- if host_uuid:
- if self.is_ahv_host(version, host_uuid, vm_entity):
- host = self.get_host(host_uuid)
- if host:
- if host_uuid not in host_uvm_map:
- host_uvm_map[host_uuid] = host
- if 'guest_list' in host_uvm_map[host_uuid]:
- host_uvm_map[host_uuid]['guest_list'].append(vm_entity)
- else:
- host_uvm_map[host_uuid]['guest_list'] = []
- host_uvm_map[host_uuid]['guest_list'].append(vm_entity)
- else:
- self._logger.warning("unable to read information for host %s" % host_uuid)
- continue
- else:
- self._logger.debug("Host %s is not ahv, skipping it." % host_uuid)
- continue
- host_type = self.get_hypervisor_type(version, host, vm_entity)
- host_uvm_map[host_uuid]['hypervisor_type'] = host_type
- else:
- self._logger.warning("No available vms found")
- try:
- host_uuids = self.get_hosts_uuid(version)
- if len(host_uuids) > 0:
- for host_uuid in host_uuids:
- host = self.get_host(host_uuid)
- if host_uuid not in host_uvm_map:
- host_uvm_map[host_uuid] = host
- host_uvm_map[host_uuid]['guest_list'] = []
-
- else:
- self._logger.warning("No Available AHV host found")
- except TypeError:
- # In case there is no cluster registered to the PC.
- self._logger.warning("Unable to find any AHV hosts.")
-
- return host_uvm_map
-
-class Failure(Exception):
-
- def __init__(self, details):
- self.details = details
-
- def __str__(self):
- try:
- return str(self.details)
- except Exception as exn:
- import sys
- print(exn)
- return "AHV-API failure: %s" % str(self.details)
-
- def _details_map(self):
- return dict([(str(i), self.details[i]) for i in range(len(self.details))])
diff --git a/virtwho/virt/virt.py b/virtwho/virt/virt.py
index 5495657..466dc90 100644
--- a/virtwho/virt/virt.py
+++ b/virtwho/virt/virt.py
@@ -923,7 +923,6 @@ class Virt(IntervalThread):
import virtwho.virt.hyperv # flake8: noqa
import virtwho.virt.fakevirt # flake8: noqa
import virtwho.virt.kubevirt # flake8: noqa
- import virtwho.virt.ahv # flake8: noqa
return [subcls for subcls in cls.__subclasses__()]
--
2.26.2