Deploy without puppet master:
* mco agent puppetsync; * upload modules and manifests using rsync; * limit running concurrently nodes by mco; * tests. Change-Id: I0bfbaae0b623b0b26d6a77b49f0449860cbd5520
This commit is contained in:
parent
596a9ffbfd
commit
9e8402ba8c
@ -32,11 +32,23 @@ module Astute
|
||||
@ctx.deploy_log_parser.deploy_type = deployment_info.first['deployment_mode']
|
||||
Astute.logger.info "Deployment mode #{@ctx.deploy_log_parser.deploy_type}"
|
||||
|
||||
# Generate and upload ssh keys from master node to all cluster nodes.
|
||||
# Will be used by puppet after to connect nodes between themselves.
|
||||
generate_and_upload_ssh_keys(deployment_info.map{ |n| n['uid'] }.uniq,
|
||||
deployment_info.first['deployment_id']
|
||||
)
|
||||
begin
|
||||
# Generate ssh keys to future uploading to all cluster nodes
|
||||
generate_ssh_keys(deployment_info.first['deployment_id'])
|
||||
|
||||
# Prevent to prepare too many nodes at once
|
||||
deployment_info.uniq { |n| n['uid'] }.each_slice(Astute.config[:MAX_NODES_PER_CALL]) do |part|
|
||||
# Upload ssh keys from master node to all cluster nodes.
|
||||
# Will be used by puppet after to connect nodes between themselves.
|
||||
upload_ssh_keys(part.map{ |n| n['uid'] }, part.first['deployment_id'])
|
||||
|
||||
# Sync puppet manifests and modules to every node (emulate puppet master)
|
||||
sync_puppet_manifests(part)
|
||||
end
|
||||
rescue => e
|
||||
Astute.logger.error("Unexpected error #{e.message} traceback #{e.format_backtrace}")
|
||||
raise e
|
||||
end
|
||||
|
||||
# Sort by priority (the lower the number, the higher the priority)
|
||||
# and send groups to deploy
|
||||
@ -90,42 +102,49 @@ module Astute
|
||||
nodes_array.find { |n| node['uid'] == n['uid'] }
|
||||
end
|
||||
|
||||
# Generate and upload ssh keys from master node to all cluster nodes.
|
||||
def generate_and_upload_ssh_keys(node_uids, deployment_id)
|
||||
# Sync puppet manifests and modules to every node
|
||||
def sync_puppet_manifests(deployment_info)
|
||||
sync_mclient = MClient.new(@ctx, "puppetsync", deployment_info.map{ |n| n['uid'] }.uniq)
|
||||
master_ip = deployment_info.first['master_ip']
|
||||
# Paths /puppet/modules and /puppet/manifests/ in master node set by FUEL
|
||||
# Check fuel source code /deployment/puppet/nailgun/manifests/puppetsync.pp
|
||||
sync_mclient.rsync(:modules_source => "rsync://#{master_ip}:/puppet/modules/",
|
||||
:manifests_source => "rsync://#{master_ip}:/puppet/manifests/"
|
||||
)
|
||||
end
|
||||
|
||||
def generate_ssh_keys(deployment_id, overwrite=false)
|
||||
raise "Deployment_id is missing" unless deployment_id
|
||||
Astute.config.PUPPET_SSH_KEYS.each do |key_name|
|
||||
generate_ssh_key(key_name, deployment_id)
|
||||
upload_ssh_key(node_uids, key_name, deployment_id)
|
||||
dir_path = File.join(KEY_DIR, deployment_id.to_s, key_name)
|
||||
key_path = File.join(dir_path, key_name)
|
||||
FileUtils.mkdir_p dir_path
|
||||
return if File.exist?(key_path) && !overwrite
|
||||
|
||||
# Generate 2 keys(<name> and <name>.pub) and save it to <KEY_DIR>/<name>/
|
||||
File.delete key_path if File.exist? key_path
|
||||
result = system("ssh-keygen -b 2048 -t rsa -N '' -f #{key_path}")
|
||||
raise "Could not generate ssh key!" unless result
|
||||
end
|
||||
end
|
||||
|
||||
def generate_ssh_key(key_name, deployment_id, overwrite=false)
|
||||
dir_path = File.join(KEY_DIR, deployment_id.to_s, key_name)
|
||||
key_path = File.join(dir_path, key_name)
|
||||
FileUtils.mkdir_p dir_path
|
||||
return if File.exist?(key_path) && !overwrite
|
||||
|
||||
# Generate 2 keys(<name> and <name>.pub) and save it to <KEY_DIR>/<name>/
|
||||
File.delete key_path if File.exist? key_path
|
||||
result = system("ssh-keygen -b 2048 -t rsa -N '' -f #{key_path}")
|
||||
raise "Could not generate ssh key!" unless result
|
||||
end
|
||||
|
||||
def upload_ssh_key(node_uids, key_name, deployment_id, overwrite=false)
|
||||
upload_mclient = MClient.new(@ctx, "uploadfile", node_uids)
|
||||
[key_name, key_name + ".pub"].each do |ssh_key|
|
||||
source_path = File.join(KEY_DIR, deployment_id.to_s, key_name, ssh_key)
|
||||
destination_path = File.join(KEY_DIR, key_name, ssh_key)
|
||||
content = File.read(source_path)
|
||||
upload_mclient.upload(:path => destination_path,
|
||||
:content => content,
|
||||
:user_owner => 'root',
|
||||
:group_owner => 'root',
|
||||
:permissions => '0600',
|
||||
:dir_permissions => '0700',
|
||||
:overwrite => true,
|
||||
:parents => true
|
||||
)
|
||||
def upload_ssh_keys(node_uids, deployment_id, overwrite=false)
|
||||
Astute.config.PUPPET_SSH_KEYS.each do |key_name|
|
||||
upload_mclient = MClient.new(@ctx, "uploadfile", node_uids)
|
||||
[key_name, key_name + ".pub"].each do |ssh_key|
|
||||
source_path = File.join(KEY_DIR, deployment_id.to_s, key_name, ssh_key)
|
||||
destination_path = File.join(KEY_DIR, key_name, ssh_key)
|
||||
content = File.read(source_path)
|
||||
upload_mclient.upload(:path => destination_path,
|
||||
:content => content,
|
||||
:user_owner => 'root',
|
||||
:group_owner => 'root',
|
||||
:permissions => '0600',
|
||||
:dir_permissions => '0700',
|
||||
:overwrite => true,
|
||||
:parents => true
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -96,7 +96,7 @@ module Astute
|
||||
{'type' => 'components-list',
|
||||
'endlog_patterns' => [{'pattern' => /Finished catalog run in [0-9]+\.[0-9]* seconds\n/, 'progress' => 1.0}],
|
||||
'chunk_size' => 40000,
|
||||
'filename' => 'puppet-agent.log',
|
||||
'filename' => 'puppet-apply.log',
|
||||
'path_format' => "<%= @pattern_spec['path_prefix'] %><%= node['fqdn'] %>/<%= @pattern_spec['filename'] %>",
|
||||
'components_list' => [
|
||||
{'name' => 'Galera', 'weight' => 5, 'patterns' => [
|
||||
@ -261,7 +261,7 @@ module Astute
|
||||
{'type' => 'components-list',
|
||||
'endlog_patterns' => [{'pattern' => /Finished catalog run in [0-9]+\.[0-9]* seconds\n/, 'progress' => 1.0}],
|
||||
'chunk_size' => 40000,
|
||||
'filename' => 'puppet-agent.log',
|
||||
'filename' => 'puppet-apply.log',
|
||||
'path_format' => "<%= @pattern_spec['path_prefix'] %><%= node['fqdn'] %>/<%= @pattern_spec['filename'] %>",
|
||||
'components_list' => [
|
||||
{'name' => 'Keystone', 'weight' => 10, 'patterns' => [
|
||||
@ -314,7 +314,7 @@ module Astute
|
||||
{'type' => 'components-list',
|
||||
'endlog_patterns' => [{'pattern' => /Finished catalog run in [0-9]+\.[0-9]* seconds\n/, 'progress' => 1.0}],
|
||||
'chunk_size' => 40000,
|
||||
'filename' => 'puppet-agent.log',
|
||||
'filename' => 'puppet-apply.log',
|
||||
'path_format' => "<%= @pattern_spec['path_prefix'] %><%= node['fqdn'] %>/<%= @pattern_spec['filename'] %>",
|
||||
'components_list' => [
|
||||
{'name' => 'Glance', 'weight' => 10, 'patterns' => [
|
||||
@ -401,7 +401,7 @@ module Astute
|
||||
{'type' => 'components-list',
|
||||
'endlog_patterns' => [{'pattern' => /Finished catalog run in [0-9]+\.[0-9]* seconds\n/, 'progress' => 1.0}],
|
||||
'chunk_size' => 40000,
|
||||
'filename' => 'puppet-agent.log',
|
||||
'filename' => 'puppet-apply.log',
|
||||
'path_format' => "<%= @pattern_spec['path_prefix'] %><%= node['fqdn'] %>/<%= @pattern_spec['filename'] %>",
|
||||
'components_list' => [
|
||||
{'name' => 'Glance', 'weight' => 10, 'patterns' => [
|
||||
@ -488,7 +488,7 @@ module Astute
|
||||
{'type' => 'components-list',
|
||||
'endlog_patterns' => [{'pattern' => /Finished catalog run in [0-9]+\.[0-9]* seconds\n/, 'progress' => 1.0}],
|
||||
'chunk_size' => 40000,
|
||||
'filename' => 'puppet-agent.log',
|
||||
'filename' => 'puppet-apply.log',
|
||||
'path_format' => "<%= @pattern_spec['path_prefix'] %><%= node['fqdn'] %>/<%= @pattern_spec['filename'] %>",
|
||||
'components_list' => [
|
||||
{'name' => 'Keystone', 'weight' => 10, 'patterns' => [
|
||||
@ -541,7 +541,7 @@ module Astute
|
||||
'type' => 'count-lines',
|
||||
'endlog_patterns' => [{'pattern' => /Finished catalog run in [0-9]+\.[0-9]* seconds\n/, 'progress' => 1.0}],
|
||||
'expected_line_number' => 345,
|
||||
'filename' => 'puppet-agent.log',
|
||||
'filename' => 'puppet-apply.log',
|
||||
'path_format' => "<%= @pattern_spec['path_prefix'] %><%= node['fqdn'] %>/<%= @pattern_spec['filename'] %>"
|
||||
},
|
||||
|
||||
@ -549,7 +549,7 @@ module Astute
|
||||
'type' => 'count-lines',
|
||||
'endlog_patterns' => [{'pattern' => /Finished catalog run in [0-9]+\.[0-9]* seconds\n/, 'progress' => 1.0}],
|
||||
'expected_line_number' => 345,
|
||||
'filename' => 'puppet-agent.log',
|
||||
'filename' => 'puppet-apply.log',
|
||||
'path_format' => "<%= @pattern_spec['path_prefix'] %><%= node['fqdn'] %>/<%= @pattern_spec['filename'] %>"
|
||||
},
|
||||
|
||||
@ -557,7 +557,7 @@ module Astute
|
||||
'type' => 'count-lines',
|
||||
'endlog_patterns' => [{'pattern' => /Finished catalog run in [0-9]+\.[0-9]* seconds\n/, 'progress' => 1.0}],
|
||||
'expected_line_number' => 345,
|
||||
'filename' => 'puppet-agent.log',
|
||||
'filename' => 'puppet-apply.log',
|
||||
'path_format' => "<%= @pattern_spec['path_prefix'] %><%= node['fqdn'] %>/<%= @pattern_spec['filename'] %>"
|
||||
},
|
||||
|
||||
@ -565,7 +565,7 @@ module Astute
|
||||
'type' => 'count-lines',
|
||||
'endlog_patterns' => [{'pattern' => /Finished catalog run in [0-9]+\.[0-9]* seconds\n/, 'progress' => 1.0}],
|
||||
'expected_line_number' => 345,
|
||||
'filename' => 'puppet-agent.log',
|
||||
'filename' => 'puppet-apply.log',
|
||||
'path_format' => "<%= @pattern_spec['path_prefix'] %><%= node['fqdn'] %>/<%= @pattern_spec['filename'] %>"
|
||||
},
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ module Astute
|
||||
@nodes = nodes.map { |n| n.to_s } if nodes
|
||||
@check_result = check_result
|
||||
@retries = Astute.config.MC_RETRIES
|
||||
#FIXME: this timeout does not work
|
||||
@timeout = timeout
|
||||
initialize_mclient
|
||||
end
|
||||
@ -87,7 +88,10 @@ module Astute
|
||||
failed = @mc_res.select{|x| x.results[:statuscode] != 0 }
|
||||
if failed.any?
|
||||
err_msg += "MCollective call failed in agent '#{@agent}', "\
|
||||
"method '#{method}', failed nodes: #{failed.map{|x| x.results[:sender]}.join(',')} \n"
|
||||
"method '#{method}', failed nodes: \n"
|
||||
failed.each do |n|
|
||||
err_msg += "ID: #{n.results[:sender]} - Reason: #{n.results[:statusmsg]}\n"
|
||||
end
|
||||
end
|
||||
unless err_msg.empty?
|
||||
Astute.logger.error err_msg
|
||||
@ -95,7 +99,6 @@ module Astute
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def mc_send(*args)
|
||||
@mc.send(*args)
|
||||
rescue => ex
|
||||
|
@ -1,5 +1,5 @@
|
||||
metadata :name => "puppetd",
|
||||
:description => "Run puppet agent, get its status, and enable/disable it",
|
||||
:description => "Run puppet, get its status, and enable/disable it",
|
||||
:author => "R.I.Pienaar",
|
||||
:license => "Apache License 2.0",
|
||||
:version => "1.8",
|
||||
@ -29,13 +29,13 @@ action "last_run_summary", :description => "Get a summary of the last puppet run
|
||||
:display_as => "Versions"
|
||||
end
|
||||
|
||||
action "enable", :description => "Enable puppet agent" do
|
||||
action "enable", :description => "Enable puppet" do
|
||||
output :output,
|
||||
:description => "String indicating status",
|
||||
:display_as => "Status"
|
||||
end
|
||||
|
||||
action "disable", :description => "Disable puppet agent" do
|
||||
action "disable", :description => "Disable puppet" do
|
||||
output :output,
|
||||
:description => "String indicating status",
|
||||
:display_as => "Status"
|
||||
@ -51,38 +51,38 @@ action "runonce", :description => "Invoke a single puppet run" do
|
||||
# :maxlength => 5
|
||||
|
||||
output :output,
|
||||
:description => "Output from puppet agent",
|
||||
:description => "Output from puppet",
|
||||
:display_as => "Output"
|
||||
end
|
||||
|
||||
action "status", :description => "Get puppet agent's status" do
|
||||
action "status", :description => "Get puppet status" do
|
||||
display :always
|
||||
|
||||
output :status,
|
||||
:description => "The status of the puppet agent: disabled, running, idling or stopped",
|
||||
:description => "The status of the puppet: disabled, running, idling or stopped",
|
||||
:display_as => "Status"
|
||||
|
||||
output :enabled,
|
||||
:description => "Whether puppet agent is enabled",
|
||||
:description => "Whether puppet is enabled",
|
||||
:display_as => "Enabled"
|
||||
|
||||
output :running,
|
||||
:description => "Whether puppet agent is running",
|
||||
:description => "Whether puppet is running",
|
||||
:display_as => "Running"
|
||||
|
||||
output :idling,
|
||||
:description => "Whether puppet agent is idling",
|
||||
:description => "Whether puppet is idling",
|
||||
:display_as => "Idling"
|
||||
|
||||
output :stopped,
|
||||
:description => "Whether puppet agent is stopped",
|
||||
:description => "Whether puppet is stopped",
|
||||
:display_as => "Stopped"
|
||||
|
||||
output :lastrun,
|
||||
:description => "When puppet agent last ran",
|
||||
:description => "When puppet last ran",
|
||||
:display_as => "Last Run"
|
||||
|
||||
output :output,
|
||||
:description => "String displaying agent status",
|
||||
:description => "String displaying puppet status",
|
||||
:display_as => "Status"
|
||||
end
|
||||
|
@ -24,8 +24,8 @@ module MCollective
|
||||
# /var/lib/puppet/state/state.yaml
|
||||
# puppetd.lockfile - Where to find the lock file; defaults to
|
||||
# /var/lib/puppet/state/puppetdlock
|
||||
# puppetd.puppetd - Where to find the puppet agent binary; defaults to
|
||||
# /usr/bin/puppet agent
|
||||
# puppetd.puppetd - Where to find the puppet binary; defaults to
|
||||
# /usr/bin/puppet apply
|
||||
# puppetd.summary - Where to find the summary file written by Puppet
|
||||
# 2.6.8 and newer; defaults to
|
||||
# /var/lib/puppet/state/last_run_summary.yaml
|
||||
@ -34,10 +34,13 @@ module MCollective
|
||||
class Puppetd<RPC::Agent
|
||||
def startup_hook
|
||||
@splaytime = @config.pluginconf["puppetd.splaytime"].to_i || 0
|
||||
@lockfile = @config.pluginconf["puppetd.lockfile"] || "/var/lib/puppet/state/puppetdlock"
|
||||
@lockfile = @config.pluginconf["puppetd.lockfile"] || "/tmp/puppetdlock"
|
||||
@statefile = @config.pluginconf["puppetd.statefile"] || "/var/lib/puppet/state/state.yaml"
|
||||
@pidfile = @config.pluginconf["puppet.pidfile"] || "/var/run/puppet/agent.pid"
|
||||
@puppetd = @config.pluginconf["puppetd.puppetd"] || "/usr/bin/puppet agent"
|
||||
@puppetd = @config.pluginconf["puppetd.puppetd"] || "/usr/sbin/daemonize -a -e /var/log/puppet/puppet.err \
|
||||
-o /var/log/puppet/puppet.log \
|
||||
-l #{@lockfile} \
|
||||
/usr/bin/puppet apply /etc/puppet/manifests/site.pp"
|
||||
@last_summary = @config.pluginconf["puppet.summary"] || "/var/lib/puppet/state/last_run_summary.yaml"
|
||||
end
|
||||
|
||||
@ -134,31 +137,30 @@ module MCollective
|
||||
set_status
|
||||
case (reply[:status])
|
||||
when 'disabled' then # can't run
|
||||
reply.fail "Empty Lock file exists; puppet agent is disabled."
|
||||
reply.fail "Empty Lock file exists; puppet is disabled."
|
||||
|
||||
when 'running' then # can't run two simultaniously
|
||||
reply.fail "Lock file and PID file exist; puppet agent is running."
|
||||
reply.fail "Lock file and PID file exist; puppet is running."
|
||||
|
||||
when 'idling' then # signal daemon
|
||||
pid = puppet_agent_pid
|
||||
begin
|
||||
::Process.kill('USR1', pid)
|
||||
reply[:output] = "Signalled daemonized puppet agent to run (process #{pid}); " + (reply[:output] || '')
|
||||
reply[:output] = "Signalled daemonized puppet to run (process #{pid}); " + (reply[:output] || '')
|
||||
rescue => ex
|
||||
reply.fail "Failed to signal the puppet agent daemon (process #{pid}): #{ex}"
|
||||
reply.fail "Failed to signal the puppet daemon (process #{pid}): #{ex}"
|
||||
end
|
||||
|
||||
when 'stopped' then # just run
|
||||
runonce_background
|
||||
|
||||
else
|
||||
reply.fail "Unknown puppet agent status: #{reply[:status]}"
|
||||
reply.fail "Unknown puppet status: #{reply[:status]}"
|
||||
end
|
||||
end
|
||||
|
||||
def runonce_background
|
||||
cmd = [@puppetd, "--onetime", "--ignorecache", "--logdest", 'syslog', '--trace']
|
||||
|
||||
cmd = [@puppetd, "--logdest", 'syslog', '--trace']
|
||||
unless request[:forcerun]
|
||||
if @splaytime && @splaytime > 0
|
||||
cmd << "--splaylimit" << @splaytime << "--splay"
|
||||
|
61
mcagents/puppetsync.ddl
Normal file
61
mcagents/puppetsync.ddl
Normal file
@ -0,0 +1,61 @@
|
||||
metadata:name => "puppetsync",
|
||||
:description => "Downloads latest version of Puppet manifests to managed servers",
|
||||
:author => "Mirantis Inc",
|
||||
:license => "Apache License 2.0",
|
||||
:version => "0.1",
|
||||
:url => "http://mirantis.com",
|
||||
:timeout => 300
|
||||
|
||||
action "rsync", :description => "Download using rsync" do
|
||||
display :failed
|
||||
|
||||
input :modules_source,
|
||||
:prompt => "Rsync source URL of modules",
|
||||
:description => "Where to get modules from. URL with any protocol supported by rsync",
|
||||
:type => :string,
|
||||
:validation => :shellsafe,
|
||||
:optional => false,
|
||||
:default => 'rsync://10.20.0.2:/puppet/modules/',
|
||||
:maxlength => 256
|
||||
|
||||
input :manifests_source,
|
||||
:prompt => "Rsync source URL of manifests",
|
||||
:description => "Where to get manifests from. URL with any protocol supported by rsync",
|
||||
:type => :string,
|
||||
:validation => :shellsafe,
|
||||
:optional => false,
|
||||
:default => 'rsync://10.20.0.2:/puppet/manifests/',
|
||||
:maxlength => 256
|
||||
|
||||
input :modules_path,
|
||||
:prompt => "Rsync destination of modules",
|
||||
:description => "Where should downloaded modules be saved?",
|
||||
:type => :string,
|
||||
:validation => :shellsafe,
|
||||
:optional => false,
|
||||
:default => '/etc/puppet/modules/',
|
||||
:maxlength => 256
|
||||
|
||||
input :manifests_path,
|
||||
:prompt => "Rsync destination of manifests",
|
||||
:description => "Where should downloaded manifests be saved?",
|
||||
:type => :string,
|
||||
:validation => :shellsafe,
|
||||
:optional => false,
|
||||
:default => '/etc/puppet/manifests/',
|
||||
:maxlength => 256
|
||||
|
||||
input :rsync_options,
|
||||
:prompt => "Options for rsync command run",
|
||||
:description => "What options should be pathed to rsync command?",
|
||||
:type => :string,
|
||||
:validation => :shellsafe,
|
||||
:optional => false,
|
||||
:default => '-c -r --delete',
|
||||
:maxlength => 256
|
||||
|
||||
output :msg,
|
||||
:description => "Report message",
|
||||
:display_as => "Message"
|
||||
|
||||
end
|
74
mcagents/puppetsync.rb
Normal file
74
mcagents/puppetsync.rb
Normal file
@ -0,0 +1,74 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2013 Mirantis, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
module MCollective
|
||||
module Agent
|
||||
class Puppetsync < RPC::Agent
|
||||
|
||||
action 'rsync' do
|
||||
['modules', 'manifests'].each do |type|
|
||||
# Rsync depend of presence or absence of
|
||||
source = request.data["#{type}_source".to_sym].chomp('/').concat('/')
|
||||
path = request.data["#{type}_path".to_sym].chomp('/').concat('/')
|
||||
cmd = "rsync #{request.data[:rsync_options]} #{source} #{path}"
|
||||
run_and_respond(cmd)
|
||||
end
|
||||
reply[:msg] = "Puppet modules and manifests was sync!"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def run_and_respond(cmd)
|
||||
stdout, stderr, exit_code = runcommand(cmd)
|
||||
|
||||
if exit_code != 0
|
||||
reply.fail! "Fail to upload folder using command #{cmd}.
|
||||
Exit code: #{exit_code}, stderr: #{stderr}"
|
||||
end
|
||||
end
|
||||
|
||||
def runcommand(cmd)
|
||||
# We cannot use Shell from puppet because
|
||||
# version 2.3.1 has bug, with returning wrong exit
|
||||
# code in some cases, in newer version mcollective
|
||||
# it was fixed
|
||||
# https://github.com/puppetlabs/marionette-collective
|
||||
# /commit/10f163550bc6395f1594dacb9f15a86d4a3fde27
|
||||
# So, it's just fixed code from Shell#runcommand
|
||||
thread = Thread.current
|
||||
stdout = ''
|
||||
stderr = ''
|
||||
status = systemu(cmd, {'stdout' => stdout, 'stderr' => stderr}) do |cid|
|
||||
begin
|
||||
while(thread.alive?)
|
||||
sleep 0.1
|
||||
end
|
||||
Process.waitpid(cid) if Process.getpgid(cid)
|
||||
rescue SystemExit
|
||||
rescue Errno::ESRCH
|
||||
rescue Errno::ECHILD
|
||||
rescue Exception => e
|
||||
Log.info("Unexpected exception received while waiting for child process: #{e.class}: #{e}")
|
||||
end
|
||||
end
|
||||
|
||||
[stdout, stderr, status.exitstatus]
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -4,7 +4,7 @@ metadata :name => "systemtype",
|
||||
:license => "Apache License 2.0",
|
||||
:version => "0.0.1",
|
||||
:url => 'http://www.mirantis.com/',
|
||||
:timeout => 40
|
||||
:timeout => 60
|
||||
|
||||
action "get_type", :description => "Get the type" do
|
||||
display :always
|
||||
|
@ -35,17 +35,25 @@ describe Astute::DeploymentEngine do
|
||||
let(:deployer) { Engine.new(ctx) }
|
||||
|
||||
describe '#deploy' do
|
||||
|
||||
before(:each) do
|
||||
deployer.stubs(:generate_ssh_keys)
|
||||
deployer.stubs(:upload_ssh_keys)
|
||||
deployer.stubs(:sync_puppet_manifests)
|
||||
end
|
||||
|
||||
it 'should generate and upload ssh keys' do
|
||||
nodes = [{'uid' => 1, 'deployment_id' => 1}, {'uid' => 2}, {'uid' => 1}]
|
||||
deployer.stubs(:deploy_piece)
|
||||
|
||||
deployer.expects(:generate_and_upload_ssh_keys).with([1,2], nodes.first['deployment_id'])
|
||||
deployer.expects(:generate_ssh_keys).with(nodes.first['deployment_id'])
|
||||
deployer.expects(:upload_ssh_keys).with([1,2], nodes.first['deployment_id']).returns()
|
||||
deployer.expects(:sync_puppet_manifests).with([{'uid' => 1, 'deployment_id' => 1}, {'uid' => 2}])
|
||||
|
||||
deployer.deploy(nodes)
|
||||
end
|
||||
|
||||
it 'deploy nodes by order' do
|
||||
deployer.stubs(:generate_and_upload_ssh_keys)
|
||||
nodes = [{'uid' => 1, 'priority' => 10}, {'uid' => 2, 'priority' => 0}, {'uid' => 1, 'priority' => 15}]
|
||||
|
||||
deployer.expects(:deploy_piece).with([{'uid' => 2, 'priority' => 0}])
|
||||
@ -56,7 +64,6 @@ describe Astute::DeploymentEngine do
|
||||
end
|
||||
|
||||
it 'nodes with same priority should be deploy at parallel' do
|
||||
deployer.stubs(:generate_and_upload_ssh_keys)
|
||||
nodes = [{'uid' => 1, 'priority' => 10}, {'uid' => 2, 'priority' => 0}, {'uid' => 3, 'priority' => 10}]
|
||||
|
||||
deployer.expects(:deploy_piece).with([{'uid' => 2, 'priority' => 0}])
|
||||
@ -66,7 +73,6 @@ describe Astute::DeploymentEngine do
|
||||
end
|
||||
|
||||
it 'node with several roles with same priority should not run at parallel' do
|
||||
deployer.stubs(:generate_and_upload_ssh_keys)
|
||||
nodes = [
|
||||
{'uid' => 1, 'priority' => 10, 'role' => 'compute'},
|
||||
{'uid' => 2, 'priority' => 0, 'role' => 'primary-controller'},
|
||||
@ -81,7 +87,6 @@ describe Astute::DeploymentEngine do
|
||||
end
|
||||
|
||||
it 'node with several roles with same priority should not run at parallel, but diffirent nodes should' do
|
||||
deployer.stubs(:generate_and_upload_ssh_keys)
|
||||
nodes = [
|
||||
{'uid' => 1, 'priority' => 10, 'role' => 'compute'},
|
||||
{'uid' => 3, 'priority' => 10, 'role' => 'compute'},
|
||||
@ -108,7 +113,10 @@ describe Astute::DeploymentEngine do
|
||||
|
||||
it 'number of nodes running in parallel should be limit' do
|
||||
Astute.config.MAX_NODES_PER_CALL = 1
|
||||
deployer.stubs(:generate_and_upload_ssh_keys)
|
||||
deployer.stubs(:generate_ssh_keys)
|
||||
deployer.stubs(:upload_ssh_keys)
|
||||
deployer.stubs(:sync_puppet_manifests)
|
||||
|
||||
nodes = [
|
||||
{'uid' => 1, 'priority' => 10, 'role' => 'compute'},
|
||||
{'uid' => 3, 'priority' => 10, 'role' => 'compute'},
|
||||
@ -131,17 +139,41 @@ describe Astute::DeploymentEngine do
|
||||
|
||||
end
|
||||
|
||||
describe '#generate_and_upload_ssh_keys' do
|
||||
describe '#sync_puppet_manifests' do
|
||||
before(:each) do
|
||||
deployer.stubs(:deploy_piece)
|
||||
deployer.stubs(:generate_ssh_keys)
|
||||
deployer.stubs(:upload_ssh_keys)
|
||||
end
|
||||
|
||||
let(:nodes) { [{'uid' => 1, 'deployment_id' => 1, 'master_ip' => '10.20.0.2'}, {'uid' => 2}] }
|
||||
|
||||
it "should sync puppet modules and manifests mcollective client 'puppetsync'" do
|
||||
mclient = mock_rpcclient(nodes)
|
||||
Astute::MClient.any_instance.stubs(:rpcclient).returns(mclient)
|
||||
Astute::MClient.any_instance.stubs(:log_result).returns(mclient)
|
||||
Astute::MClient.any_instance.stubs(:check_results_with_retries).returns(mclient)
|
||||
|
||||
master_ip = nodes.first['master_ip']
|
||||
mclient.expects(:rsync).with(:modules_source => "rsync://#{master_ip}:/puppet/modules/",
|
||||
:manifests_source => "rsync://#{master_ip}:/puppet/manifests/"
|
||||
)
|
||||
deployer.deploy(nodes)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#generation and uploading of ssh keys' do
|
||||
before(:each) do
|
||||
Astute.config.PUPPET_SSH_KEYS = ['nova']
|
||||
deployer.stubs(:deploy_piece)
|
||||
deployer.stubs(:sync_puppet_manifests)
|
||||
end
|
||||
|
||||
let(:nodes) { [{'uid' => 1, 'deployment_id' => 1}, {'uid' => 2}] }
|
||||
|
||||
it 'should use Astute.config to get the ssh names that need to generate' do
|
||||
deployer.expects(:generate_ssh_key).with('nova', nodes.first['deployment_id'])
|
||||
deployer.expects(:upload_ssh_key).with([1, 2], 'nova', nodes.first['deployment_id'])
|
||||
deployer.expects(:generate_ssh_keys).with(nodes.first['deployment_id'])
|
||||
deployer.expects(:upload_ssh_keys).with([1, 2], nodes.first['deployment_id'])
|
||||
deployer.deploy(nodes)
|
||||
end
|
||||
|
||||
@ -152,7 +184,7 @@ describe Astute::DeploymentEngine do
|
||||
|
||||
context 'generation of ssh keys' do
|
||||
before(:each) do
|
||||
deployer.stubs(:upload_ssh_key).with([1, 2], 'nova', nodes.first['deployment_id'])
|
||||
deployer.stubs(:upload_ssh_keys).with([1, 2], nodes.first['deployment_id'])
|
||||
end
|
||||
|
||||
it 'should save files in correct place: KEY_DIR/<name of key>/' do
|
||||
@ -207,7 +239,7 @@ describe Astute::DeploymentEngine do
|
||||
|
||||
context 'upload ssh keys' do
|
||||
before(:each) do
|
||||
deployer.stubs(:generate_ssh_key)
|
||||
deployer.stubs(:generate_ssh_keys)
|
||||
end
|
||||
|
||||
it "should upload ssh keys using mcollective client 'uploadfile'" do
|
||||
|
@ -90,6 +90,6 @@ describe MClient do
|
||||
mclient = MClient.new(@ctx, "faketest", nodes.map {|x| x['uid']})
|
||||
mclient.retries = 1
|
||||
expect { mclient.echo(:msg => 'hello world') }.to \
|
||||
raise_error(/MCollective agents '3' didn't respond. \n.* failed nodes: 2/)
|
||||
raise_error(/MCollective agents '3' didn't respond./)
|
||||
end
|
||||
end
|
||||
|
@ -46,13 +46,19 @@ describe "NailyFact DeploymentEngine" do
|
||||
nodes_with_role(deploy_data, 'cinder')
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
uniq_nodes_uid = deploy_data.map {|n| n['uid'] }.uniq
|
||||
deploy_engine.stubs(:generate_ssh_keys).with(deploy_data.first['deployment_id'])
|
||||
deploy_engine.stubs(:upload_ssh_keys).with(uniq_nodes_uid, deploy_data.first['deployment_id'])
|
||||
deploy_engine.stubs(:sync_puppet_manifests).with(deploy_data.uniq { |n| n['uid'] })
|
||||
end
|
||||
|
||||
context 'log parsing' do
|
||||
let(:deploy_data) do
|
||||
[{'uid' => 1, 'role' => 'controller', 'deployment_mode' => 'unknown', 'deployment_id' => '123'}]
|
||||
end
|
||||
|
||||
it "it should not raise an exception if deployment mode is unknown" do
|
||||
deploy_engine.stubs(:generate_and_upload_ssh_keys).with([1], deploy_data.first['deployment_id'])
|
||||
deploy_engine.expects(:upload_facts).times(deploy_data.size)
|
||||
Astute::PuppetdDeployer.stubs(:deploy).with(ctx, deploy_data, instance_of(Fixnum), true).once
|
||||
expect {deploy_engine.deploy(deploy_data)}.to_not raise_exception
|
||||
@ -66,14 +72,11 @@ describe "NailyFact DeploymentEngine" do
|
||||
|
||||
it "should not raise any exception" do
|
||||
deploy_engine.expects(:upload_facts).times(deploy_data.size)
|
||||
|
||||
uniq_nodes_uid = deploy_data.map {|n| n['uid'] }.uniq
|
||||
deploy_engine.expects(:generate_and_upload_ssh_keys).with(uniq_nodes_uid, deploy_data.first['deployment_id'])
|
||||
|
||||
|
||||
# we got two calls, one for controller (high priority), and another for all computes (same low priority)
|
||||
Astute::PuppetdDeployer.expects(:deploy).with(ctx, controller_nodes, instance_of(Fixnum), true).once
|
||||
Astute::PuppetdDeployer.expects(:deploy).with(ctx, compute_nodes, instance_of(Fixnum), true).once
|
||||
|
||||
|
||||
expect {deploy_engine.deploy(deploy_data)}.to_not raise_exception
|
||||
end
|
||||
end
|
||||
@ -93,21 +96,16 @@ describe "NailyFact DeploymentEngine" do
|
||||
deploy_engine.expects(:upload_facts).times(node_amount)
|
||||
ctx.deploy_log_parser.expects(:prepare).with(compute_nodes).once
|
||||
ctx.deploy_log_parser.expects(:prepare).with(cinder_nodes).once
|
||||
|
||||
uniq_nodes_uid = deploy_data.map {|n| n['uid'] }.uniq
|
||||
deploy_engine.expects(:generate_and_upload_ssh_keys).with(uniq_nodes_uid, deploy_data.first['deployment_id'])
|
||||
|
||||
Astute::PuppetdDeployer.expects(:deploy).times(2)
|
||||
|
||||
deploy_engine.deploy(deploy_data)
|
||||
end
|
||||
|
||||
it "should generate and publish facts for every deploy call because node may be deployed several times" do
|
||||
|
||||
it "should generate and publish facts for every deploy call because node may be deployed several times" do
|
||||
deploy_engine.expects(:upload_facts).times(node_amount)
|
||||
ctx.deploy_log_parser.expects(:prepare).with(compute_nodes).once
|
||||
ctx.deploy_log_parser.expects(:prepare).with(cinder_nodes).once
|
||||
deploy_engine.expects(:upload_facts).times(node_amount)
|
||||
|
||||
uniq_nodes_uid = deploy_data.map {|n| n['uid'] }.uniq
|
||||
deploy_engine.expects(:generate_and_upload_ssh_keys).with(uniq_nodes_uid, deploy_data.first['deployment_id'])
|
||||
|
||||
Astute::PuppetdDeployer.expects(:deploy).times(2)
|
||||
|
||||
@ -122,9 +120,6 @@ describe "NailyFact DeploymentEngine" do
|
||||
|
||||
it "ha deploy should not raise any exception" do
|
||||
deploy_engine.expects(:upload_facts).at_least_once
|
||||
|
||||
uniq_nodes_uid = deploy_data.map {|n| n['uid'] }.uniq
|
||||
deploy_engine.expects(:generate_and_upload_ssh_keys).with(uniq_nodes_uid, deploy_data.first['deployment_id'])
|
||||
|
||||
primary_controller = deploy_data.find { |n| n['role'] == 'primary-controller' }
|
||||
Astute::PuppetdDeployer.expects(:deploy).with(ctx, [primary_controller], 2, true).once
|
||||
@ -137,18 +132,18 @@ describe "NailyFact DeploymentEngine" do
|
||||
deploy_engine.deploy(deploy_data)
|
||||
end
|
||||
|
||||
it "ha deploy should not raise any exception if there are only one controller" do
|
||||
deploy_engine.expects(:upload_facts).at_least_once
|
||||
Astute::PuppetdDeployer.expects(:deploy).once
|
||||
context 'exception case' do
|
||||
let(:deploy_data) do
|
||||
[Fixtures.ha_deploy.find { |n| n['role'] == 'controller' }]
|
||||
end
|
||||
|
||||
ctrl = deploy_data.find { |n| n['role'] == 'controller' }
|
||||
it "ha deploy should not raise any exception if there are only one controller" do
|
||||
deploy_engine.expects(:upload_facts).at_least_once
|
||||
Astute::PuppetdDeployer.expects(:deploy).once
|
||||
|
||||
uniq_nodes_uid = [ctrl].map {|n| n['uid'] }.uniq
|
||||
deploy_engine.expects(:generate_and_upload_ssh_keys).with(uniq_nodes_uid, deploy_data.first['deployment_id'])
|
||||
|
||||
deploy_engine.deploy([ctrl])
|
||||
deploy_engine.deploy(deploy_data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end # 'ha deploy'
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user