CLOUDSTACK-8247: Pull average Cpu util report between polling

Pull average Cpu util report between polling intervals instead of since boot
instead of using values since uptime

(cherry picked from commit 04176eaf171b46638be99b2f675aa2f09e99e1b8)
Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>

Conflicts:
	plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java

This closes #297
This commit is contained in:
Rohit Yadav 2015-05-22 12:20:50 +01:00
parent b9a0b88078
commit cde6ef94b8
4 changed files with 231 additions and 125 deletions

View File

@ -16,50 +16,6 @@
// under the License. // under the License.
package com.cloud.hypervisor.kvm.resource; package com.cloud.hypervisor.kvm.resource;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.ejb.Local;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
import org.apache.cloudstack.storage.to.VolumeObjectTO;
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.libvirt.Connect;
import org.libvirt.Domain;
import org.libvirt.DomainBlockStats;
import org.libvirt.DomainInfo;
import org.libvirt.DomainInfo.DomainState;
import org.libvirt.DomainInterfaceStats;
import org.libvirt.LibvirtException;
import org.libvirt.NodeInfo;
import com.cloud.agent.api.Answer; import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command; import com.cloud.agent.api.Command;
import com.cloud.agent.api.HostVmStateReportEntry; import com.cloud.agent.api.HostVmStateReportEntry;
@ -139,6 +95,50 @@ import com.cloud.utils.script.Script;
import com.cloud.utils.ssh.SshHelper; import com.cloud.utils.ssh.SshHelper;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VirtualMachine.PowerState;
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
import org.apache.cloudstack.storage.to.VolumeObjectTO;
import org.apache.cloudstack.utils.linux.CPUStat;
import org.apache.cloudstack.utils.linux.MemStat;
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.libvirt.Connect;
import org.libvirt.Domain;
import org.libvirt.DomainBlockStats;
import org.libvirt.DomainInfo;
import org.libvirt.DomainInfo.DomainState;
import org.libvirt.DomainInterfaceStats;
import org.libvirt.LibvirtException;
import org.libvirt.NodeInfo;
import javax.ejb.Local;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* LibvirtComputingResource execute requests on the computing/routing host using * LibvirtComputingResource execute requests on the computing/routing host using
@ -261,6 +261,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
protected boolean _disconnected = true; protected boolean _disconnected = true;
protected int _cmdsTimeout; protected int _cmdsTimeout;
protected int _stopTimeout; protected int _stopTimeout;
protected CPUStat _cpuStat = new CPUStat();
protected MemStat _memStat = new MemStat();
@Inject @Inject
private LibvirtUtilitiesHelper libvirtUtilitiesHelper; private LibvirtUtilitiesHelper libvirtUtilitiesHelper;
@ -330,6 +332,14 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
return libvirtUtilitiesHelper; return libvirtUtilitiesHelper;
} }
public CPUStat getCPUStat() {
return _cpuStat;
}
public MemStat getMemStat() {
return _memStat;
}
public VirtualRoutingResource getVirtRouterResource() { public VirtualRoutingResource getVirtRouterResource() {
return _virtRouterResource; return _virtRouterResource;
} }

View File

