Add function for parsing services cgroups settings

Current function was introduced to convert cgroups settings in JSON
format to the HASH what will be processed by main cgroups puppet
module.

Change-Id: I580207f26d672df87b20aa10468ed062be135f46
Implements: blueprint cgroups
This commit is contained in:
slava 2016-02-17 15:27:15 +03:00
parent 7f9b8f648b
commit 20752a7974
5 changed files with 262 additions and 0 deletions

View File

@ -0,0 +1,19 @@
source 'https://rubygems.org'
group :development, :test do
gem 'rake', :require => false
gem 'pry', :require => false
gem 'rspec', '~>3.3', :require => false
gem 'rspec-puppet', '~>2.2.0', :require => false
gem 'puppetlabs_spec_helper', :require => false
gem 'puppet-lint', '~> 0.3.2'
gem 'json', :require => false
end
if puppetversion = ENV['PUPPET_GEM_VERSION']
gem 'puppet', puppetversion, :require => false
else
gem 'puppet', '<4.0', :require => false
end
# vim:ft=ruby

View File

@ -0,0 +1,8 @@
require 'rubygems'
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'
PuppetLint.configuration.fail_on_warnings = false
PuppetLint.configuration.send('disable_80chars')
PuppetLint.configuration.send('disable_class_parameter_defaults')
PuppetLint.configuration.send('disable_class_inherits_from_params_class')

View File

@ -0,0 +1,72 @@
require 'json'
module CgroupsSettings
require 'facter'
# value is valid if value has integer type or
# matches with pattern: %percent, min_value, max_value
def self.handle_value(group, value)
return value if value.is_a?(Numeric)
if group == 'memory' and value.match(/%(\d+), (\d+), (\d+)/)
percent, min, max = value.scan(/%(\d+), (\d+), (\d+)/).flatten.map { |i| i.to_i }
total_memory = Facter.value(:memorysize_mb)
res = (total_memory.to_f / 100.0) * percent.to_f
return [min, max, res].sort[1]
end
end
end
Puppet::Parser::Functions::newfunction(:prepare_cgroups_hash, :type => :rvalue, :arity => 1, :doc => <<-EOS
This function get hash contains service and its cgroups settings(in JSON format) and serialize it.
ex: prepare_cgroups_hash(hiera('cgroups'))
Following input:
{
'metadata' => {
'always_editable' => true,
'group' => 'general',
'label' => 'Cgroups',
'weight' => 50
},
cinder-api: {"blkio":{"blkio.weight":500}}
}
will be transformed to:
[{"cinder-api"=>{"blkio"=>{"blkio.weight"=>500}}}]
Pattern for value field:
{
group1 => {
param1 => value1,
param2 => value2
},
group2 => {
param3 => value3,
param4 => value4
}
}
EOS
) do |argv|
raise(Puppet::ParseError, "prepare_cgroups_hash(...): Wrong type of argument. Hash is expected.") unless argv[0].is_a?(Hash)
# wipe out UI metadata
cgroups = argv[0].tap { |el| el.delete('metadata') }
serialized_data = {}
cgroups.each do |service, settings|
hash_settings = JSON.parse(settings) rescue raise("'#{service}': JSON parsing error for : #{settings}")
hash_settings.each do |group, options|
raise("'#{service}': group '#{group}' options is not a HASH instance") unless options.is_a?(Hash)
options.each do |option, value|
options[option] = CgroupsSettings.handle_value(group, value)
raise("'#{service}': group '#{group}': option '#{option}' has wrong value") if options[option].nil?
end
end
serialized_data[service] = hash_settings
end
serialized_data
end
# vim: set ts=2 sw=2 et :

View File

@ -0,0 +1,133 @@
require 'spec_helper'
describe Puppet::Parser::Functions.function(:prepare_cgroups_hash) do
let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
subject do
function_name = Puppet::Parser::Functions.function(:prepare_cgroups_hash)
scope.method(function_name)
end
it 'should exist' do
subject == Puppet::Parser::Functions.function(:prepare_cgroups_hash)
end
Facter.stubs(:fact).with(:memorysize_mb).returns Facter.add(:memorysize_mb) { setcode { 1024 } }
context "transform simple hash" do
let(:sample) {
{
'metadata' => {
'always_editable' => true,
'group' => 'general',
'label' => 'Cgroups',
'weight' => 50
},
'cinder' => '{"blkio":{"blkio.weight":500, "blkio.test":800}, "memory":{"memory.soft_limit_in_bytes":700}}',
'keystone' => '{"cpu":{"cpu.shares":70}}'
}
}
let(:result) {
{
'cinder' => {
'blkio' => {
'blkio.weight' => 500,
'blkio.test' => 800
},
'memory' => {
'memory.soft_limit_in_bytes' => 700
},
},
'keystone' => {
'cpu' => {
'cpu.shares' => 70
}
}
}
}
it 'should transform hash with simple values' do
should run.with_params(sample).and_return(result)
end
end
context "transform hash with expression" do
let(:sample) {
{
'metadata' => {
'always_editable' => true,
'group' => 'general',
'label' => 'Cgroups',
'weight' => 50
},
'neutron' => '{"memory":{"memory.soft_limit_in_bytes":"%50, 300, 700"}}'
}
}
let(:result) {
{
'neutron' => {
'memory' => {
'memory.soft_limit_in_bytes' => 512
}
}
}
}
it 'should transform hash including expression to compute' do
should run.with_params(sample).and_return(result)
end
end
context "wrong JSON format" do
let(:sample) {
{
'neutron' => '{"memory":{"memory.soft_limit_in_bytes":"%50, 300, 700"}}}}'
}
}
let(:result) {
{}
}
it 'should raise if settings have wrong JSON format' do
is_expected.to run.with_params(sample).and_raise_error(RuntimeError, /JSON parsing error/)
end
end
context "service's cgroup settings are not a HASH" do
let(:sample) {
{
'neutron' => '{"memory": 28}'
}
}
it 'should raise if group option is not a Hash' do
is_expected.to run.with_params(sample).and_raise_error(RuntimeError, /options is not a HASH instance/)
end
end
context "cgroup limit is not an integer" do
let(:sample) {
{
'neutron' => '{"memory":{"memory.soft_limit_in_bytes":"test"}}'
}
}
it 'should raise if limit value is not an integer or template' do
is_expected.to run.with_params(sample).and_raise_error(RuntimeError, /has wrong value/)
end
end
end

View File

@ -0,0 +1,30 @@
require 'rubygems'
require 'puppetlabs_spec_helper/module_spec_helper'
fixture_path = File.expand_path(File.join(__FILE__, '..', 'fixtures'))
PROJECT_ROOT = File.expand_path('..', File.dirname(__FILE__))
$LOAD_PATH.unshift(File.join(PROJECT_ROOT, "lib"))
# Add fixture lib dirs to LOAD_PATH. Work-around for PUP-3336
if Puppet.version < '4.0.0'
Dir["#{fixture_path}/modules/*/lib"].entries.each do |lib_dir|
$LOAD_PATH << lib_dir
end
end
RSpec.configure do |c|
c.module_path = File.join(fixture_path, 'modules')
c.manifest_dir = File.join(fixture_path, 'manifests')
c.mock_with(:mocha)
c.alias_it_should_behave_like_to :it_configures, 'configures'
end
def puppet_debug_override
if ENV['SPEC_PUPPET_DEBUG']
Puppet::Util::Log.level = :debug
Puppet::Util::Log.newdestination(:console)
end
end
###