Merge branch 'CID-428-increments_in_stack_node_names' into features
This commit is contained in:
commit
13b3d56ab9
@ -54,8 +54,8 @@ module Devops
|
|||||||
self.parameters = attrs['parameters']
|
self.parameters = attrs['parameters']
|
||||||
self.owner = attrs['owner']
|
self.owner = attrs['owner']
|
||||||
self.run_list = attrs['run_list'] || []
|
self.run_list = attrs['run_list'] || []
|
||||||
self.stack_status = attrs['stack_status']
|
|
||||||
self.tags = attrs['tags'] || {}
|
self.tags = attrs['tags'] || {}
|
||||||
|
self.stack_status = attrs['stack_status']
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
require 'workers/stack_bootstrap/chef_node_name_builder'
|
require 'workers/stack_bootstrap/chef_node_name_builder'
|
||||||
RSpec.describe ChefNodeNameBuilder do
|
RSpec.describe ChefNodeNameBuilder do
|
||||||
# real response
|
# test with real response to ensure it is processed correctly
|
||||||
let(:server_info) do
|
let(:server_info) do
|
||||||
{
|
{
|
||||||
"name"=>"stack-achuchkalov-aws-test-1455976199-master01",
|
"name"=>"stack-achuchkalov-aws-test-1455976199-master01",
|
||||||
@ -21,33 +21,26 @@ RSpec.describe ChefNodeNameBuilder do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
let(:project) { build(:project, id: 'proj', with_deploy_env_identifiers: %w(dev)) }
|
let(:node_name_builder) {
|
||||||
let(:env) { project.deploy_env('dev') }
|
ChefNodeNameBuilder.new(
|
||||||
let(:build_node_name) {
|
provider_server_info: server_info,
|
||||||
described_class.new(server_info, project, env).build_node_name
|
project_id: 'proj',
|
||||||
|
env_id: 'dev'
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
let(:build_node_name) { node_name_builder.build_node_name!({}) }
|
||||||
|
|
||||||
def set_mask(mask)
|
def set_mask(mask)
|
||||||
server_info['tags']['cid:node-name-mask'] = mask
|
server_info['tags']['cid:node-name-mask'] = mask
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#build_node_name' do
|
describe '#build_node_name' do
|
||||||
it 'uses default mask ("$project-$cfname-$env")' do
|
it 'uses default mask (":project-:instancename-:env")' do
|
||||||
expect(build_node_name).to eq 'proj-master01-dev'
|
expect(build_node_name).to eq 'proj-master01-dev'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'substitutes $project, $env, $instanceid and $cfname' do
|
it 'substitutes :project, :env, :instanceid and :instancename' do
|
||||||
set_mask('$project/$env/$instanceid/$cfname')
|
set_mask(':project/:env/:instanceid/:instancename')
|
||||||
expect(build_node_name).to eq 'proj/dev/i-fac32c7e/master01'
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'substitutes $time' do
|
|
||||||
set_mask('$project-$time')
|
|
||||||
expect(build_node_name).to match /proj-\d+/
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'substitutes :project, :env, :instanceid and :cfname' do
|
|
||||||
set_mask(':project/:env/:instanceid/:cfname')
|
|
||||||
expect(build_node_name).to eq 'proj/dev/i-fac32c7e/master01'
|
expect(build_node_name).to eq 'proj/dev/i-fac32c7e/master01'
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -56,14 +49,24 @@ RSpec.describe ChefNodeNameBuilder do
|
|||||||
expect(build_node_name).to match /proj-\d+/
|
expect(build_node_name).to match /proj-\d+/
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'works with both colon and dollar variables' do
|
describe 'substitutes incrementers variables :increment-groupname: with numbers depending on @incrementers_values param' do
|
||||||
set_mask('$project/$env/:instanceid/:cfname')
|
it 'starts with 01 for empty hash' do
|
||||||
expect(build_node_name).to eq 'proj/dev/i-fac32c7e/master01'
|
set_mask('node-:increment-slave:')
|
||||||
|
expect(node_name_builder.build_node_name!({})).to eq 'node-01'
|
||||||
|
end
|
||||||
|
|
||||||
|
it "continues with next values if hash isn't empty" do
|
||||||
|
set_mask('node-:increment-slave:')
|
||||||
|
expect(node_name_builder.build_node_name!({'slave' => nil})).to eq 'node-01'
|
||||||
|
expect(node_name_builder.build_node_name!({'slave' => 1})).to eq 'node-02'
|
||||||
|
expect(node_name_builder.build_node_name!({'slave' => 50})).to eq 'node-51'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'could substitute different incrementers at once' do
|
||||||
|
set_mask('node-:increment-slave:-:increment-master:')
|
||||||
|
expect(node_name_builder.build_node_name!({'slave' => 1, 'master' => 3})).to eq 'node-02-04'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'substitutes underscores to dashes' do
|
|
||||||
server_info['tags']['Name'] = 'server_1'
|
|
||||||
expect(build_node_name).to match 'proj-server-1-dev'
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -98,7 +98,7 @@ RSpec.describe StackServersPersister, stubbed_connector: true do
|
|||||||
persister.persist
|
persister.persist
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'build chef_node_name with default mask "$project-$cfname-$env"' do
|
it 'build chef_node_name with default mask ":project-:instancename-:env"' do
|
||||||
expect(stubbed_connector).to receive(:server_insert) do |server|
|
expect(stubbed_connector).to receive(:server_insert) do |server|
|
||||||
expect(server.chef_node_name).to eq 'name-server1-foo'
|
expect(server.chef_node_name).to eq 'name-server1-foo'
|
||||||
end
|
end
|
||||||
@ -106,12 +106,28 @@ RSpec.describe StackServersPersister, stubbed_connector: true do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "builds chef_node_name with custom mask if info['tags']['cid:node-name-mask'] exists" do
|
it "builds chef_node_name with custom mask if info['tags']['cid:node-name-mask'] exists" do
|
||||||
server_info_hash['tags']['cid:node-name-mask'] = '$project-$cfname-123'
|
server_info_hash['tags']['cid:node-name-mask'] = ':project-:instancename-123'
|
||||||
expect(stubbed_connector).to receive(:server_insert) do |server|
|
expect(stubbed_connector).to receive(:server_insert) do |server|
|
||||||
expect(server.chef_node_name).to eq 'name-server1-123'
|
expect(server.chef_node_name).to eq 'name-server1-123'
|
||||||
end
|
end
|
||||||
persister.persist
|
persister.persist
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'incremented variables' do
|
||||||
|
it 'substitutes :increment-groupid: with incrementing numbers' do
|
||||||
|
allow(provider).to receive(:stack_servers) {[
|
||||||
|
{'id' => 'server1', 'tags' => {'cid:node-name-mask' => 'node-:increment-group1:-dev'}, 'key_name' => 'key'},
|
||||||
|
{'id' => 'server1', 'tags' => {'cid:node-name-mask' => 'node-:increment-group1:-dev'}, 'key_name' => 'key'}
|
||||||
|
]}
|
||||||
|
expect(stubbed_connector).to receive(:server_insert) do |server|
|
||||||
|
expect(server.chef_node_name).to eq 'node-01-dev'
|
||||||
|
end.ordered
|
||||||
|
expect(stubbed_connector).to receive(:server_insert) do |server|
|
||||||
|
expect(server.chef_node_name).to eq 'node-02-dev'
|
||||||
|
end
|
||||||
|
persister.persist
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -1,34 +1,63 @@
|
|||||||
class ChefNodeNameBuilder
|
# Builds node name from mask. Mask could be passed in server's +cid:node-name-mask+ tag,
|
||||||
DEFAULT_MASK = '$project-$cfname-$env'
|
# default mask is used otherwise. Mask is a string with possible several variables inserted, e.g.
|
||||||
|
# +':project/:env/:instanceid/:instancename/:increment-group1:'+
|
||||||
|
# Variables meanings:
|
||||||
|
# - +:project+ is replaced with project name (given in constructor)
|
||||||
|
# - +:env+ is replaced with env name (given in constructor)
|
||||||
|
# - +:instanceid+ is replaced with provider instance id (fetched from server info)
|
||||||
|
# - +:instancename+ is replaced with value of Name tag (fetched from server info)
|
||||||
|
# - +:increment-groupname:+ is replaced with incremented number tied to group name. There could be several groups in one stack.
|
||||||
|
# P.S. Colons are used instead of dollar signs, because it's convinient to set nodename mask tag to AWS stack and not in template
|
||||||
|
# (you set tag once and it propagates to all instances), but stacks don't support dollar signs in tags (unlike EC2 instances).
|
||||||
|
|
||||||
def initialize(server_info, project, env)
|
class ChefNodeNameBuilder
|
||||||
@server_info, @project, @env = server_info, project, env
|
DEFAULT_MASK = ':project-:instancename-:env'
|
||||||
@mask = server_info['tags']['cid:node-name-mask'] || DEFAULT_MASK
|
|
||||||
|
# @param attrs [Hash] should contain
|
||||||
|
# +:provider_server_info+
|
||||||
|
# +:project_id+
|
||||||
|
# +:env_id+
|
||||||
|
def initialize(attrs)
|
||||||
|
@server_info = attrs[:provider_server_info]
|
||||||
|
@project, @env = attrs[:project_id], attrs[:env_id]
|
||||||
|
@mask = @server_info['tags']['cid:node-name-mask'] || DEFAULT_MASK
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_node_name
|
|
||||||
|
# @param incrementers_values [Hash] is a hash in which key is name of a variable and value is last substituted number for that var.
|
||||||
|
# This method modifies +incrementers_values+, updating values for substituted variables.
|
||||||
|
#
|
||||||
|
# Examples (assume mask is set to +':project-master-:increment-group1:'+):
|
||||||
|
# incremeters_values = {}
|
||||||
|
# builder.build_node_name!(incremeters_values) # returns 'mpda-master-01'
|
||||||
|
# puts incremeters_values # {'group1' => 1}
|
||||||
|
# builder.build_node_name!(incremeters_values) # returns 'mpda-master-02'
|
||||||
|
# puts incremeters_values # {'group1' => 2}
|
||||||
|
def build_node_name!(incrementers_values)
|
||||||
result = @mask.dup
|
result = @mask.dup
|
||||||
replace_dollar_variables!(result)
|
replace_variables!(result)
|
||||||
replace_colon_variables!(result)
|
replace_incrementers!(result, incrementers_values)
|
||||||
result.gsub!('_', '-')
|
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def replace_dollar_variables!(result)
|
def replace_variables!(result)
|
||||||
result.gsub!('$project', @project.id)
|
result.gsub!(':project', @project)
|
||||||
result.gsub!('$env', @env.identifier)
|
result.gsub!(':env', @env)
|
||||||
result.gsub!('$instanceid', @server_info['id'])
|
|
||||||
result.gsub!('$cfname', @server_info['tags']['Name'] || '')
|
|
||||||
result.gsub!('$time', Time.now.to_i.to_s)
|
|
||||||
end
|
|
||||||
|
|
||||||
def replace_colon_variables!(result)
|
|
||||||
result.gsub!(':project', @project.id)
|
|
||||||
result.gsub!(':env', @env.identifier)
|
|
||||||
result.gsub!(':instanceid', @server_info['id'])
|
result.gsub!(':instanceid', @server_info['id'])
|
||||||
result.gsub!(':cfname', @server_info['tags']['Name'] || '')
|
result.gsub!(':instancename', @server_info['tags']['Name'] || '')
|
||||||
result.gsub!(':time', Time.now.to_i.to_s)
|
result.gsub!(':time', Time.now.to_i.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def replace_incrementers!(result, incrementers_values)
|
||||||
|
groupname_regexp = /(?<=:increment-)\w+(?=:)/
|
||||||
|
result.gsub!(/:increment-\w+:/) do |incrementer|
|
||||||
|
group_name = groupname_regexp.match(incrementer)[0]
|
||||||
|
prev_value = incrementers_values[group_name] || 0
|
||||||
|
current_value = prev_value + 1
|
||||||
|
incrementers_values[group_name] = current_value
|
||||||
|
current_value.to_s.rjust(2, '0')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
@ -42,18 +42,18 @@ class StackServersPersister
|
|||||||
end
|
end
|
||||||
|
|
||||||
# takes a hash, returns Server model
|
# takes a hash, returns Server model
|
||||||
def persist_stack_server(info_hash)
|
def persist_stack_server(server_info)
|
||||||
server_attrs = {
|
server_attrs = {
|
||||||
'_id' => info_hash['id'],
|
'_id' => server_info['id'],
|
||||||
'chef_node_name' => ChefNodeNameBuilder.new(info_hash, @project, @deploy_env).build_node_name,
|
'chef_node_name' => get_name_builder(server_info).build_node_name!(incrementers_values),
|
||||||
'created_by' => stack.owner,
|
'created_by' => stack.owner,
|
||||||
'deploy_env' => @deploy_env.identifier,
|
'deploy_env' => @deploy_env.identifier,
|
||||||
'key' => info_hash['key_name'] || @provider.ssh_key,
|
'key' => server_info['key_name'] || @provider.ssh_key,
|
||||||
'project' => @project.id,
|
'project' => @project.id,
|
||||||
'provider' => @provider.name,
|
'provider' => @provider.name,
|
||||||
'remote_user' => mongo.image(@deploy_env.image).remote_user,
|
'remote_user' => mongo.image(@deploy_env.image).remote_user,
|
||||||
'private_ip' => info_hash['private_ip'],
|
'private_ip' => server_info['private_ip'],
|
||||||
'public_ip' => info_hash['public_ip'],
|
'public_ip' => server_info['public_ip'],
|
||||||
'run_list' => stack.run_list || [],
|
'run_list' => stack.run_list || [],
|
||||||
'stack' => stack.name
|
'stack' => stack.name
|
||||||
}
|
}
|
||||||
@ -63,6 +63,19 @@ class StackServersPersister
|
|||||||
server
|
server
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_name_builder(server_info)
|
||||||
|
ChefNodeNameBuilder.new(
|
||||||
|
provider_server_info: server_info,
|
||||||
|
project_id: @project.id,
|
||||||
|
env_id: @deploy_env.identifier,
|
||||||
|
owner: stack.owner
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def incrementers_values
|
||||||
|
@incrementers_values ||= {}
|
||||||
|
end
|
||||||
|
|
||||||
def mongo
|
def mongo
|
||||||
Devops::Db.connector
|
Devops::Db.connector
|
||||||
end
|
end
|
||||||
|
|||||||
@ -18,7 +18,7 @@ class StackSynchronizer
|
|||||||
stack.sync!
|
stack.sync!
|
||||||
print_new_events
|
print_new_events
|
||||||
case stack.stack_status
|
case stack.stack_status
|
||||||
when 'CREATE_IN_PROGRESS', 'ROLLBACK_IN_PROGRESS'
|
when 'CREATE_IN_PROGRESS', 'ROLLBACK_IN_PROGRESS', 'DELETE_IN_PROGRESS'
|
||||||
when 'CREATE_COMPLETE'
|
when 'CREATE_COMPLETE'
|
||||||
::Devops::Db.connector.stack_update(stack)
|
::Devops::Db.connector.stack_update(stack)
|
||||||
puts_and_flush "Stack '#{stack.id}' status is now #{stack.stack_status}"
|
puts_and_flush "Stack '#{stack.id}' status is now #{stack.stack_status}"
|
||||||
@ -26,6 +26,9 @@ class StackSynchronizer
|
|||||||
when 'ROLLBACK_COMPLETE'
|
when 'ROLLBACK_COMPLETE'
|
||||||
puts_and_flush "Stack '#{stack.id}' status is rolled back"
|
puts_and_flush "Stack '#{stack.id}' status is rolled back"
|
||||||
return error_code(:stack_rolled_back)
|
return error_code(:stack_rolled_back)
|
||||||
|
when 'DELETE_COMPLETE'
|
||||||
|
puts_and_flush "Stack '#{stack.id}' status is deleted"
|
||||||
|
return error_code(:stack_deleted)
|
||||||
else
|
else
|
||||||
puts_and_flush "Unknown stack status: '#{stack.stack_status}'"
|
puts_and_flush "Unknown stack status: '#{stack.stack_status}'"
|
||||||
return error_code(:unkown_status)
|
return error_code(:unkown_status)
|
||||||
@ -54,7 +57,8 @@ class StackSynchronizer
|
|||||||
stack_rolled_back: 1,
|
stack_rolled_back: 1,
|
||||||
unkown_status: 2,
|
unkown_status: 2,
|
||||||
timeout: 3,
|
timeout: 3,
|
||||||
error: 5
|
error: 5,
|
||||||
|
stack_deleted: 6
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user