Merge branch 'master' into external_redis

This commit is contained in:
Scott Schneider 2014-02-14 11:18:47 -08:00
commit 3eb60665c2
9 changed files with 282 additions and 11 deletions

15
LICENSE Normal file
View file

@ -0,0 +1,15 @@
vmware-host-pooler
Copyright (C) 2014 Scott Schneider <sschneid@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -1,7 +1,7 @@
body, body,
#content { #content {
background: #fff; background: #fff;
margin-top: 20px; margin-top: 0px;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
} }
@ -27,7 +27,7 @@ body,
float: right; float: right;
position: relative; position: relative;
right: 30px; right: 30px;
top: 100px; top: 90px;
font: 50px 'PT Sans', sans-serif; font: 50px 'PT Sans', sans-serif;
letter-spacing: -0.05em; letter-spacing: -0.05em;
color: #444; color: #444;
@ -117,6 +117,7 @@ body,
.module { .module {
margin-top: 5px; margin-top: 5px;
margin-left: 25px; margin-left: 25px;
margin-right: 25px;
font: 13px 'PT Sans', sans-serif; font: 13px 'PT Sans', sans-serif;
line-height: 20px; line-height: 20px;
color: #888; color: #888;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Before After
Before After

View file

@ -1,6 +1,6 @@
var pool_url = '/dashboard/stats/vcloud/pool'; var pool_url = '/dashboard/stats/vcloud/pool';
var pool_width = 130; var pool_width = 130;
var pool_height = 85; var pool_height = 80;
var stats_vcloud_pool__data = {}; var stats_vcloud_pool__data = {};
var stats_vcloud_pool__svg = {}; var stats_vcloud_pool__svg = {};
@ -70,7 +70,7 @@ d3.json( pool_url+'?history=1',
stats_vcloud_pool__svg[ pool ] = d3.select( '#stats-vcloud-pool' ) stats_vcloud_pool__svg[ pool ] = d3.select( '#stats-vcloud-pool' )
.append( 'svg' ) .append( 'svg' )
.style( 'margin', '15px 0px 0px 0px' ) .style( 'margin', '15px 0px 0px 0px' )
.style( 'padding', '0px 10px 20px 10px' ) .style( 'padding', '0px 10px 10px 10px' )
.attr( 'width', pool_width ) .attr( 'width', pool_width )
.attr( 'height', pool_height ); .attr( 'height', pool_height );

View file

@ -0,0 +1,189 @@
var running_url = '/dashboard/stats/vcloud/running';
var running_height = 120;
var colorscale = d3.scale.category20();
var color = {};
var stats_vcloud_running__data = {};
var stats_vcloud_running__svg = {};
var stats_vcloud_running__data__total = 0;
d3.json( running_url+'?history=1',
function( stats_vcloud_running__data ) {
if ( typeof stats_vcloud_running__data[ 'stack' ] === 'undefined' ) {
stats_vcloud_running__data[ 'stack' ] = [];
stats_vcloud_running__data[ 'stack_t' ] = [];
}
for ( var key in stats_vcloud_running__data ) {
if ( stats_vcloud_running__data[ key ][ 'history' ] ) {
for ( var c = 0; c < stats_vcloud_running__data[ key ][ 'history' ].length; c++ ) {
if ( typeof stats_vcloud_running__data[ 'stack' ][ c ] === 'undefined' ) {
stats_vcloud_running__data[ 'stack' ][ c ] = {};
}
stats_vcloud_running__data[ 'stack' ][ c ][ key ] = stats_vcloud_running__data[ key ][ 'history' ][ c ];
}
}
}
for ( var c in stats_vcloud_running__data[ 'stack' ] ) {
for ( var n = 0; n < 8; n++ ) {
stats_vcloud_running__data[ 'stack_t' ].push( stats_vcloud_running__data[ 'stack' ][ c ] );
}
}
stats_vcloud_running__data[ 'stack' ] = stats_vcloud_running__data[ 'stack_t' ];
delete stats_vcloud_running__data[ 'stack_t' ];
( function tick() {
setTimeout( function() {
var stats_vcloud_running__data__live = ( function() {
var stats_vcloud_running__data__live = null;
$.ajax( {
'url': running_url,
'async': false,
'global': false,
'dataType': 'json',
'success': function( data ) {
stats_vcloud_running__data__live = data;
}
} );
return stats_vcloud_running__data__live;
} )();
var stats_vcloud_running__data__keys = [];
for ( var key in stats_vcloud_running__data__live ) {
stats_vcloud_running__data__keys.push( key );
for ( var c = 0; c < Object.keys(stats_vcloud_running__data__keys).length; c++ ) { color[key] = colorscale( c ); }
}
$( '#stats-vcloud-running' ).empty();
var x = d3.scale.linear().domain( [ 0, 500 ] ).range( [ 0, document.getElementById( 'stats-vcloud-running' ).offsetWidth ] );
var y = d3.scale.linear().domain( [ 0, stats_vcloud_running__data__total ] ).range( [ running_height, 0 ] );
var area = d3.svg.area()
.x( function( d, i ) { return x( i ); } )
.y0( function( d ) { return y( d.y0 ); } )
.y1( function( d ) { return y( d.y0 + d.y ); } );
var path = d3.svg.line()
.x( function( d, i ) { return x( i ); } )
.y( function( d ) { return y( d.y0 + d.y ); } );
var stack = d3.layout.stack()
.values( function( d ) { return d.values; } );
if ( typeof stats_vcloud_running__data[ 'stack' ] === 'undefined' ) {
stats_vcloud_running__data[ 'stack' ] = [];
}
stats_vcloud_running__data[ 'tmp' ] = {};
for ( var key in stats_vcloud_running__data__live ) {
stats_vcloud_running__data[ 'tmp' ][ key ] = stats_vcloud_running__data__live[ key ][ 'running' ];
}
stats_vcloud_running__data[ 'stack' ].push( stats_vcloud_running__data[ 'tmp' ] );
var stats_vcloud_running__data__graph = stack(
stats_vcloud_running__data__keys.sort().map(
function( name ) {
return {
name: name,
values: stats_vcloud_running__data[ 'stack' ].map( function( d ) {
return { y: d[ name ] };
})
}
}
)
);
stats_vcloud_running__data__total = d3.max(
stats_vcloud_running__data__graph, function( layer ) {
return d3.max( layer.values, function( d ) {
return d.y0 + d.y;
} );
}
);
var svg = d3.select( '#stats-vcloud-running' )
.append( 'svg' )
.attr( 'height', running_height )
.attr( 'width', '100%' )
.style( 'margin-top', '15px' )
.style( 'margin-bottom', '10px' )
.append( 'g' );
var mysvg = svg.selectAll( '#stats-vcloud-running' )
.data( stats_vcloud_running__data__graph )
.enter()
.append( 'g' );
mysvg.append( 'path' )
.attr( 'd', function( d ) { return area( d.values ); } )
.attr( 'clas', 'area' )
.attr( 'opacity', '0.25' )
.style( 'fill', function( d ) { return color[ d.name ]; } );
mysvg.append( 'path' )
.attr( 'd', function( d ) { return path( d.values ); } )
.attr( 'class', 'line' )
.attr( 'stroke', function( d ) { return '#888'; } )
.attr( 'stroke-width', '1' );
stats_vcloud_running__data__keys.sort().map(
function( key ) {
stats_vcloud_running__svg[ key ] = d3.select( '#stats-vcloud-running' )
.append( 'svg' )
.style( 'margin', '0px 0px 0px 0px' )
.style( 'padding', '0px 10px 10px 10px' )
.attr( 'width', '130px' )
.attr( 'height', '12px' );
stats_vcloud_running__svg[ key ]
.append( 'rect' )
.attr( {
'x': '5',
'y': '3',
'width': '10',
'height': '10',
'opacity': '0.25',
'fill': function( d ) { return color[ key ]; }
} );
stats_vcloud_running__svg[ key ]
.append( 'text' )
.text(
( key )
)
.attr( {
'x': '20',
'y': '12',
'font-face': '\'PT Sans\', sans-serif',
'font-size': '12px',
'font-weight': 'bold',
'fill': '#888'
} );
}
);
if ( stats_vcloud_running__data[ 'stack' ].length > 500 ) {
stats_vcloud_running__data[ 'stack' ].shift();
}
tick();
}, 5000 );
} )();
}
);

View file

@ -10,6 +10,18 @@
<br /> <br />
<!-- stats-vcloud-running -->
<div class='label'>VMs running tests</div>
<div id='stats-vcloud-running' class='module'>
<div class='spinner'></div> Loading data...
</div>
<script src='/lib/stats-vcloud-running.js'></script>
<br />
<!-- stats-vcloud-pool --> <!-- stats-vcloud-pool -->
<div class='label'>vCloud pool status</div> <div class='label'>vCloud pool status</div>

View file

@ -17,7 +17,7 @@
<div id='content'> <div id='content'>
<div id='header'> <div id='header'>
<embed src='/img/logo.jpg' width='216px' height='162px' class='logo' /> <embed src='/img/logo.jpg' width='200px' height='150px' class='logo' />
<div class='text'><%= site_name %></div> <div class='text'><%= site_name %></div>
</div> </div>

View file

@ -1,5 +1,6 @@
#!/usr/bin/ruby #!/usr/bin/ruby
require 'json'
require 'rbvmomi' require 'rbvmomi'
require 'redis' require 'redis'
require 'time' require 'time'
@ -166,9 +167,12 @@ def clone_vm template, pool, folder, datastore
# Annotate with creation time, origin template, etc. # Annotate with creation time, origin template, etc.
configSpec = RbVmomi::VIM.VirtualMachineConfigSpec( configSpec = RbVmomi::VIM.VirtualMachineConfigSpec(
:annotation => :annotation => JSON.pretty_generate({
'Base template: ' + vm['template'] + "\n" + name: vm['hostname'],
'Creation time: ' + Time.now.strftime("%Y-%m-%d %H:%M") created_by: $config[:vsphere]['username'],
base_template: vm['template'],
creation_timestamp: Time.now.utc
})
) )
# Put the VM in the specified folder and resource pool # Put the VM in the specified folder and resource pool
@ -369,9 +373,10 @@ def check_pool pool
$redis.scard('vmware_host_pool__pending__'+pool['name']) $redis.scard('vmware_host_pool__pending__'+pool['name'])
begin begin
$graphite.log( if (defined? $graphite)
'vcloud.ready.'+pool['name'], $redis.scard('vmware_host_pool__ready__'+pool['name']) $graphite.log('vcloud.ready.'+pool['name'], $redis.scard('vmware_host_pool__ready__'+pool['name']))
) if defined? $graphite $graphite.log('vcloud.running.'+pool['name'], $redis.scard('vmware_host_pool__running__'+pool['name']))
end
rescue rescue
end end

View file

@ -114,6 +114,55 @@ get '/dashboard/stats/vcloud/pool' do
JSON.pretty_generate(result) JSON.pretty_generate(result)
end end
get '/dashboard/stats/vcloud/running' do
result = Hash.new
config[:pools].each do |pool|
running = $redis.scard( 'vmware_host_pool__running__' + pool['name'] )
pool['major'] = $1 if pool['name'] =~ /^(\w+)\-/
result[pool['major']] ||= Hash.new
result[pool['major']]['running'] = result[pool['major']]['running'].to_i + running.to_i
end
if ( params[:history] )
if ( config[:config]['graphite'] )
begin
buffer = open( 'http://'+config[:config]['graphite']+'/render?target=vcloud.running.*&from=-1hour&format=json' ).read
JSON.parse( buffer ).each do |pool|
if pool['target'] =~ /.*\.(.*)$/
pool['name'] = $1
pool['major'] = $1 if pool['name'] =~ /^(\w+)\-/
result[pool['major']]['history'] ||= Array.new
for i in 0..pool['datapoints'].length
if (
pool['datapoints'][i] and
pool['datapoints'][i][0]
)
pool['last'] = pool['datapoints'][i][0]
result[pool['major']]['history'][i] ||= 0
result[pool['major']]['history'][i] = result[pool['major']]['history'][i].to_i + pool['datapoints'][i][0].to_i
else
result[pool['major']]['history'][i] = result[pool['major']]['history'][i].to_i + pool['last'].to_i
end
end
end
end
rescue
end
end
end
content_type :json
JSON.pretty_generate(result)
end
get '/status' do get '/status' do
content_type :json content_type :json