Overvåk ledig diskplass med WMI


torsdag 4. juni 2009 Diverse prosjekter Jobb Software/verktøy

Med gjevne mellomrom går en eller annen disk på en eller annen server full, enten det er på grunn av ivrige logger, akkumulerende backups, voksende databaser eller noe helt annet. Uansett hva det er skaper det alltid problemer og tapt arbeidstid. Og med like gjevne mellomrom kan man høre meg klage, og si at nå vi få på plass en løsning som kan overvåke diskene våre.

I dag bestemte jeg meg derimot for å ikke klage lengre, og 20 minutter senere hadde jeg laget en liten app som viste meg hvor mye ledig diskplass det var på serverne våre. Jeg ante ikke at det skulle være enkelt.

Jeg begynte med å lage en liten dataklasse for å holde på informasjonen om en disk. Med hjelp av CodeRush tok det ikke mange sekunder eller tastetrykk. Her er DiskInfo-klassen:

    8 public class DiskInfo

    9 {

   10     public string DriveLetter { get; set; }

   11     public string VolumeName { get; set; }

   12     public double Size { get; set; }

   13     public double Free { get; set; }

   14     public double PercentFree { get { return Free / Size; } }

   15 

   16     public override string ToString()

   17     {

   18         return string.Format("{0}{1}{2}{3}{4}",

   19             DriveLetter.PadRight(5),

   20             VolumeName.PadRight(30),

   21             Size.ToString("###,###,###,###").PadLeft(15),

   22             Free.ToString("###,###,###,###").PadLeft(15),

   23             PercentFree.ToString("#0%").PadLeft(10));

   24     }

   25 }

Og så trengte jeg noe som kunne hente ut informasjonen. Jeg har hørt mye om Windows Management Instrumentation (WMI), men aldri brukt det. Men en liten titt på System.Management namespacet avslørte at dette var akkurat det jeg behøvde:

Provides access to a rich set of management information and management events about the system, devices, and applications instrumented to the WMI infrastructure. Applications and services can query for interesting management information (such as how much free space is left on the disk, what is the current CPU utilization, which database a certain application is connected to, and much more)...

Jeg laget en kjapp liten command-klasse jeg valgte å kalle DiskInfoRetriever, som gitt navnet på en server henter ut informasjon om alle diskene på den maskinen:

    9 using System.Management;

   10 

   11 public class DiskInfoRetriever

   12 {

   13     private string _Server;

   14 

   15     public List<DiskInfo> Items { get; set; }

   16 

   17     public DiskInfoRetriever(string server)

   18     {

   19         _Server = FixServerName(server);

   20         Items = new List<DiskInfo>();

   21     }

   22 

   23     private string FixServerName(string server)

   24     {

   25         return server.StartsWith(@"\\")

   26             ? server

   27             : @"\\" + server + @"\root\cimv2";

   28     }

   29 

   30     public void Execute()

   31     {

   32         var scope = new ManagementScope(_Server);

   33         var query = new ObjectQuery(

   34               "select FreeSpace, VolumeName, Size, Name "

   35             + "from Win32_LogicalDisk where DriveType=3");

   36 

   37         var searcher = new ManagementObjectSearcher(scope, query);

   38         var results = searcher.Get();

   39 

   40         Items.Clear();

   41 

   42         const int MEGABYTE = 1048576;

   43         foreach (ManagementObject result in results)

   44         {

   45             Items.Add(new DiskInfo

   46             {

   47                 DriveLetter = result["Name"].ToString(),

   48                 VolumeName = result["VolumeName"].ToString(),

   49                 Size = (double.Parse(result["Size"].ToString()) / MEGABYTE),

   50                 Free = (double.Parse(result["FreeSpace"].ToString()) / MEGABYTE),

   51             });

   52         }

   53     }

   54 }

Legg merke til den SQL-lignende spørringen på linje 34/35.

Nå gjenstod det bare å definere en liste med servere, initialisere en bunch med command-objekter, eksekvere dem, og loope gjennom resultatet for å skrive objektene til konsollet. Det gjorde jeg i Main:

   10 static void Main(string[] args)

   11 {

   12     string[] servers = { "s1dev02", "s1dev03", "s1dev04", "s1dev05", "s1hvsql01" };

   13 

   14     try

   15     {

   16         foreach (var server in servers)

   17         {

   18             Console.WriteLine(server + ":");

   19 

   20             var diskInfoRetriever = new DiskInfoRetriever(server);

   21             diskInfoRetriever.Execute();

   22             diskInfoRetriever.Items.ForEach((disk) => Console.WriteLine(disk));

   23 

   24             Console.WriteLine();

   25         }

   26     }

   27     catch (Exception ex)

   28     {

   29         Console.ForegroundColor = ConsoleColor.Red;

   30         Console.WriteLine(ex.ToString());

   31     }

   32 

   33     Console.WriteLine();

   34     Console.WriteLine("press ENTER to exit..");

   35     Console.ReadLine();

   36 }

20 minutter tidligere hadde jeg ingen anelse om at jeg kom til å lage dette her, eller at det var så enkelt. For fremtiden skal jeg tenke meg om en ekstra gang før jeg klager over en manglende, teknisk løsning. Det meste lar seg løse, og mye er enklere enn man tror.

Neste steg blir å lage en ny modul til ContikiCenter som kan informere oss om når disker nærmer seg smertegrensen. Her er forresten resultatet av dagens kjøring:

Disk Watcher console app

Obs, det ser ut som om vi må foreta en liten opprydning på s1dev04. Jaja, det får vente til i morgen.. :)


comments powered by Disqus