diff --git a/lib/vmpooler/api/helpers.rb b/lib/vmpooler/api/helpers.rb index a97455b..334a99b 100644 --- a/lib/vmpooler/api/helpers.rb +++ b/lib/vmpooler/api/helpers.rb @@ -79,6 +79,26 @@ module Vmpooler return false end + def export_tags(backend, hostname, tags) + tags.each_pair do |tag, value| + next if value.nil? or value.empty? + + backend.hset('vmpooler__vm__' + hostname, 'tag:' + tag, value) + backend.hset('vmpooler__tag__' + Date.today.to_s, hostname + ':' + tag, value) + end + end + + def filter_tags(tags) + return unless Vmpooler::API.settings.config[:tagfilter] + + tags.each_pair do |tag, value| + next unless filter = Vmpooler::API.settings.config[:tagfilter][tag] + tags[tag] = value.match(filter).captures.join if value.match(filter) + end + + tags + end + def mean(list) s = list.map(&:to_f).reduce(:+).to_f (s > 0 && list.length > 0) ? s / list.length.to_f : 0 diff --git a/lib/vmpooler/api/v1.rb b/lib/vmpooler/api/v1.rb index dfba6fb..d27c474 100644 --- a/lib/vmpooler/api/v1.rb +++ b/lib/vmpooler/api/v1.rb @@ -476,6 +476,10 @@ module Vmpooler unless arg.is_a?(Hash) failure = true end + + if config['allowed_tags'] + failure = true if not (arg.keys - config['allowed_tags']).empty? + end else failure = true end @@ -493,15 +497,8 @@ module Vmpooler backend.hset('vmpooler__vm__' + params[:hostname], param, arg) when 'tags' - arg.keys.each do |tag| - if Vmpooler::API.settings.config[:tagfilter] and Vmpooler::API.settings.config[:tagfilter][tag] - filter = Vmpooler::API.settings.config[:tagfilter][tag] - arg[tag] = arg[tag].match(filter).captures.join if arg[tag].match(filter) - end - - backend.hset('vmpooler__vm__' + params[:hostname], 'tag:' + tag, arg[tag]) - backend.hset('vmpooler__tag__' + Date.today.to_s, params[:hostname] + ':' + tag, arg[tag]) - end + filter_tags(arg) + export_tags(backend, params[:hostname], arg) end end diff --git a/spec/vmpooler/api/v1_spec.rb b/spec/vmpooler/api/v1_spec.rb index 788bc24..7ef1b5e 100644 --- a/spec/vmpooler/api/v1_spec.rb +++ b/spec/vmpooler/api/v1_spec.rb @@ -323,6 +323,15 @@ describe Vmpooler::API::V1 do expect(last_response.status).to eq(200) end + it 'skips empty tags' do + put "#{prefix}/vm/testhost", '{"tags":{"tested_by":""}}' + + expect(last_response).to be_ok + expect(last_response.header['Content-Type']).to eq('application/json') + expect(last_response.body).to eq(JSON.pretty_generate({'ok' => true})) + expect(last_response.status).to eq(200) + end + it 'does not set tags if request body format is invalid' do put "#{prefix}/vm/testhost", '{"tags":{"tested"}}' @@ -332,6 +341,23 @@ describe Vmpooler::API::V1 do expect(last_response.status).to eq(400) end + context '(allowed_tags configured)' do + let(:config) { { + config: { + 'allowed_tags' => ['created_by', 'project', 'url'] + } + } } + + it 'fails if specified tag is not in allowed_tags array' do + put "#{prefix}/vm/testhost", '{"tags":{"created_by":"rspec","tested_by":"rspec"}}' + + expect(last_response).to_not be_ok + expect(last_response.header['Content-Type']).to eq('application/json') + expect(last_response.body).to eq(JSON.pretty_generate({'ok' => false})) + expect(last_response.status).to eq(400) + end + end + context '(tagfilter configured)' do let(:config) { { tagfilter: { 'url' => '(.*)\/' }, diff --git a/vmpooler.yaml.example b/vmpooler.yaml.example index dda99cc..114a7c4 100644 --- a/vmpooler.yaml.example +++ b/vmpooler.yaml.example @@ -156,6 +156,9 @@ # Same as vm_lifetime, but applied if a valid authentication token is # included during the request. # +# - allowed_tags +# If set, restricts tags to those specified in this array. +# # - domain # If set, returns a top-level 'domain' JSON key in POST requests @@ -169,6 +172,9 @@ vm_checktime: 15 vm_lifetime: 12 vm_lifetime_auth: 24 + allowed_tags: + - 'created_by' + - 'project' domain: 'company.com' # :pools: