From 7f4a2c4408a30b93908ce788dce7c7d4f80abb21 Mon Sep 17 00:00:00 2001 From: Masahiro Nagano Date: Thu, 20 May 2010 17:18:47 +0900 Subject: [PATCH] =?UTF-8?q?web=E3=81=AE=E3=83=AA=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=AF=E3=82=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README | 44 ++++++- cloudforecast_web | 176 +++---------------------- docs/cloudforecast.png | Bin 0 -> 70386 bytes lib/CloudForecast/Web.pm | 226 +++++++++++++++++++++----------- lib/CloudForecast/Web/Server.pm | 163 +++++++++++++++++++++++ 5 files changed, 364 insertions(+), 245 deletions(-) create mode 100644 docs/cloudforecast.png create mode 100644 lib/CloudForecast/Web/Server.pm diff --git a/README b/README index 481b42c..4cd5d43 100644 --- a/README +++ b/README @@ -2,15 +2,45 @@ CloudForecast - server resource monitoring framework WARNING: Alpha quality code -# schedule daemon -CF_DEBUG=1 ./cloudforecast_radar -c cloudforecast.yaml -l server_list.yaml +サーバ等のリソース監視をするためのツールです。 +RRDToolの薄いラッパー、情報取得のためのフレームワークとして設計されています。 +CloudForecastは、4つのプロセスによって動作します。 -# fetcher worker -CF_DEBUG=1 ./cf_fetcher_worker -c cloudforecast.yaml + - 巡回デーモン + - グラフ閲覧 HTTPD + - 情報取得Gearmanワーカー + - RRDファイル更新Gearmanワーカー + +小規模な監視では、Gearmanがなくても動作可能です。 +動作イメージはdocsディレクトリ以下の cloudforecast.png になります + +# 巡回デーモン +$ ./cloudforecast_radar -r -c cloudforecast.yaml -l server_list.yaml + - 起動すると5分ごとに巡回を行います + - -r 再起動オプション。ライブラリや設定ファイルを更新すると自動で再起動します + - -c 設定ファイル + - -c サーバ一覧 -# rrd update worker -CF_DEBUG=1 ./cf_updater_worker -c cloudforecast.yaml # web server -CF_DEBUG=1 ./cloudforecast_web -p 5000 -c cloudforecast.yaml -l server_list.yaml +$ ./cloudforecast_web -r- p 5000 -c cloudforecast.yaml -l server_list.yaml + - グラフ閲覧 HTTPD + - -p ポート httpdのport + + +# 情報取得Gearmanワーカー +$ ./cf_fetcher_worker -r -c cloudforecast.yaml \ + -max-workers 2 -max-request-per-child 100 -max-exection-time 60 + - geamarnでのリソース情報取得ワーカー + - -max-worker preforkするワーカー数 + - -max-request-per-child 1ワーカープロセス処理回数。この回数を超えるとプロセスが新しく作り直される + - -max-exection-time ワーカーの1回の取得作業でこれ以上の時間かかっている場合、そのワーカーを停止します + +# RRDファイル更新Gearmanワーカー +$ ./cf_updater_worker -r -c cloudforecast.yaml \ + -max-workers 2 -max-request-per-child 100 -max-exection-time 60 + - gearmanでのリソース情報をrrdファイルに書き込むワーカー + +#環境変数 +CF_DEBUG=1 をするとdebugログが出力されます diff --git a/cloudforecast_web b/cloudforecast_web index 96cc76e..6128779 100755 --- a/cloudforecast_web +++ b/cloudforecast_web @@ -3,171 +3,29 @@ use FindBin; use lib "$FindBin::Bin/lib"; use lib "$FindBin::Bin/site-lib"; -use CloudForecast::Web -base; -use CloudForecast::ConfigLoader; -use CloudForecast::Host; +use CloudForecast::Web::Server; use Getopt::Long; my $root_dir = $FindBin::Bin; -my $config_yaml = $root_dir . '/cloudforecast.yaml'; -my $server_list_yaml = $root_dir . '/server_list.yaml'; +my $config = $root_dir . '/cloudforecast.yaml'; +my $server_list = $root_dir .'/server_list.yaml'; +my $restarter = 0; +my $port = 5000; -my @argv = @ARGV; -Getopt::Long::Configure("no_ignore_case", "pass_through"); GetOptions( - 'c|config=s' => \$config_yaml, - 'l|server-list=s' => \$server_list_yaml, + 'port=s' => \$port, + 'r|restarter' => \$restarter, + 'c|config=s' => \$config, + 'l|server-list=s' => \$server_list, ); -die 'config not found' unless $config_yaml; -die 'server_list not found' unless $server_list_yaml; +die 'config not found' unless $config; +die 'server_list not found' unless $server_list; -my $configloader = CloudForecast::ConfigLoader->new({ +CloudForecast::Web::Server->new({ + port => $port, + restarter => $restarter, root_dir => $root_dir, - global_config => $config_yaml, - server_list => $server_list_yaml, -}); -$configloader->load_all(); - -my $global_config = $configloader->global_config; -my $server_list = $configloader->server_list; -my $all_hosts = $configloader->all_hosts; - -my $page_title = $server_list_yaml; -$page_title =~ s!^(.+)/!!; -$page_title =~ s!\.[^.]+$!!; - -sub get_host { - my $host = shift; - my $host_instance = CloudForecast::Host->new({ - address => $host->{address}, - hostname => $host->{hostname}, - details => $host->{details}, - resources => $host->{resources}, - component_config => $host->{component_config}, - global_config => $global_config, - }); - $host_instance; -} - -get '/' => sub { - my $req = shift; - my $p = shift; - return render('index.mt'); -}; - -get '/server' => sub { - my $req = shift; - - my $address = $req->param('address'); - return [ 404, [], ['Address Not Found'] ] unless $address; - - my $host = $all_hosts->{$address}; - return [ 404, [], ['Host Not Found'] ] unless $host; - - my $host_instance = get_host($host); - my @graph_list = $host_instance->list_graph; - - return render('server.mt'); -}; - -get '/graph' => sub { - my $req = shift; - - my $address = $req->param('address'); - return [ 404, [], ['Address Not Found'] ] unless $address; - my $resource = $req->param('resource'); - return [ 404, [], ['Resource Not Found'] ] unless $resource; - my $key = $req->param('key'); - return [ 404, [], ['Graph type key Not Found'] ] unless $key; - - my $span = $req->param('span') || 'd'; - my $host = $all_hosts->{$address}; - return [ 404, [], ['Host Not Found'] ] unless $host; - - my $host_instance = get_host($host); - my ($img,$err) = $host_instance->draw_graph($resource,$key, $span); - - return [ 500, [], ['Internal Server Error', $err] ] unless $img; - return [ 200, ['Content-Type','image/png'], [$img] ]; -}; - -get '/default.css' => sub { - my $req = shift; - return [ 200, ['Content-Type','text/css'], [render('css.mt')] ]; -}; - - -run_server(@argv); - -__DATA__ -@@ index.mt - - -CloudForecast Server List - - - -

- - - -
- - - - - - -@@ server.mt - - -CloudForecast Server List - - - -

-

{address} ?> {hostname} ?> {details} ?>

- - -

{resource_class} ?>

-{graphs}} ) { ?> - - - - -
- - - - - - - -@@ css.mt - -a { color: #5555cc;} -a:link { color: #5555cc;} -a:visited { color: #555599;} -a:active { color: #999999; } -a:hover { color: #999999; } - -ol, ul{ - list-style-position:inside; -} - + global_config => $config, + server_list => $server_list, +})->run; diff --git a/docs/cloudforecast.png b/docs/cloudforecast.png new file mode 100644 index 0000000000000000000000000000000000000000..3adc6d55dce2f904e796b4d00783971b90c4ecd1 GIT binary patch literal 70386 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 ~^(8zCY0ray#2cKvVlzfT<1nNXs@K3Rc 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'_ROUTER'); +__PACKAGE__->mk_accessors(qw/configloader + restarter + port/); -our @EXPORT = qw/get post any render run_server/; +our @EXPORT = qw/get post any/; sub import { my ($class, $name) = @_; @@ -24,120 +29,183 @@ sub import { { no strict 'refs'; if ( $name && $name =~ /^-base/ ) { - - $_ROUTER = Router::Simple->new(); - - for my $func (@EXPORT) { - *{"$caller\::$func"} = \&$func; + if ( ! $caller->isa($class) && $caller ne 'main' ) { + push @{"$caller\::ISA"}, $class; } } + for my $func (@EXPORT) { + *{"$caller\::$func"} = \&$func; + } } strict->import; warnings->import; } -sub psgify (&) { - my $code = shift; - sub { - my $env = shift; - my $req = Plack::Request->new($env); - my $p = delete $env->{'cloudforecast-web.args'}; - my $res = $code->($req, $p); - my $res_t = ref $res || ''; - if ( $res_t eq 'Plack::Response' ) { - return $res->finalize; - } - elsif ( $res_t eq 'ARRAY' ) { - return $res; - } - elsif ( !$res_t ) { - return [ 200, [ 'Content-Type' => 'text/html; charset=utf-8'], [ $res ] ]; - } - else { - Carp::croak("unknown response type: $res, $res_t"); - } +sub new { + my $class = shift; + my $args = ref $_[0] ? shift : { @_ }; + + my $configloader = CloudForecast::ConfigLoader->new({ + root_dir => $args->{root_dir}, + global_config => $args->{global_config}, + server_list => $args->{server_list}, + }); + $configloader->load_all(); + + $class->SUPER::new({ + configloader => $configloader, + restarter => $args->{restarter}, + port => $args->{port} || 5000, + }); +} + +sub run { + my $self = shift; + + my $app = $self->build_app; + $app = builder { + enable 'Plack::Middleware::Lint'; + enable 'Plack::Middleware::StackTrace'; + $app; }; + + + my $loader = Plack::Loader->load( + 'Starlet', + port => $self->port || 5000, + max_workers => 2, + ); + + my @watchdog_pid; + if ( $self->restarter ) { + CloudForecast::Log->debug("restarter start"); + push @watchdog_pid, $self->configloader->watchdog; + } + + $loader->run($app); + + for my $pid ( @watchdog_pid ) { + kill 'TERM', $pid; + waitpid( $pid, 0 ); + } } -sub router_to_app { - my $router = shift; +sub build_app { + my $self = shift; sub { - if ( my $p = $router->match($_[0]) ) { + my $env = shift; + if ( my $p = $self->router->match($env) ) { my $code = delete $p->{action}; - return [ 500, [], ['Internal Server Error'] ] unless $code; - $_[0]->{'cloudforecast-web.args'} = $p; - return $code->(@_) - } - else { - return [ 404, [ 'Content-Type' => 'text/html; charset=utf-8' ], ['not found'] ]; + return $self->ise('uri match but no action found') unless $code; + + my $req = Plack::Request->new($env); + my $res = $code->($self, $req, $p); + + my $res_t = ref $res || ''; + if ( $res_t eq 'Plack::Response' ) { + return $res->finalize; + } + elsif ( $res_t eq 'ARRAY' ) { + return $res; + } + elsif ( !$res_t ) { + return $self->html_response( $res ); + } + else { + Carp::croak("unknown response type: $res, $res_t"); + } } - } + return $self->not_found(); + }; +} + +sub ise { + my $self = shift; + my $error = shift; + CloudForecast::Log->warn($error) if $error; + $error ||= 'Internal Server Error'; + return [ 500, [ 'Content-Type' => 'text/html; charset=utf-8' ], [$error] ]; +} + +sub not_found { + my $self = shift; + my $error = shift; + CloudForecast::Log->warn($error) if $error; + $error ||= 'Not Found'; + return [ 404, [ 'Content-Type' => 'text/html; charset=utf-8' ], [$error] ]; } -sub run_server { - my $runner = Plack::Runner->new; - $runner->parse_options(@_); +sub html_response { + my $self = shift; + my $message = shift; + return [ 200, [ 'Content-Type' => 'text/html; charset=utf-8'], [ $message ] ]; +} - my $router_app = router_to_app($_ROUTER); - my $app = sub { - local $KEY = refaddr $router_app; - $router_app->(@_); +sub render { + my ( $self, $key, @args ) = @_; + my $code = do { + my $reader = Data::Section::Simple->new(ref $self); + my $tmpl = $reader->get_data_section($key); + Carp::croak("unknown template file:$key") unless $tmpl; + Text::MicroTemplate->new(template => $tmpl, package_name => ref($self) )->code(); }; - $runner->run($app); + package DB; + local *DB::render = sub { + my $coderef = (eval $code); ## no critic + die "Cannot compile template '$key': $@" if $@; + my $html = $coderef->(@args); + $html = Encode::encode_utf8($html) if utf8::is_utf8($html); + $html; + }; + goto &DB::render; } -sub any($$;$) { +sub router { + my $class = shift; + my $router = $class->_ROUTER; + if ( !$router ) { + $router = $class->_ROUTER( Router::Simple->new() ); + } + $router; +} + +sub _any($$$;$) { + my $class = shift; if ( @_ == 3 ) { my ( $methods, $pattern, $code ) = @_; - $_ROUTER->connect( + $class->router->connect( $pattern, - { action => psgify { goto $code } }, + { action => $code }, { method => [ map { uc $_ } @$methods ] } ); } else { my ( $pattern, $code ) = @_; - $_ROUTER->connect( + $class->router->connect( $pattern, - { action => psgify { goto $code } } + { action => $code } ); } } -sub get { - any( ['GET','HEAD'], $_[0], $_[1] ); +sub any { + my $class = caller; + $class->_any( @_ ); } -sub post { - any( ['POST'], $_[0], $_[1] ); +sub get { + my $class = caller; + $class->_any( ['GET','HEAD'], $_[0], $_[1] ); } -sub get_data_section { - my $pkg = caller($DATA_SECTION_LEVEL); - my $data = $CACHE{$KEY}->{__data_section} ||= Data::Section::Simple->new($pkg)->get_data_section; - return @_ ? $data->{$_[0]} : $data; +sub post { + my $class = caller; + $class->_any( ['POST'], $_[0], $_[1] ); } -sub render { - my ( $key, @args ) = @_; - my $code = $CACHE{$KEY}->{$key} ||= do { - local $DATA_SECTION_LEVEL = $DATA_SECTION_LEVEL + 1; - my $tmpl = get_data_section($key); - Carp::croak("unknown template file:$key") unless $tmpl; - Text::MicroTemplate->new(template => $tmpl, package_name => 'main')->code(); - }; - - package DB; - local *DB::render = sub { - my $coderef = (eval $code); ## no critic - die "Cannot compile template '$key': $@" if $@; - $coderef->(@args); - }; - goto &DB::render; -} 1; diff --git a/lib/CloudForecast/Web/Server.pm b/lib/CloudForecast/Web/Server.pm new file mode 100644 index 0000000..17ba2b3 --- /dev/null +++ b/lib/CloudForecast/Web/Server.pm @@ -0,0 +1,163 @@ +package CloudForecast::Web::Server; + +use strict; +use warnings; +use CloudForecast::Web -base; +use CloudForecast::Host; + +sub get_host { + my ( $self, $host ) = @_; + my $host_instance = CloudForecast::Host->new({ + address => $host->{address}, + hostname => $host->{hostname}, + details => $host->{details}, + resources => $host->{resources}, + component_config => $host->{component_config}, + global_config => $self->configloader->global_config, + }); + $host_instance; +} + +sub page_title { + my $self = shift; + my $page_title = $self->configloader->server_list_yaml; + $page_title =~ s!^(.+)/!!; + $page_title =~ s!\.[^.]+$!!; + $page_title; +} + +# shortcut +sub all_hosts { + my $self = shift; + $self->configloader->all_hosts; +} + +sub server_list { + my $self = shift; + $self->configloader->server_list; +} + +get '/' => sub { + my ( $self, $req, $p ) = @_; + return $self->render('index.mt'); +}; + +get '/server' => sub { + my ($self, $req, $p ) = @_; + + my $address = $req->param('address'); + return $self->not_found('Address Not Found') unless $address; + + my $host = $self->all_hosts->{$address}; + return $self->not_found('Host Not Found') unless $host; + + my $host_instance = $self->get_host($host); + my @graph_list = $host_instance->list_graph; + + return $self->render('server.mt'); +}; + + +get '/graph' => sub { + my ($self, $req ) = @_; + + my $address = $req->param('address'); + return $self->not_found('Address Not Found') unless $address; + my $resource = $req->param('resource'); + return $self->not_found('Resource Not Found') unless $resource; + my $key = $req->param('key'); + return $self->not_found('Graph type key Not Found') unless $key; + + my $span = $req->param('span') || 'd'; + my $host = $self->all_hosts->{$address}; + return $self->not_found('Host Not Found') unless $host; + + my $host_instance = $self->get_host($host); + my ($img,$err) = $host_instance->draw_graph($resource,$key, $span); + + return $self->ise($err) unless $img; + return [ 200, ['Content-Type','image/png'], [$img] ]; +}; + +get '/default.css' => sub { + my ($self, $req) = @_; + return [ 200, ['Content-Type','text/css'], [ $self->render('css.mt')] ]; +}; + + +1; + +__DATA__ +@@ index.mt + + +CloudForecast Server List + + + +

CloudForecast : page_title ?>

+ + + +
+ +
    + +server_list} ) { ?> +
  • {title} ?>
  • +
      + {hosts}} ) { ?> +
    • {address} ?> {hostname} ?> {details} ?>
    • + +
    + +
+ + + + +@@ server.mt + + +CloudForecast : <?= $self->page_title ?> : <?= $host->{address} ?> + + + +

CloudForecast : page_title ?>

+

{address} ?> {hostname} ?> {details} ?>

+ + +

{resource_class} ?>

+{graphs}} ) { ?> +
+ + + +
+ + + + + + + +@@ css.mt + +a { color: #5555cc;} +a:link { color: #5555cc;} +a:visited { color: #555599;} +a:active { color: #999999; } +a:hover { color: #999999; } + +ol, ul{ + list-style-position:inside; +} + + + +