@ -19,9 +19,6 @@
package com.cloud.hypervisor.kvm.resource.wrapper; package com.cloud.hypervisor.kvm.resource.wrapper;
import org.apache.cloudstack.utils.linux.MemStat;
import org.apache.log4j.Logger;
import com.cloud.agent.api.Answer; import com.cloud.agent.api.Answer;
import com.cloud.agent.api.GetHostStatsAnswer; import com.cloud.agent.api.GetHostStatsAnswer;
import com.cloud.agent.api.GetHostStatsCommand; import com.cloud.agent.api.GetHostStatsCommand;
@ -30,8 +27,9 @@ import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
import com.cloud.resource.CommandWrapper; import com.cloud.resource.CommandWrapper;
import com.cloud.resource.ResourceWrapper; import com.cloud.resource.ResourceWrapper;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
import com.cloud.utils.script.OutputInterpreter; import org.apache.cloudstack.utils.linux.CPUStat;
import com.cloud.utils.script.Script; import org.apache.cloudstack.utils.linux.MemStat;
import org.apache.log4j.Logger;
@ResourceWrapper(handles = GetHostStatsCommand.class) @ResourceWrapper(handles = GetHostStatsCommand.class)
public final class LibvirtGetHostStatsCommandWrapper extends CommandWrapper<GetHostStatsCommand, Answer, LibvirtComputingResource> { public final class LibvirtGetHostStatsCommandWrapper extends CommandWrapper<GetHostStatsCommand, Answer, LibvirtComputingResource> {
@ -40,23 +38,10 @@ public final class LibvirtGetHostStatsCommandWrapper extends CommandWrapper<GetH
@Override @Override
public Answer execute(final GetHostStatsCommand command, final LibvirtComputingResource libvirtComputingResource) { public Answer execute(final GetHostStatsCommand command, final LibvirtComputingResource libvirtComputingResource) {
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper(); CPUStat cpuStat = libvirtComputingResource.getCPUStat();
final String bashScriptPath = libvirtUtilitiesHelper.retrieveBashScriptPath(); MemStat memStat = libvirtComputingResource.getMemStat();
final double cpuUtil = cpuStat.getCpuUsedPercent();
final Script cpuScript = new Script(bashScriptPath, s_logger);
cpuScript.add("-c");
cpuScript.add("idle=$(top -b -n 1| awk -F, '/^[%]*[Cc]pu/{$0=$4; gsub(/[^0-9.,]+/,\"\"); print }'); echo $idle");
final OutputInterpreter.OneLineParser parser = new OutputInterpreter.OneLineParser();
String result = cpuScript.execute(parser);
if (result != null) {
s_logger.debug("Unable to get the host CPU state: " + result);
return new Answer(command, false, result);
}
final double cpuUtil = 100.0D - Double.parseDouble(parser.getLine());
MemStat memStat = new MemStat();
memStat.refresh(); memStat.refresh();
double totMem = memStat.getTotal(); double totMem = memStat.getTotal();
double freeMem = memStat.getAvailable(); double freeMem = memStat.getAvailable();

View File

@ -0,0 +1,104 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// 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.
package org.apache.cloudstack.utils.linux;
import org.apache.log4j.Logger;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class CPUStat {
private static final Logger s_logger = Logger.getLogger(CPUStat.class);
private Integer _cores;
private UptimeStats _lastStats;
private final String _sysfsCpuDir = "/sys/devices/system/cpu";
private final String _uptimeFile = "/proc/uptime";
class UptimeStats {
public Double upTime = 0d;
public Double cpuIdleTime = 0d;
public UptimeStats(Double upTime, Double cpuIdleTime) {
this.upTime = upTime;
this.cpuIdleTime = cpuIdleTime;
}
}
public CPUStat () {
init();
}
private void init() {
_cores = getCoresFromLinux();
_lastStats = getUptimeAndCpuIdleTime();
}
private UptimeStats getUptimeAndCpuIdleTime() {
UptimeStats uptime = new UptimeStats(0d, 0d);
try {
String[] stats = new Scanner(new File(_uptimeFile)).useDelimiter("\\Z").next().split("\\s+");
uptime = new UptimeStats(Double.parseDouble(stats[0]), Double.parseDouble(stats[1]));
} catch (FileNotFoundException ex) {
s_logger.warn("File " + _uptimeFile + " not found:" + ex.toString());
}
return uptime;
}
private Integer getCoresFromLinux() {
Integer cpus = 0;
File cpuDir = new File(_sysfsCpuDir);
File[] files = cpuDir.listFiles();
if (files != null) {
for (File file : files) {
if (file.getName().matches("cpu\\d+")) {
cpus++;
}
}
}
return cpus;
}
public Integer getCores() {
return _cores;
}
public Double getCpuUsedPercent() {
Double cpuUsed = 0d;
if (_cores == null || _cores == 0) {
_cores = getCoresFromLinux();
}
UptimeStats currentStats = getUptimeAndCpuIdleTime();
if (currentStats == null) {
return cpuUsed;
}
Double timeElapsed = currentStats.upTime - _lastStats.upTime;
Double cpuElapsed = (currentStats.cpuIdleTime - _lastStats.cpuIdleTime) / _cores;
if (timeElapsed > 0) {
cpuUsed = (1 - (cpuElapsed / timeElapsed)) * 100;
}
if (cpuUsed < 0) {
cpuUsed = 0d;
}
_lastStats = currentStats;
return cpuUsed;
}
}

View File

@ -19,59 +19,6 @@
package com.cloud.hypervisor.kvm.resource; package com.cloud.hypervisor.kvm.resource;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import javax.naming.ConfigurationException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.cloudstack.storage.command.AttachAnswer;
import org.apache.cloudstack.storage.command.AttachCommand;
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
import org.apache.commons.lang.SystemUtils;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.libvirt.Connect;
import org.libvirt.Domain;
import org.libvirt.DomainBlockStats;
import org.libvirt.DomainInfo;
import org.libvirt.DomainInfo.DomainState;
import org.libvirt.DomainInterfaceStats;
import org.libvirt.LibvirtException;
import org.libvirt.NodeInfo;
import org.libvirt.StorageVol;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import com.cloud.agent.api.Answer; import com.cloud.agent.api.Answer;
import com.cloud.agent.api.AttachIsoCommand; import com.cloud.agent.api.AttachIsoCommand;
import com.cloud.agent.api.AttachVolumeCommand; import com.cloud.agent.api.AttachVolumeCommand;
@ -169,6 +116,59 @@ import com.cloud.vm.DiskProfile;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VirtualMachine.PowerState;
import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.VirtualMachine.Type;
import org.apache.cloudstack.storage.command.AttachAnswer;
import org.apache.cloudstack.storage.command.AttachCommand;
import org.apache.cloudstack.utils.linux.CPUStat;
import org.apache.cloudstack.utils.linux.MemStat;
import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
import org.apache.commons.lang.SystemUtils;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.libvirt.Connect;
import org.libvirt.Domain;
import org.libvirt.DomainBlockStats;
import org.libvirt.DomainInfo;
import org.libvirt.DomainInfo.DomainState;
import org.libvirt.DomainInterfaceStats;
import org.libvirt.LibvirtException;
import org.libvirt.NodeInfo;
import org.libvirt.StorageVol;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import javax.naming.ConfigurationException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class LibvirtComputingResourceTest { public class LibvirtComputingResourceTest {
@ -920,24 +920,31 @@ public class LibvirtComputingResourceTest {
public void testGetHostStatsCommand() { public void testGetHostStatsCommand() {
// A bit difficult to test due to the logger being passed and the parser itself relying on the connection. // A bit difficult to test due to the logger being passed and the parser itself relying on the connection.
// Have to spend some more time afterwards in order to refactor the wrapper itself. // Have to spend some more time afterwards in order to refactor the wrapper itself.
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class); final LibvirtUtilitiesHelper libvirtUtilitiesHelper = Mockito.mock(LibvirtUtilitiesHelper.class);
final String bashScriptPath = "/path"; final CPUStat cpuStat = Mockito.mock(CPUStat.class);
final MemStat memStat = Mockito.mock(MemStat.class);
final String uuid = "e8d6b4d0-bc6d-4613-b8bb-cb9e0600f3c6"; final String uuid = "e8d6b4d0-bc6d-4613-b8bb-cb9e0600f3c6";
final GetHostStatsCommand command = new GetHostStatsCommand(uuid, "summer", 1l); final GetHostStatsCommand command = new GetHostStatsCommand(uuid, "summer", 1l);
when(libvirtComputingResource.getLibvirtUtilitiesHelper()).thenReturn(libvirtUtilitiesHelper); when(libvirtComputingResource.getCPUStat()).thenReturn(cpuStat);
when(libvirtUtilitiesHelper.retrieveBashScriptPath()).thenReturn(bashScriptPath); when(libvirtComputingResource.getMemStat()).thenReturn(memStat);
when(libvirtComputingResource.getNicStats(Mockito.anyString())).thenReturn(new Pair<Double, Double>(1.0d, 1.0d));
when(cpuStat.getCpuUsedPercent()).thenReturn(0.5d);
when(memStat.getAvailable()).thenReturn(1500.5d);
when(memStat.getTotal()).thenReturn(15000d);
final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance(); final LibvirtRequestWrapper wrapper = LibvirtRequestWrapper.getInstance();
assertNotNull(wrapper); assertNotNull(wrapper);
final Answer answer = wrapper.execute(command, libvirtComputingResource); final Answer answer = wrapper.execute(command, libvirtComputingResource);
assertFalse(answer.getResult()); assertTrue(answer.getResult());
verify(libvirtComputingResource, times(1)).getLibvirtUtilitiesHelper(); verify(libvirtComputingResource, times(1)).getCPUStat();
verify(libvirtUtilitiesHelper, times(1)).retrieveBashScriptPath(); verify(libvirtComputingResource, times(1)).getMemStat();
verify(cpuStat, times(1)).getCpuUsedPercent();
verify(memStat, times(1)).getAvailable();
verify(memStat, times(1)).getTotal();
} }
@Test @Test