From a80f02bfb2471e8611e6f6ea8e65e6f3722013c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florent=20Thi=C3=A9ry?= <florent.thiery@ubicast.eu> Date: Tue, 14 Mar 2017 15:55:26 +0100 Subject: [PATCH] add partition check, fixes #20771 --- tests/test_partitions.py | 134 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100755 tests/test_partitions.py diff --git a/tests/test_partitions.py b/tests/test_partitions.py new file mode 100755 index 00000000..d3292ab5 --- /dev/null +++ b/tests/test_partitions.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# Copyright 2017, Florent Thiery +''' +Criticality: Normal +Checks that partitions are in conformity with expected norms, and that sufficient free space is available +''' +import subprocess +import sys +import os + +BS = 512 + + +def to_gbytes(size_bytes): + return size_bytes/(1024*1024*1024) + +def read_file(fname): + with open(fname, 'r') as f: + return f.read() + +paths = [ + { + 'mount_point': '/', + 'recommended_types': ('ext4',), + 'min_size_gbytes': 20, + 'min_free_size_gbytes': 5, + }, + { + 'mount_point': '/home/msuser/msinstance', + 'recommended_types': ('ext4', 'nfsv4'), + 'min_size_gbytes': 20, + 'min_free_size_gbytes': 5, + }, + { + 'type': 'swap', + 'min_size_gbytes': 1, + }, +] + +def get_swap_gbytes(): + d = read_file('/proc/meminfo') + for l in d.split('\n'): + if 'SwapTotal'in l: + swap = l.split('SwapTotal:')[1].strip() + swap_kbytes, unit = swap.split(' ') + if unit != 'kB': + print('Warning, unexpected unit %s' % unit) + swap_gbytes = int(round(int(swap_kbytes)/(1024*1024))) + return swap_gbytes + +def get_path(path): + #Filesystem Type 1B-blocks Used Available Use% Mounted on + #/dev/loop2 ext4 52710469632 38253940736 11755397120 77% / + status, output = subprocess.getstatusoutput('df --output="source,fstype,size,used" -B 1 %s | tail -n 1' % path) + if status == 0: + dev, fstype, size, used = output.split() + else: + dev = fstype = size = used = None + return dev, fstype, to_gbytes(int(size)), to_gbytes(int(used)) + +def check_allocation(dev): + root_dev = os.path.basename(dev)[:3] + d = read_file('/proc/partitions') + dev_partitions = list() + for l in d.split('\n'): + if root_dev in l: + dev_partitions.append(l) + + max_size = 0 + total_size = 0 + for p in dev_partitions: + major, minor, blocks, name = p.split() + size = int(blocks) * 512 + if name == root_dev: + max_size = size + else: + total_size += size + unallocated = max_size - total_size + unallocated_gbytes = to_gbytes(unallocated) + if unallocated_gbytes > 1: + return False + return True + +error = False +warning = False + +def check_path(p): + global error + global warning + + psize = None + mount_point = p.get('mount_point') + if mount_point: + if os.path.isdir(mount_point): + name = mount_point + dev, fstype, psize, used = get_path(p['mount_point']) + if fstype not in p.get('recommended_types'): + print('Warning, fs type %s not recommended' % (fstype, p['recommended_types'])) + warning = True + if 'nfs' not in dev: + warning = not check_allocation(dev) + free_gb = psize - used + min_free_size_gbytes = p.get('min_free_size_gbytes') + if min_free_size_gbytes and free_gb < min_free_size_gbytes: + print('%s has less than %s GB free (%s GB free)' % (mount_point, min_free_size_gbytes, free_gb)) + error = True + else: + print('%s not found, cannot check' % mount_point) + elif p.get('type') == 'swap': + name = 'swap' + psize = get_swap_gbytes() + + if psize and psize < p['min_size_gbytes']: + print('%s is smaller than the minimum required size (%s GB < %s GB)' % (name, psize, p['min_size_gbytes'])) + error = True + +for p in paths: + check_path(p) + +OK = 0 +ERROR = 1 +WARNING = 3 +UNTESTABLE = 2 + +if error: + print('All ok') + code = ERROR +elif warning: + code = WARNING +else: + code = OK + +sys.exit(code) -- GitLab