M.C.P.C. (Mamesibori Creation Plus Communication)

印刷屋から五反田のWeb屋に転職したCLのブログです。

Xenできる人がXenXenいない(いやマジで)

おじさんが転職した先でLinuxCLIをいじれる人がマジでいなくてビビっている。サーバ管理でスクリプトなんで作っていいかとビビっているんだけれども、サーバに潜ると過去の遺産的なシェルスクリプトとかも残っていて、そのスクリプトを作った専門家がいないならいないなりで何となく修正しているみたいだから、たとえPerlで書いたとしてもPerl特有の省略記法さえやめればメンテナンスできるってことだよね、と考え、平易な記述を心がけて書くなり。

XenServerのホストから子サーバを制御するxeコマンドっていうやつがあるんだけれども、それの出力がシェルスクリプトで扱いにくいので、簡易パーサを作りました。

Filename: xenserver-snapshot-list-parser.pl

#!/usr/bin/perl

# Citrix XenServer 5.6/6.02用の xe snapshot-list の簡易パーサ
#
# XenServerじゃないXenのばあい、xeコマンドではなくxmコマンド
# なのでテストしていないけれども、__DATA__以降の書式が
# 同じなら使えると思います。

use 5.8.8; # XenServer 5.6/6.2のDom-0に入るSystem Perlは 5.8.8
use strict;
use warnings;
use Data::Dumper;

my $res = [];
my $tmp = {};
my $mkey = '';

while (<DATA>) { # _DATA_ 行以降をファイルとして読み込み
  # Whileによって、$_ に1行ごと読み込まれる。
  # Perl読めない人向けに明示的に$_を書く

  $_ =~ tr/\x0D\x0A//d; # 改行コードを念のために除去(chompよりも確実に)
  $_ = trim( $_ );

  if ( $_ =~ m/^$/ ) { # 改行が区切り
    if ( $mkey ne '' ) {
      push @$res, $tmp;
      $tmp  = {};
      $mkey = '';
    }
  }
  else { # 区切りじゃない場合
    my ($key, $value) = split ':', $_, 2;
    my $type;
    ($key, $type) = split '\(', $key, 2;
    $type  =~ s/\)//;
    $type  = trim( $type );
    $key   = trim( $key );
    $value = trim( $value );
    if ( $mkey eq '' ) {
      $mkey = $value;
    }
    # ( R*):通常のパラメータ (SR*):setパラメータ (MR*):mapパラメータ で分岐
    if ( $type =~ m/S/i ) { # typeがS(setパラメータ)の場合
      my $tmp = [];
      foreach my $item ( split ';', $value ) {
        push @$tmp, trim($item);
      }
      $value = $tmp;
    }
    elsif ($type =~ m/M/i ){ # typeかM(mapパラメータ)の場合
      my $tmp = {};
      foreach my $item ( split ';', $value ) {
        my ( $key, $value ) = split ':', $item, 2;
        $tmp->{ trim( $key ) } = trim( $value );
      }
      $value = $tmp;
    }
    $tmp->{$key} = $value;
  }
}
# ファイル読み込みループ終わり
if ( $mkey ne '' ) { # まだ格納していないアイテムがある場合
  push @$res, $tmp;
} # つまり最後の行の改行があるかないか、ていう問題

print Dumper $res;
exit;

# use String::Util qw(trim); が使えない環境での代替trim()
sub trim {
  my $val = shift;
  $val =~ s/^\s*(.*?)\s*$/$1/;
  return $val;
}

__DATA__
uuid ( RO)                     : abcdef01-2345-6789-abcd-ef0123456789
               name-label ( RW): snapshot-001-20130414
         name-description ( RW):
    is-snapshot-from-vmpp ( RO): false


uuid ( RO)                     : bcdef012-3456-789a-bcde-f0123456789a
               name-label ( RW): snapshot-20130414
         name-description ( RW):
    is-snapshot-from-vmpp ( RO): false


uuid ( RO)                     : cdef0123-4567-89ab-cdef-0123456789ab
               name-label ( RW): snapshot-001
         name-description ( RW):
    is-snapshot-from-vmpp ( RO): false

出力:

$ perl xenserver-snapshot-list-parser.pl
$VAR1 = [
          {
            'name-description' => '',
            'name-label' => 'snapshot-001-20130414',
            'is-snapshot-from-vmpp' => 'false',
            'uuid' => 'abcdef01-2345-6789-abcd-ef0123456789'
          },
          {
            'name-description' => '',
            'name-label' => 'snapshot-20130414',
            'is-snapshot-from-vmpp' => 'false',
            'uuid' => 'bcdef012-3456-789a-bcde-f0123456789a'
          },
          {
            'name-description' => '',
            'name-label' => 'snapshot-001',
            'is-snapshot-from-vmpp' => 'false',
            'uuid' => 'cdef0123-4567-89ab-cdef-0123456789ab'
          }
        ];
$

データ構造体になってくれたらあとはgrepで絞り込んだりしていろいろ出来るよね。おじさんとしては、サーバのスナップショットの世代管理をしたいと思っています。