Skip to content

Commit c37060a

Browse files
committed
CLOUDSTACK-8338: Fix hypervisor stats reporting for KVM on EL7
EL7 has a different output to 'free', use /proc/meminfo instead of a tool to be more consistent across distros (cherry picked from commit 212a05a) Signed-off-by: Rohit Yadav <[email protected]> Conflicts: plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
1 parent 0c6758f commit c37060a

File tree

3 files changed

+130
-22
lines changed

3 files changed

+130
-22
lines changed

plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetHostStatsCommandWrapper.java

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package com.cloud.hypervisor.kvm.resource.wrapper;
2121

22+
import org.apache.cloudstack.utils.linux.MemStat;
2223
import org.apache.log4j.Logger;
2324

2425
import com.cloud.agent.api.Answer;
@@ -55,28 +56,10 @@ public Answer execute(final GetHostStatsCommand command, final LibvirtComputingR
5556
}
5657
final double cpuUtil = 100.0D - Double.parseDouble(parser.getLine());
5758

58-
long freeMem = 0;
59-
final Script memScript = new Script(bashScriptPath, s_logger);
60-
memScript.add("-c");
61-
memScript.add("freeMem=$(free|grep cache:|awk '{print $4}');echo $freeMem");
62-
final OutputInterpreter.OneLineParser Memparser = new OutputInterpreter.OneLineParser();
63-
result = memScript.execute(Memparser);
64-
if (result != null) {
65-
s_logger.debug("Unable to get the host Mem state: " + result);
66-
return new Answer(command, false, result);
67-
}
68-
freeMem = Long.parseLong(Memparser.getLine());
69-
70-
final Script totalMem = new Script(bashScriptPath, s_logger);
71-
totalMem.add("-c");
72-
totalMem.add("free|grep Mem:|awk '{print $2}'");
73-
final OutputInterpreter.OneLineParser totMemparser = new OutputInterpreter.OneLineParser();
74-
result = totalMem.execute(totMemparser);
75-
if (result != null) {
76-
s_logger.debug("Unable to get the host Mem state: " + result);
77-
return new Answer(command, false, result);
78-
}
79-
final long totMem = Long.parseLong(totMemparser.getLine());
59+
MemStat memStat = new MemStat();
60+
memStat.refresh();
61+
double totMem = memStat.getTotal();
62+
double freeMem = memStat.getAvailable();
8063

8164
final Pair<Double, Double> nicStats = libvirtComputingResource.getNicStats(libvirtComputingResource.getPublicBridgeName());
8265

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.utils.linux;
18+
19+
import java.util.HashMap;
20+
import java.util.Map;
21+
22+
import java.io.File;
23+
import java.io.FileNotFoundException;
24+
import java.util.Scanner;
25+
26+
public class MemStat {
27+
protected final static String MEMINFO_FILE = "/proc/meminfo";
28+
protected final static String FREE_KEY = "MemFree";
29+
protected final static String CACHE_KEY = "Cached";
30+
protected final static String TOTAL_KEY = "MemTotal";
31+
32+
private Map<String, Double> _memStats = new HashMap<String, Double>();
33+
34+
public MemStat() {
35+
}
36+
37+
public Double getTotal() {
38+
return _memStats.get(TOTAL_KEY);
39+
}
40+
41+
public Double getAvailable() {
42+
return getFree() + getCache();
43+
}
44+
45+
public Double getFree() {
46+
return _memStats.get(FREE_KEY);
47+
}
48+
49+
public Double getCache() {
50+
return _memStats.get(CACHE_KEY);
51+
}
52+
53+
public void refresh() {
54+
try {
55+
Scanner fileScanner = new Scanner(new File(MEMINFO_FILE));
56+
parseFromScanner(fileScanner);
57+
} catch (FileNotFoundException ex) {
58+
throw new RuntimeException("File " + MEMINFO_FILE + " not found:" + ex.toString());
59+
}
60+
}
61+
62+
protected void parseFromScanner(Scanner scanner) {
63+
scanner.useDelimiter("\\n");
64+
while(scanner.hasNext()) {
65+
String[] stats = scanner.next().split("\\:\\s+");
66+
if (stats.length == 2) {
67+
_memStats.put(stats[0], Double.valueOf(stats[1].replaceAll("\\s+\\w+","")));
68+
}
69+
}
70+
}
71+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.utils.linux;
18+
19+
import org.junit.Assert;
20+
import org.junit.Test;
21+
22+
import java.util.Scanner;
23+
24+
public class MemStatTest {
25+
@Test
26+
public void getMemInfoParseTest() {
27+
String memInfo = "MemTotal: 5830236 kB\n" +
28+
"MemFree: 156752 kB\n" +
29+
"Buffers: 326836 kB\n" +
30+
"Cached: 2606764 kB\n" +
31+
"SwapCached: 0 kB\n" +
32+
"Active: 4260808 kB\n" +
33+
"Inactive: 949392 kB\n";
34+
35+
MemStat memStat = null;
36+
try {
37+
memStat = new MemStat();
38+
} catch (RuntimeException ex) {
39+
// If test isn't run on linux we'll fail creation of linux-specific MemStat class due
40+
// to dependency on /proc/meminfo if we don't catch here.
41+
// We are really only interested in testing the parsing algorithm and getters.
42+
if (memStat == null) {
43+
throw ex;
44+
}
45+
}
46+
Scanner scanner = new Scanner(memInfo);
47+
memStat.parseFromScanner(scanner);
48+
49+
Assert.assertEquals(memStat.getTotal(), Double.valueOf(5830236));
50+
Assert.assertEquals(memStat.getAvailable(), Double.valueOf(2763516));
51+
Assert.assertEquals(memStat.getFree(), Double.valueOf(156752));
52+
Assert.assertEquals(memStat.getCache(), Double.valueOf(2606764));
53+
}
54+
}

0 commit comments

Comments
 (0)