Board logo

标题: Unix/Linux 系统自动化管理 磁盘管理篇(2) [打印本页]

作者: look_w    时间: 2018-6-13 15:27     标题: Unix/Linux 系统自动化管理 磁盘管理篇(2)

UNIX/Linux 系统磁盘空间监控自动化脚本示例在下面的内容中,我们给出了一个对磁盘分区剩余空间大小进行自动化监控的示例,用户可根据自身需求,对示例脚本进行修改以达到特定的管理目的。
我们的自动化磁盘分区空间监控系统分为三个部分,由三个文件 /root/disktab,checkdisk 脚本和 /root/diskresp 实现。/root/disktab 文件定义了需要监控的磁盘分区,报警阈值和达到阈值后的动作。checkdisk 则实现了整个对于磁盘空间的监控过程,而 /root/diskresp 文件为用户自定义的磁盘空间达到阈值后的响应脚本。
监控脚本将被添加到 crontab 中,这样就可以使监控循环进行。我们的脚本在 RedHatEL-Server 5.3(perl 版本 5.8.8)、SLES 11(perl 版本 5.10.0) 和 AIX 5.3(perl 版本 5.8.2) 上测试通过。
定义的 /root/disktab 文件拥有下面的格式
分区所 mount 的目录        报警阈值        达到阈值后的动作
清单 6. 分区监控 /root/disktab 文件示例
1
2
/       80%     /root/diskresp
/data   100G       /root/diskresp




在这个文件中,第一行表示当"/"分区空间占用超过 80% 时,则运行脚本 /root/diskresp 进行响应;第二行表示当"/data"分区的空间占用超过 100G 时运行脚本 /root/diskresp 进行响应。我们的文件允许报警阈值以 KB,MB,GB 为单位,也可以以百分比表示。
脚本 checkdisk 主要完成的任务是分析 /root/disktab 文件并和当前查看磁盘空间的输出进行比较,对于空间异常的分区采取相应的措施。脚本 checkdisk 的第一部分先进行了初始化,获得了要使用的分区监控定义文件,默认的分区监控定义文件为 /root/disktab,也可以通过参数指定该文件的位置。
清单 7. checkdisk 脚本初始化部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/perl

use strict;

my $DISKTABFILE = "/root/disktab";
if ($ARGV[0] ne "") {
   $DISKTABFILE = $ARGV[0];
}

# 因为 Linux 和 AIX 的 df 命令格式略有不同,所以首先判断一下
my $OS = `uname`;
chomp $OS;
my $DF;
if ($OS eq "Linux") {
   $DF = "df -h";
} elsif ($OS eq "AIX") {
   # AIX 中的 df 命令,在这里使用了 -m 选项,则其输出都将以 MB 为单位(但是 MB 字样不会出现在结果输出中)
   $DF = "df -I -m";
} else {
   print "This OS is not supported.\n";
   exit 1;
}




接下来,checkdisk 脚本逐行分析了 /root/disktab 文件,使用 perl 的正则表达式,很容易可以从 /root/disktab 中将分区所 mount 的目录,报警阈值以及达到阈值后的动作等信息提取出来,然后将获得的信息存放在一个 hash table 中。
清单 8. checkdisk 脚本分析 /root/disktab 文件部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 分析 /root/disktab 文件
my %table = getTable($DISKTABFILE);

