mirror of
https://github.com/puppetlabs/vmpooler.git
synced 2026-01-26 01:58:41 -05:00
(POOLER-134) Ship VM usage stats
This commit updates vmpooler to ship VM usage stats when a VM is destroyed. The stats are gathered for jobs based on user and pool name. If a jenkins build URL is present then this is broken down by user, instance, value stream, branch and project. Additionally, if present then the RMM_COMPONENT_TO_TEST_NAME will be listed after project. Without this change we do not collect stats on per VM usage and its correlation to users and pools.
This commit is contained in:
parent
e3e51afc05
commit
9a57c6d1b5
7 changed files with 270 additions and 4 deletions
|
|
@ -45,10 +45,11 @@ def create_ready_vm(template, name, token = nil)
|
|||
redis.hset("vmpooler__vm__#{name}", "template", template)
|
||||
end
|
||||
|
||||
def create_running_vm(template, name, token = nil)
|
||||
create_vm(name, token)
|
||||
def create_running_vm(template, name, token = nil, user = nil)
|
||||
create_vm(name, token, nil, user)
|
||||
redis.sadd("vmpooler__running__#{template}", name)
|
||||
redis.hset("vmpooler__vm__#{name}", "template", template)
|
||||
redis.hset("vmpooler__vm__#{name}", 'template', template)
|
||||
redis.hset("vmpooler__vm__#{name}", 'checkout', Time.now)
|
||||
end
|
||||
|
||||
def create_pending_vm(template, name, token = nil)
|
||||
|
|
@ -57,10 +58,11 @@ def create_pending_vm(template, name, token = nil)
|
|||
redis.hset("vmpooler__vm__#{name}", "template", template)
|
||||
end
|
||||
|
||||
def create_vm(name, token = nil, redis_handle = nil)
|
||||
def create_vm(name, token = nil, redis_handle = nil, user = nil)
|
||||
redis_db = redis_handle ? redis_handle : redis
|
||||
redis_db.hset("vmpooler__vm__#{name}", 'checkout', Time.now)
|
||||
redis_db.hset("vmpooler__vm__#{name}", 'token:token', token) if token
|
||||
redis_db.hset("vmpooler__vm__#{name}", 'token:user', user) if user
|
||||
end
|
||||
|
||||
def create_completed_vm(name, pool, active = false, redis_handle = nil)
|
||||
|
|
@ -81,6 +83,11 @@ def create_migrating_vm(name, pool, redis_handle = nil)
|
|||
redis_db.sadd("vmpooler__migrating__#{pool}", name)
|
||||
end
|
||||
|
||||
def create_tag(vm, tag_name, tag_value, redis_handle = nil)
|
||||
redis_db = redis_handle ? redis-handle : redis
|
||||
redis_db.hset("vmpooler__vm__#{vm}", "tag:#{tag_name}", tag_value)
|
||||
end
|
||||
|
||||
def add_vm_to_migration_set(name, redis_handle = nil)
|
||||
redis_db = redis_handle ? redis_handle : redis
|
||||
redis_db.sadd('vmpooler__migration', name)
|
||||
|
|
|
|||
|
|
@ -757,11 +757,18 @@ EOT
|
|||
end
|
||||
|
||||
it 'should emit a timing metric' do
|
||||
allow(subject).to receive(:get_vm_usage_labels)
|
||||
expect(metrics).to receive(:timing).with("destroy.#{pool}", String)
|
||||
|
||||
subject._destroy_vm(vm,pool,provider)
|
||||
end
|
||||
|
||||
it 'should check usage labels' do
|
||||
expect(subject).to receive(:get_vm_usage_labels).with(vm)
|
||||
|
||||
subject._destroy_vm(vm,pool,provider)
|
||||
end
|
||||
|
||||
it 'should dereference the mutex' do
|
||||
expect(subject).to receive(:dereference_mutex)
|
||||
|
||||
|
|
@ -803,6 +810,171 @@ EOT
|
|||
end
|
||||
end
|
||||
|
||||
describe '#get_vm_usage_labels' do
|
||||
|
||||
let(:template) { 'pool1' }
|
||||
let(:user) { 'vmpuser' }
|
||||
let(:vm) { 'vm1' }
|
||||
|
||||
context 'when label evaluation is disabled' do
|
||||
it 'should do nothing' do
|
||||
subject.get_vm_usage_labels(vm)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when label evaluation is enabled' do
|
||||
|
||||
before(:each) do
|
||||
config[:config]['usage_stats'] = true
|
||||
end
|
||||
|
||||
context 'when a VM has not been checked out' do
|
||||
before(:each) do
|
||||
create_ready_vm(template, vm)
|
||||
end
|
||||
|
||||
it 'should return' do
|
||||
expect(subject).to receive(:get_vm_usage_labels).and_return(nil)
|
||||
|
||||
subject.get_vm_usage_labels(vm)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a VM has been checked out' do
|
||||
|
||||
context 'without auth' do
|
||||
|
||||
before(:each) do
|
||||
create_running_vm(template, vm)
|
||||
end
|
||||
|
||||
it 'should emit a metric' do
|
||||
expect(metrics).to receive(:increment).with("usage.unauthenticated.#{template}")
|
||||
|
||||
subject.get_vm_usage_labels(vm)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with auth' do
|
||||
|
||||
before(:each) do
|
||||
create_running_vm(template, vm, token, user)
|
||||
end
|
||||
|
||||
it 'should emit a metric' do
|
||||
expect(metrics).to receive(:increment).with("usage.#{user}.#{template}")
|
||||
|
||||
subject.get_vm_usage_labels(vm)
|
||||
end
|
||||
|
||||
context 'with a jenkins_build_url label' do
|
||||
let(:jenkins_build_url) { 'https://jenkins.example.com/job/enterprise_pe-acceptance-tests_integration-system_pe_full-agent-upgrade_weekend_2018.1.x/LAYOUT=centos6-64mcd-ubuntu1404-32f-64f,LEGACY_AGENT_VERSION=NONE,PLATFORM=NOTUSED,SCM_BRANCH=2018.1.x,UPGRADE_FROM=2018.1.0,UPGRADE_TO_VERSION=NONE,label=beaker/222/' }
|
||||
let(:url_parts) { jenkins_build_url.split('/')[2..-1] }
|
||||
let(:instance) { url_parts[0].gsub('.', '_') }
|
||||
let(:value_stream_parts) { url_parts[2].split('_') }
|
||||
let(:value_stream) { value_stream_parts.shift }
|
||||
let(:branch) { value_stream_parts.pop }
|
||||
let(:project) { value_stream_parts.shift }
|
||||
let(:job_name) { value_stream_parts.join('_') }
|
||||
|
||||
before(:each) do
|
||||
create_tag(vm, 'jenkins_build_url', jenkins_build_url)
|
||||
end
|
||||
|
||||
it 'should emit a metric with information from the URL' do
|
||||
expect(metrics).to receive(:increment).with("usage.#{user}.#{instance}.#{value_stream}.#{branch}.#{project}.#{job_name}.#{template}")
|
||||
|
||||
subject.get_vm_usage_labels(vm)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a jenkins_build_url that contains RMM_COMPONENT_TO_TEST_NAME' do
|
||||
let(:jenkins_build_url) { 'https://jenkins.example.com/job/platform_puppet-agent-extra_puppet-agent-integration-suite_pr/RMM_COMPONENT_TO_TEST_NAME=puppet,SLAVE_LABEL=beaker,TEST_TARGET=redhat7-64a/824/' }
|
||||
let(:url_parts) { jenkins_build_url.split('/')[2..-1] }
|
||||
let(:instance) { url_parts[0].gsub('.', '_') }
|
||||
let(:value_stream_parts) { url_parts[2].split('_') }
|
||||
let(:value_stream) { value_stream_parts.shift }
|
||||
let(:branch) { value_stream_parts.pop }
|
||||
let(:project) { value_stream_parts.shift }
|
||||
let(:job_name) { value_stream_parts.join('_') }
|
||||
let(:build_metadata) { url_parts[3] }
|
||||
let(:build_component) { subject.component_to_test('RMM_COMPONENT_TO_TEST_NAME', build_metadata) }
|
||||
|
||||
before(:each) do
|
||||
create_tag(vm, 'jenkins_build_url', jenkins_build_url)
|
||||
end
|
||||
|
||||
it 'should emit a metric with information from the URL' do
|
||||
expect(metrics).to receive(:increment).with("usage.#{user}.#{instance}.#{value_stream}.#{branch}.#{project}.#{job_name}.#{build_component}.#{template}")
|
||||
|
||||
subject.get_vm_usage_labels(vm)
|
||||
end
|
||||
|
||||
context 'when there is no matrix job information' do
|
||||
|
||||
let(:jenkins_build_url) { 'https://jenkins.example.com/job/platform_puppet-agent-extra_puppet-agent-integration-suite_pr/824/' }
|
||||
let(:url_parts) { jenkins_build_url.split('/')[2..-1] }
|
||||
let(:instance) { url_parts[0].gsub('.', '_') }
|
||||
let(:value_stream_parts) { url_parts[2].split('_') }
|
||||
let(:value_stream) { value_stream_parts.shift }
|
||||
let(:branch) { value_stream_parts.pop }
|
||||
let(:project) { value_stream_parts.shift }
|
||||
let(:job_name) { value_stream_parts.join('_') }
|
||||
|
||||
before(:each) do
|
||||
create_tag(vm, 'jenkins_build_url', jenkins_build_url)
|
||||
end
|
||||
|
||||
it 'should emit a metric with information from the URL without a build_component' do
|
||||
expect(metrics).to receive(:increment).with("usage.#{user}.#{instance}.#{value_stream}.#{branch}.#{project}.#{job_name}.#{template}")
|
||||
|
||||
subject.get_vm_usage_labels(vm)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#component_to_test' do
|
||||
let(:matching_key) { 'LABEL_ONE' }
|
||||
let(:matching_value) { 'test' }
|
||||
let(:labels_string) { "#{matching_key}=#{matching_value},LABEL_TWO=test2,LABEL_THREE=test3" }
|
||||
let(:nonmatrix_string) { 'test,stuff,and,things' }
|
||||
|
||||
context 'when string contains a matching key' do
|
||||
it 'should print the corresponding value' do
|
||||
expect(subject.component_to_test(matching_key, labels_string)).to eq(matching_value)
|
||||
end
|
||||
|
||||
context 'when match contains no value' do
|
||||
it 'should return nil' do
|
||||
expect(subject.component_to_test(matching_key, matching_key)).to be nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when string contains no key value pairs' do
|
||||
it 'should return' do
|
||||
expect(subject.component_to_test(matching_key, nonmatrix_string)).to be nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when labels_string is a job number' do
|
||||
it 'should return nil' do
|
||||
expect(subject.component_to_test(matching_key, '25')).to be nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when labels_string is nil' do
|
||||
it 'should return nil' do
|
||||
expect(subject.component_to_test(matching_key, nil)).to be nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#purge_unused_vms_and_folders' do
|
||||
let(:config) { YAML.load(<<-EOT
|
||||
---
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue