1#!/usr/bin/env python3

2# -*- coding: utf-8 -*-

3#

4# This file is part of Checkbox.

5#

6# Copyright 2014 Canonical Ltd.

7#

8# Authors:

9# Brendan Donegan <brendan.donegan@canonical.com>

10# Jeff Lane <jeff.lane@canonical.com>

11# Sylvain Pineau <sylvain.pineau@canonical.com>

12#

13# Checkbox is free software: you can redistribute it and/or modify

14# it under the terms of the GNU General Public License version 3,

15# as published by the Free Software Foundation.

16#

17# Checkbox is distributed in the hope that it will be useful,

18# but WITHOUT ANY WARRANTY; without even the implied warranty of

19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

20# GNU General Public License for more details.

21#

22# You should have received a copy of the GNU General Public License

23# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.

24

25 import os

26 import sys

27 import re

28 from subprocess import check_output, CalledProcessError, PIPE

29

30 from checkbox_support.helpers.human_readable_bytes import HumanReadableBytes

31 from checkbox_support.parsers.lshwjson import LshwJsonParser

32 from checkbox_support.parsers.meminfo import MeminfoParser

33

34

35 class LshwJsonResult:

36

37 memory_reported = 0

38 banks_reported = 0

39

40 # jlane LP:1525009

41 # Discovered the case can change, my x86 systems used "System Memory"

42 # Failing ARM system used "System memory"

43 desc_regex = re.compile("System Memory", re.IGNORECASE)

44

45 def addHardware(self, hardware):

46 if self.desc_regex.match(str(hardware.get("description", 0))):

47 self.memory_reported += int(hardware.get("size", 0))

48 elif "bank" in hardware["id"]:

49 self.banks_reported += int(hardware.get("size", 0))

50

51

52 def get_installed_memory_size():

53 try:

54 output = check_output(

55 ["lshw", "-json"], universal_newlines=True, stderr=PIPE

56 )

57 except CalledProcessError:

58 return 0

59 lshw = LshwJsonParser(output)

60 result = LshwJsonResult()

61 lshw.run(result)

62

63 if result.memory_reported:

64 return result.memory_reported

65 else:

66 return result.banks_reported

67

68

69 class MeminfoResult:

70

71 memtotal = 0

72

73 def setMemory(self, memory):

74 self.memtotal = memory["total"]

75

76

77 def get_visible_memory_size():

78 parser = MeminfoParser(open("/proc/meminfo"))

79 result = MeminfoResult()

80 parser.run(result)

81

82 return result.memtotal

83

84

85 def get_threshold(installed_memory):

86 GB = 1024**3

87 if installed_memory <= 2 * GB:

88 return 25

89 elif installed_memory <= 6 * GB:

90 return 20

91 elif installed_memory <= 8 * GB:

92 return 15

93 elif installed_memory <= 16 * GB:

94 return 12

95 else:

96 return 10

97

98

99 def main():

100 if os.geteuid() != 0:

101 print("This script must be run as root.", file=sys.stderr)

102 return 1

103

104 installed_memory = HumanReadableBytes(get_installed_memory_size())

105 visible_memory = HumanReadableBytes(get_visible_memory_size())

106 threshold = get_threshold(installed_memory)

107

108 difference = HumanReadableBytes(installed_memory - visible_memory)

109 try:

110 percentage = difference / installed_memory * 100

111 except ZeroDivisionError:

112 print("Results:")

113 print(

114 "\t/proc/meminfo reports:\t{}".format(visible_memory),

115 file=sys.stderr,

116 )

117 print("\tlshw reports:\t{}".format(installed_memory), file=sys.stderr)

118 print(

119 "\nFAIL: Either lshw or /proc/meminfo returned a memory size "

120 "of 0 kB",

121 file=sys.stderr,

122 )

123 return 1

124

125 if percentage <= threshold:

126 print("Results:")

127 print("\t/proc/meminfo reports:\t{}".format(visible_memory))

128 print("\tlshw reports:\t{}".format(installed_memory))

129 print(

130 "\nPASS: Meminfo reports %s less than lshw, a "

131 "difference of %.2f%%. This is less than the "

132 "%d%% variance allowed." % (difference, percentage, threshold)

133 )

134 return 0

135 else:

136 print("Results:", file=sys.stderr)

137 print(

138 "\t/proc/meminfo reports:\t{}".format(visible_memory),

139 file=sys.stderr,

140 )

141 print("\tlshw reports:\t{}".format(installed_memory), file=sys.stderr)

142 print(

143 "\nFAIL: Meminfo reports %d less than lshw, "

144 "a difference of %.2f%%. Only a variance of %d%% in "

145 "reported memory is allowed."

146 % (difference, percentage, threshold),

147 file=sys.stderr,

148 )

149 return 1

150

151

152 if __name__ == "__main__":

153 sys.exit(main())