sub getTable
{
   # 通过参数取得 table 文件的位置
   my ($tabfile) = @_;
   my %rs;

   # 打开文件
   unless(open(TABF, $tabfile)) {
       print "Can't open file '$tabfile'.\n";
       exit 1;
   }
   # 分析 disktab 文件每行的内容,将其存放在一个 hash table 中
   foreach my $line (<TABF>) {
       # 使用正则表达式,分析出 table 文件中每一行的挂载点、阈值大小和采取的行动
       if(!($line =~ /^#/) && $line =~ /(\S+)\s+(\S+)\s+(.*)\s*$/) {
           my $mp = $1;
           my $size = $2;
           my $action = $3;
           $rs{$mp} = [$size, $action];
       }
   }
   close TABF;
   return %rs;
}




清单 9 中的脚本实现了实时监控并检测分区状况,通过前面获得的用户定义的阈值和 df 命令的输出进行比较,如果 df 显示的某个分区的空间占用超过了用户定义的阈值,则执行用户定义的操作。
清单 9. checkdisk 脚本根据分区状况执行响应
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# 将分析出的 hash table 以引用的形式传递给 checkDisk 函数,checkDisk 函数完成检查分区空间,并执行相应动作的任务。
checkDisk(\%table);
sub checkDisk
{
   my ($tab) = @_;
   my @df_rs = `$DF`; # 执行 df 命令
   chomp @df_rs;
   my ($mp, $used_size, $used_perc);
   my ($minsize, $minperc);
   my $comp_with_perc; # 此变量用于表明是使用百分比进行比较还是使用绝对空间大小值
   my %rs;
   my $env_str;
   # 分析 df 命令的每一行输出
   foreach my $line (@df_rs) {
       $comp_with_perc = 0;
       # 使用正则表达式,分析出 df 输出的每一行的挂载点、空间使用大小和空间使用百分比
       if ($line =~ /^\S+\s+\S+\s+(\S+)\s+\S+\s+(\d+)%\s+(\S+)\s*$/) {
           $mp = $3; $used_size = $1; $used_perc = $2;
       } else {
           next;
       }
       # 如果某个分区的 Mount Point 在 table 中有一项和它对应,则继续进行,否则分析下一行
       if (!defined($$tab{$mp})) {
           next;
       }

       # 将得到的信息,存储起来,作为环境变量传递给将要运行的响应脚本
       $env_str = "DISK_MOUNTP=$mp";
       $env_str .= " DISK_MIN=$$tab{$mp}[0]";
       $env_str .= $used_size =~ /^\d+\.?\d*$/ ? " DISK_USED=${used_size}M" : "
           DISK_USED=$used_size";
       $env_str .= " DISK_USED_PERC=$used_perc%";
       # 分析 hash table 中的阈值,如果阈值使用的是大小值,则现将其统一单位为 MB
       if ($$tab{$mp}[0] =~ /^(\d+\.?\d*)G$/) {
           $minsize = $1 * 1024;
       }elsif ($$tab{$mp}[0] =~ /^(\d+\.?\d*)M$/) {
           $minsize = $1;
       }elsif ($$tab{$mp}[0] =~ /^(\d+\.?\d*)K$/) {
           $minsize = $1 / 1024;
       }elsif ($$tab{$mp}[0] =~ /^(\d+\.?\d*)%$/) {
           $minperc = $1;
           # 如果 hash table 中阈值存放的是一个百分比,则表明要进行占用百分比的比较
           $comp_with_perc = 1;
       }else {
           print "Format error: $$tab{$mp}[0]\n";
           next;
       }

       # 如果使用空间占用 size 进行比较,则也将 df 命令中得到的空间大小统一单位到 MB
       if (!$comp_with_perc) {
           if ($used_size =~ /^(\d+\.?\d*)G$/) {
               $used_size = $1 * 1024;
           }elsif ($used_size =~ /^(\d+\.?\d*)M$/ || $used_size =~ /^(\d+\.?\d*)$/) {
               $used_size = $1;
           }elsif ($used_size =~ /^(\d+\.?\d*)K$/) {
               $used_size = $1 / 1024;
           }
       }

       # 比较实际空间占用和 table 中记录的阈值
       if ((!$comp_with_perc && $minsize < $used_size) ||
           ($comp_with_perc && $minperc < $used_perc)) {
           print "WARNING DISK SIZE for $mp\n";
           # 调用 table 中记录的响应脚本,$env_str 中存放的 DISK_MOUNTP,DISK_MIN,DISK_USED,
           # DISK_USED_PERC,作为环境变量传递给脚本
           my $cmd = "$env_str $$tab{$mp}[1] 2>&1";
           print "Running command: $cmd\n";
           my $output = `$cmd`; chomp $output;
           print "Output:\n$output\nExit code = $?\n";
       }
   }
}




响应脚本(在本例中为 /root/diskresp)中可以从环境变量得到占用空间异常的分区的 Mount Point(DISK_MOUNTP),设置的阈值(DISK_MIN),空间占用大小(DISK_USED)以及空间占用比例(DISK_USED_PERC)。
响应脚本可以采取各种动作来解决空间占用问题,例如删除一些临时文件,或者是仅仅发一封信来通知管理员。一下给出一个响应脚本的例子,它所做的就是给 root 用户发一封信。
清单 10. 响应脚本示例
1
2
3
#!/bin/bash
echo "The $DISK_MOUNTP is now used $DISK_USED ($DISK_USED_PERC), over $DISK_MIN." |
mail -s "WARNING DISK SIZE for $DISK_MOUNTP" root




现在通过手工运行 /root/checkdisk 脚本,其已经可以正常工作。为了实现自动化的监控,我们需要系统的 cron 服务的帮助。
使用命令“crontab -e”编辑 crontab,添加一条类似于以下的项:
*/2 * * * * /root/checkdisk 2>&1 >> /root/checkdisk.log
这表示每两分钟运行一次 checkdisk 脚本,将其输出存储在 /root/checkdisk.log 文件中。可以根据自己的需求修改脚本运行的时间。cron 运行命令时,其命令输出不会显示在屏幕上,而是将输出通过邮件发给管理员,所以为了方便查看命令的输出,最好将输出重定向到文件中。
以上步骤完成后,就可以实现对磁盘分区的自动监控了。
对 checkdisk 脚本稍加修改就可以通过 ssh 或 rsh 实现对远程机器某个分区的监控,也可以使用 du 实现对某个文件夹大小的监控。(比如管理员可能在没有使用 quota 的情况下要监控每个用户的 home 目录的大小,以免某个用户占用过大的空间。)




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0