diff --git a/lib/astute/deployment_engine.rb b/lib/astute/deployment_engine.rb index 42a60c63..a10de7b6 100644 --- a/lib/astute/deployment_engine.rb +++ b/lib/astute/deployment_engine.rb @@ -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( and .pub) and save it to // + 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( and .pub) and save it to // - 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 diff --git a/lib/astute/logparser/parser_patterns.rb b/lib/astute/logparser/parser_patterns.rb index ed4e8a3a..2e72d8ad 100644 --- a/lib/astute/logparser/parser_patterns.rb +++ b/lib/astute/logparser/parser_patterns.rb @@ -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'] %>" }, } diff --git a/lib/astute/mclient.rb b/lib/astute/mclient.rb index 2edfeb40..8b90e62f 100644 --- a/lib/astute/mclient.rb +++ b/lib/astute/mclient.rb @@ -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 diff --git a/mcagents/puppetd.ddl b/mcagents/puppetd.ddl index dd685fcc..20e8e2c4 100644 --- a/mcagents/puppetd.ddl +++ b/mcagents/puppetd.ddl @@ -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 diff --git a/mcagents/puppetd.rb b/mcagents/puppetd.rb index 922beae7..5453f7ab 100644 --- a/mcagents/puppetd.rb +++ b/mcagents/puppetd.rb @@ -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 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" diff --git a/mcagents/puppetsync.ddl b/mcagents/puppetsync.ddl new file mode 100644 index 00000000..586c1eb9 --- /dev/null +++ b/mcagents/puppetsync.ddl @@ -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 \ No newline at end of file diff --git a/mcagents/puppetsync.rb b/mcagents/puppetsync.rb new file mode 100644 index 00000000..7b185d3b --- /dev/null +++ b/mcagents/puppetsync.rb @@ -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 \ No newline at end of file diff --git a/mcagents/systemtype.ddl b/mcagents/systemtype.ddl index ab4f8767..f0ffe298 100644 --- a/mcagents/systemtype.ddl +++ b/mcagents/systemtype.ddl @@ -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 diff --git a/spec/unit/deployment_engine_spec.rb b/spec/unit/deployment_engine_spec.rb index 039c2415..0e91bde5 100644 --- a/spec/unit/deployment_engine_spec.rb +++ b/spec/unit/deployment_engine_spec.rb @@ -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//' 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 diff --git a/spec/unit/mclient_spec.rb b/spec/unit/mclient_spec.rb index 2d775a58..c9194a58 100644 --- a/spec/unit/mclient_spec.rb +++ b/spec/unit/mclient_spec.rb @@ -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 diff --git a/spec/unit/nailyfact_deploy_spec.rb b/spec/unit/nailyfact_deploy_spec.rb index 7be1ba56..42abf179 100644 --- a/spec/unit/nailyfact_deploy_spec.rb +++ b/spec/unit/nailyfact_deploy_spec.rb @@ -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