Data files are now and should continue to be gleaned from pypowervm, which should be relied upon to keep them current (with respect to the REST API), clean, and consolidated. A recent pypowervm change set has added all the data files needed by this project, so they are removed from here. The test utilities used to load these files were also refactored (moved to a different package). This change set accomodates that refactor. Change-Id: Ic289c0fda3fe8271465f4c66ab99238d880931b3
275 lines
12 KiB
Python
275 lines
12 KiB
Python
# Copyright 2014, 2015 IBM Corp.
|
|
#
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
#
|
|
|
|
import mock
|
|
|
|
import logging
|
|
from nova import test
|
|
import pypowervm.tests.test_fixtures as pvm_fx
|
|
from pypowervm.tests.test_utils import pvmhttp
|
|
import pypowervm.wrappers.managed_system as pvm_ms
|
|
from pypowervm.wrappers.pcm import phyp as pvm_phyp
|
|
|
|
from nova_powervm.virt.powervm import host as pvm_host
|
|
|
|
MS_HTTPRESP_FILE = "managedsystem.txt"
|
|
PCM_FILE = "phyp_pcm_data2.txt"
|
|
PCM2_FILE = "phyp_pcm_data3.txt"
|
|
MS_NAME = 'HV4'
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
logging.basicConfig()
|
|
|
|
|
|
class TestPowerVMHost(test.TestCase):
|
|
def setUp(self):
|
|
super(TestPowerVMHost, self).setUp()
|
|
|
|
ms_http = pvmhttp.load_pvm_resp(MS_HTTPRESP_FILE)
|
|
self.assertNotEqual(ms_http, None,
|
|
"Could not load %s " %
|
|
MS_HTTPRESP_FILE)
|
|
|
|
entries = ms_http.response.feed.findentries(pvm_ms._SYSTEM_NAME,
|
|
MS_NAME)
|
|
|
|
self.assertNotEqual(entries, None,
|
|
"Could not find %s in %s" %
|
|
(MS_NAME, MS_HTTPRESP_FILE))
|
|
|
|
self.ms_entry = entries[0]
|
|
self.wrapper = pvm_ms.System.wrap(self.ms_entry)
|
|
|
|
def test_host_resources(self):
|
|
stats = pvm_host.build_host_resource_from_ms(self.wrapper)
|
|
self.assertIsNotNone(stats)
|
|
|
|
# Check for the presence of fields
|
|
fields = (('vcpus', 500), ('vcpus_used', 0),
|
|
('memory_mb', 5242880), ('memory_mb_used', 128),
|
|
'hypervisor_type', 'hypervisor_version',
|
|
'hypervisor_hostname', 'cpu_info',
|
|
'supported_instances', 'stats')
|
|
for fld in fields:
|
|
if isinstance(fld, tuple):
|
|
value = stats.get(fld[0], None)
|
|
self.assertEqual(value, fld[1])
|
|
else:
|
|
value = stats.get(fld, None)
|
|
self.assertIsNotNone(value)
|
|
# Check for individual stats
|
|
hstats = (('proc_units', '500.00'), ('proc_units_used', '0.00'))
|
|
for stat in hstats:
|
|
if isinstance(stat, tuple):
|
|
value = stats['stats'].get(stat[0], None)
|
|
self.assertEqual(value, stat[1])
|
|
else:
|
|
value = stats['stats'].get(stat, None)
|
|
self.assertIsNotNone(value)
|
|
|
|
|
|
class TestHostCPUStats(test.TestCase):
|
|
|
|
def setUp(self):
|
|
super(TestHostCPUStats, self).setUp()
|
|
|
|
# Fixture for the adapter
|
|
self.adpt = self.useFixture(pvm_fx.AdapterFx()).adpt
|
|
|
|
# Test data
|
|
self.cur_json_resp = pvmhttp.PVMFile(PCM_FILE)
|
|
self.prev_json_resp = pvmhttp.PVMFile(PCM2_FILE)
|
|
|
|
# Put in the samples.
|
|
self.phyp = pvm_phyp.PhypInfo(self.cur_json_resp.body)
|
|
self.prev_phyp = pvm_phyp.PhypInfo(self.prev_json_resp.body)
|
|
|
|
def _get_sample(self, lpar_id, sample):
|
|
for lpar in sample.lpars:
|
|
if lpar.id == lpar_id:
|
|
return lpar
|
|
return None
|
|
|
|
@mock.patch('nova_powervm.virt.powervm.host.HostCPUStats._get_cpu_freq')
|
|
@mock.patch('pypowervm.tasks.monitor.util.MetricCache._refresh_if_needed')
|
|
@mock.patch('pypowervm.tasks.monitor.util.ensure_ltm_monitors')
|
|
def test_update_internal_metric(self, mock_ensure_ltm, mock_refresh,
|
|
mock_cpu_freq):
|
|
host_stats = pvm_host.HostCPUStats(self.adpt, 'host_uuid')
|
|
mock_cpu_freq.return_value = 4116
|
|
|
|
# Make sure None is returned if there is no data.
|
|
host_stats.cur_phyp = None
|
|
host_stats._update_internal_metric()
|
|
self.assertEqual(None, host_stats.cur_data)
|
|
|
|
# Make the 'prev' the current...for the first pass
|
|
host_stats.cur_phyp = self.prev_phyp
|
|
host_stats.prev_phyp = None
|
|
host_stats._update_internal_metric()
|
|
|
|
# Validate the dictionary... No user cycles because all of the
|
|
# previous data is empty.
|
|
expect = {'iowait': 0, 'idle': 1.6125886579352732e+16,
|
|
'kernel': 58599310268, 'user': 0,
|
|
'frequency': 4116}
|
|
self.assertEqual(expect, host_stats.cur_data)
|
|
|
|
# Now 'increment' it with a new current/previous
|
|
host_stats.cur_phyp = self.phyp
|
|
host_stats.prev_phyp = self.prev_phyp
|
|
host_stats._update_internal_metric()
|
|
|
|
# Validate this dictionary. Note that the values are still higher
|
|
# overall, even though we add the 'deltas' from each VM.
|
|
expect = {'iowait': 0, 'idle': 1.6125856569262732e+16,
|
|
'kernel': 58599310268, 'user': 30010090000,
|
|
'frequency': 4116}
|
|
self.assertEqual(expect, host_stats.cur_data)
|
|
|
|
@mock.patch('nova_powervm.virt.powervm.host.HostCPUStats.'
|
|
'_get_total_cycles')
|
|
@mock.patch('nova_powervm.virt.powervm.host.HostCPUStats._get_cpu_freq')
|
|
@mock.patch('pypowervm.tasks.monitor.util.MetricCache._refresh_if_needed')
|
|
@mock.patch('pypowervm.tasks.monitor.util.ensure_ltm_monitors')
|
|
def test_update_internal_metric_bad_total(
|
|
self, mock_ensure_ltm, mock_refresh, mock_cpu_freq,
|
|
mock_tot_cycles):
|
|
"""Validates that if the total cycles are off, we handle."""
|
|
host_stats = pvm_host.HostCPUStats(self.adpt, 'host_uuid')
|
|
mock_cpu_freq.return_value = 4116
|
|
|
|
# Mock the total cycles to some really low number.
|
|
mock_tot_cycles.return_value = 5
|
|
|
|
# Now 'increment' it with a new current/previous
|
|
host_stats.cur_phyp = self.phyp
|
|
host_stats.prev_phyp = self.prev_phyp
|
|
host_stats._update_internal_metric()
|
|
|
|
# Validate this dictionary. Note that the idle is now 0...not a
|
|
# negative number.
|
|
expect = {'iowait': 0, 'idle': 0, 'kernel': 58599310268,
|
|
'user': 30010090000, 'frequency': 4116}
|
|
self.assertEqual(expect, host_stats.cur_data)
|
|
|
|
@mock.patch('subprocess.check_output')
|
|
@mock.patch('pypowervm.tasks.monitor.util.MetricCache._refresh_if_needed')
|
|
@mock.patch('pypowervm.tasks.monitor.util.ensure_ltm_monitors')
|
|
def test_get_cpu_freq(self, mock_ensure_ltm, mock_refresh, mock_cmd):
|
|
host_stats = pvm_host.HostCPUStats(self.adpt, 'host_uuid')
|
|
mock_cmd.return_value = '4116.000000MHz\n'
|
|
self.assertEqual(4116, host_stats._get_cpu_freq())
|
|
self.assertEqual(int, type(host_stats._get_cpu_freq()))
|
|
|
|
@mock.patch('pypowervm.tasks.monitor.util.MetricCache._refresh_if_needed')
|
|
@mock.patch('pypowervm.tasks.monitor.util.ensure_ltm_monitors')
|
|
def test_gather_user_cycles(self, mock_ensure_ltm, mock_refresh):
|
|
host_stats = pvm_host.HostCPUStats(self.adpt, 'host_uuid')
|
|
|
|
# Test that we can run with previous samples and then without.
|
|
host_stats.cur_phyp = self.phyp
|
|
host_stats.prev_phyp = self.prev_phyp
|
|
resp = host_stats._gather_user_cycles()
|
|
self.assertEqual(30010090000, resp)
|
|
|
|
# Last, test to make sure the previous data is used.
|
|
host_stats.prev_data = {'user': 1000000}
|
|
resp = host_stats._gather_user_cycles()
|
|
self.assertEqual(30011090000, resp)
|
|
|
|
# Now test if there is no previous sample. Since there are no previous
|
|
# samples, it will be 0 (except it WILL default up to the previous
|
|
# min cycles, which we just set to 1000000).
|
|
host_stats.prev_phyp = None
|
|
resp = host_stats._gather_user_cycles()
|
|
self.assertEqual(1000000, resp)
|
|
|
|
@mock.patch('pypowervm.tasks.monitor.util.MetricCache._refresh_if_needed')
|
|
@mock.patch('pypowervm.tasks.monitor.util.ensure_ltm_monitors')
|
|
def test_delta_proc_cycles(self, mock_ensure_ltm, mock_refresh):
|
|
host_stats = pvm_host.HostCPUStats(self.adpt, 'host_uuid')
|
|
|
|
# Test that a previous sample allows us to gather the delta across all
|
|
# of the VMs. This should take into account the scenario where a LPAR
|
|
# is deleted and a new one takes its place (LPAR ID 6)
|
|
delta = host_stats._delta_proc_cycles(self.phyp.sample.lpars,
|
|
self.prev_phyp.sample.lpars)
|
|
self.assertEqual(10010090000, delta)
|
|
|
|
# Now test as if there is no previous data. This results in 0 as they
|
|
# could have all been LPMs with months of cycles (rather than 30
|
|
# seconds delta).
|
|
delta2 = host_stats._delta_proc_cycles(self.phyp.sample.lpars, None)
|
|
self.assertEqual(0, delta2)
|
|
self.assertNotEqual(delta2, delta)
|
|
|
|
# Test that we can do this with the VIOSes as well.
|
|
delta = host_stats._delta_proc_cycles(self.phyp.sample.vioses,
|
|
self.prev_phyp.sample.vioses)
|
|
self.assertEqual(20000000000, delta)
|
|
|
|
@mock.patch('pypowervm.tasks.monitor.util.MetricCache._refresh_if_needed')
|
|
@mock.patch('pypowervm.tasks.monitor.util.ensure_ltm_monitors')
|
|
def test_delta_user_cycles(self, mock_ensure_ltm, mock_refresh):
|
|
host_stats = pvm_host.HostCPUStats(self.adpt, 'host_uuid')
|
|
|
|
# Test that a previous sample allows us to gather just the delta.
|
|
new_elem = self._get_sample(4, self.phyp.sample)
|
|
old_elem = self._get_sample(4, self.prev_phyp.sample)
|
|
delta = host_stats._delta_user_cycles(new_elem, old_elem)
|
|
self.assertEqual(45000, delta)
|
|
|
|
# Validate the scenario where we don't have a previous. Should default
|
|
# to 0, given no context of why the previous sample did not have the
|
|
# data.
|
|
delta = host_stats._delta_user_cycles(new_elem, None)
|
|
self.assertEqual(0, delta)
|
|
|
|
@mock.patch('pypowervm.tasks.monitor.util.MetricCache._refresh_if_needed')
|
|
@mock.patch('pypowervm.tasks.monitor.util.ensure_ltm_monitors')
|
|
def test_find_prev_sample(self, mock_ensure_ltm, mock_refresh):
|
|
host_stats = pvm_host.HostCPUStats(self.adpt, 'host_uuid')
|
|
|
|
# Sample 6 in the current shouldn't match the previous. It has the
|
|
# same LPAR ID, but a different name. This is considered different
|
|
new_elem = self._get_sample(6, self.phyp.sample)
|
|
prev = host_stats._find_prev_sample(new_elem,
|
|
self.prev_phyp.sample.lpars)
|
|
self.assertIsNone(prev)
|
|
|
|
# Lpar 4 should be in the old one. Match that up.
|
|
new_elem = self._get_sample(4, self.phyp.sample)
|
|
prev = host_stats._find_prev_sample(new_elem,
|
|
self.prev_phyp.sample.lpars)
|
|
self.assertIsNotNone(prev)
|
|
self.assertEqual(500000, prev.processor.entitled_proc_cycles)
|
|
|
|
# Test that we get None back if there are no previous samples
|
|
prev = host_stats._find_prev_sample(new_elem, None)
|
|
self.assertIsNone(prev)
|
|
|
|
@mock.patch('pypowervm.tasks.monitor.util.MetricCache._refresh_if_needed')
|
|
@mock.patch('pypowervm.tasks.monitor.util.ensure_ltm_monitors')
|
|
def test_get_total_cycles(self, mock_ensure_ltm, mock_refresh):
|
|
host_stats = pvm_host.HostCPUStats(self.adpt, 'host_uuid')
|
|
host_stats.cur_phyp = self.phyp
|
|
|
|
# Make sure we get the full system cycles.
|
|
max_cycles = host_stats._get_total_cycles()
|
|
self.assertEqual(1.6125945178663e+16, max_cycles)
|