diff --git a/lib/astute/config.rb b/lib/astute/config.rb index d71529ab..938bb1fe 100644 --- a/lib/astute/config.rb +++ b/lib/astute/config.rb @@ -61,6 +61,7 @@ module Astute conf[:puppet_retries] = 2 # how many times astute will try to run puppet conf[:puppet_succeed_retries] = 0 # use this to rerun a puppet task again if it was successful (idempotency) conf[:puppet_module_path] = '/etc/puppet/modules' # where we should find basic modules for puppet + conf[:puppet_noop_run] = false # enable Puppet noop run conf[:mc_retries] = 10 # MClient tries to call mcagent before failure conf[:mc_retry_interval] = 1 # MClient sleeps for ## sec between retries conf[:puppet_fade_interval] = 30 # retry every ## seconds to check puppet state if it was running diff --git a/lib/astute/puppet_task.rb b/lib/astute/puppet_task.rb index ef51d726..c3515d5b 100644 --- a/lib/astute/puppet_task.rb +++ b/lib/astute/puppet_task.rb @@ -27,7 +27,8 @@ module Astute :timeout => Astute.config.puppet_timeout, :puppet_debug => false, :succeed_retries => Astute.config.puppet_succeed_retries, - :raw_report => Astute.config.puppet_raw_report + :raw_report => Astute.config.puppet_raw_report, + :puppet_noop_run => Astute.config.puppet_noop_run, } @options = options.compact.reverse_merge(default_options) @options.freeze @@ -125,7 +126,8 @@ module Astute :puppet_debug => @options[:puppet_debug], :manifest => @options[:puppet_manifest], :modules => @options[:puppet_modules], - :cwd => @options[:cwd] + :cwd => @options[:cwd], + :puppet_noop_run => @options[:puppet_noop_run], ) end diff --git a/lib/astute/task_cluster.rb b/lib/astute/task_cluster.rb index 31f4094b..22738aab 100644 --- a/lib/astute/task_cluster.rb +++ b/lib/astute/task_cluster.rb @@ -15,6 +15,7 @@ require 'fuel_deployment' module Astute class TaskCluster < Deployment::Cluster + attr_accessor :noop_run def hook_post_gracefully_stop(*args) report_new_node_status(args[0]) diff --git a/lib/astute/task_deployment.rb b/lib/astute/task_deployment.rb index 78e46694..8d8b08e5 100644 --- a/lib/astute/task_deployment.rb +++ b/lib/astute/task_deployment.rb @@ -39,6 +39,10 @@ module Astute 'fault_tolerance_groups', [] ) + cluster.noop_run = tasks_metadata.fetch( + 'noop_run', + false + ) offline_uids = fail_offline_nodes(tasks_graph) critical_uids = critical_node_uids(cluster.fault_tolerance_groups) @@ -51,6 +55,7 @@ module Astute node.set_status_failed if offline_uids.include?(node_id) end + setup_fail_behavior(tasks_graph, cluster) setup_tasks(tasks_graph, cluster) setup_task_depends(tasks_graph, cluster) setup_task_concurrency(tasks_graph, cluster) @@ -67,6 +72,8 @@ module Astute result[:success] = true else result = cluster.run + # imitate dry_run results for noop run after deployment + result = {:success => true } if cluster.noop_run end report_deploy_result(result) end @@ -87,6 +94,15 @@ module Astute tasks_graph end + def setup_fail_behavior(tasks_graph, cluster) + return unless cluster.noop_run + tasks_graph.each do |node_id, tasks| + tasks.each do |task| + task['fail_on_error'] = false + end + end + end + def setup_tasks(tasks_graph, cluster) tasks_graph.each do |node_id, tasks| tasks.each do |task| diff --git a/lib/astute/task_node.rb b/lib/astute/task_node.rb index db9fce74..27a048f5 100644 --- a/lib/astute/task_node.rb +++ b/lib/astute/task_node.rb @@ -113,14 +113,14 @@ module Astute def select_task_engine(data) # TODO: replace by Object.const_get(type.split('_').collect(&:capitalize).join) case data['type'] - when 'shell' then Shell.new(data, @ctx) - when 'puppet' then Puppet.new(data, @ctx) - when 'upload_file' then UploadFile.new(data, @ctx) - when 'upload_files' then UploadFiles.new(data, @ctx) - when 'reboot' then Reboot.new(data, @ctx) - when 'sync' then Sync.new(data, @ctx) - when 'cobbler_sync' then CobblerSync.new(data, @ctx) - when 'copy_files' then CopyFiles.new(data, @ctx) + when 'shell' then noop_run? ? NoopShell.new(data, @ctx) : Shell.new(data, @ctx) + when 'puppet' then noop_run? ? NoopPuppet.new(data, @ctx) : Puppet.new(data, @ctx) + when 'upload_file' then noop_run? ? NoopUploadFile.new(data, @ctx) : UploadFile.new(data, @ctx) + when 'upload_files' then noop_run? ? NoopUploadFiles.new(data, @ctx) : UploadFiles.new(data, @ctx) + when 'reboot' then noop_run? ? NoopReboot.new(data, @ctx) : Reboot.new(data, @ctx) + when 'sync' then noop_run? ? NoopSync.new(data, @ctx) : Sync.new(data, @ctx) + when 'cobbler_sync' then noop_run? ? NoopCobblerSync.new(data, @ctx) : CobblerSync.new(data, @ctx) + when 'copy_files' then noop_run? ? NoopCopyFiles.new(data, @ctx) : CopyFiles.new(data, @ctx) when 'noop' then Noop.new(data, @ctx) when 'stage' then Noop.new(data, @ctx) when 'skipped' then Noop.new(data, @ctx) @@ -132,5 +132,8 @@ module Astute !['noop', 'stage', 'skipped'].include?(data['type']) end + def noop_run? + cluster.noop_run + end end -end \ No newline at end of file +end diff --git a/lib/astute/tasks/noop_cobbler_sync.rb b/lib/astute/tasks/noop_cobbler_sync.rb new file mode 100644 index 00000000..7d77a930 --- /dev/null +++ b/lib/astute/tasks/noop_cobbler_sync.rb @@ -0,0 +1,19 @@ +# Copyright 2016 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. +require 'astute/tasks/noop' + +module Astute + class NoopCobblerSync < Noop + end +end diff --git a/lib/astute/tasks/noop_copy_files.rb b/lib/astute/tasks/noop_copy_files.rb new file mode 100644 index 00000000..f9d358c5 --- /dev/null +++ b/lib/astute/tasks/noop_copy_files.rb @@ -0,0 +1,19 @@ +# Copyright 2016 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. +require 'astute/tasks/noop' + +module Astute + class NoopCopyFiles < Noop + end +end diff --git a/lib/astute/tasks/noop_puppet.rb b/lib/astute/tasks/noop_puppet.rb new file mode 100644 index 00000000..bdbf5ea3 --- /dev/null +++ b/lib/astute/tasks/noop_puppet.rb @@ -0,0 +1,43 @@ +# Copyright 2016 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. + +require 'astute/tasks/puppet' + +module Astute + class NoopPuppet < Puppet + + private + + def create_puppet_task + PuppetTask.new( + Context.new( + @ctx.task_id, + PuppetLoggerReporter.new, + LogParser::NoParsing.new + ), + {'uid' => @task['node_id'].to_s, 'role' => task_name}, + { + :retries => @task['parameters']['retries'], + :puppet_manifest => @task['parameters']['puppet_manifest'], + :puppet_modules => @task['parameters']['puppet_modules'], + :cwd => @task['parameters']['cwd'], + :timeout => @task['parameters']['timeout'], + :puppet_debug => @task['parameters']['debug'], + :puppet_noop_run => true, + } + ) + end + + end +end diff --git a/lib/astute/tasks/noop_reboot.rb b/lib/astute/tasks/noop_reboot.rb new file mode 100644 index 00000000..fe1f200e --- /dev/null +++ b/lib/astute/tasks/noop_reboot.rb @@ -0,0 +1,19 @@ +# Copyright 2016 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. +require 'astute/tasks/noop' + +module Astute + class NoopReboot < Noop + end +end diff --git a/lib/astute/tasks/noop_shell.rb b/lib/astute/tasks/noop_shell.rb new file mode 100644 index 00000000..caa695d5 --- /dev/null +++ b/lib/astute/tasks/noop_shell.rb @@ -0,0 +1,36 @@ +# Copyright 2016 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. +require 'astute/tasks/shell' + +module Astute + class NoopShell < Shell + + private + + def process + run_shell_without_check( + @task['node_id'], + "mkdir -p #{SHELL_MANIFEST_DIR}", + timeout=2 + ) + upload_shell_manifest + @puppet_task = NoopPuppet.new( + generate_puppet_hook, + @ctx + ) + @puppet_task.run + end + + end +end diff --git a/lib/astute/tasks/noop_sync.rb b/lib/astute/tasks/noop_sync.rb new file mode 100644 index 00000000..6096ae9f --- /dev/null +++ b/lib/astute/tasks/noop_sync.rb @@ -0,0 +1,19 @@ +# Copyright 2015 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. +require 'astute/tasks/noop' + +module Astute + class NoopSync < Noop + end +end diff --git a/lib/astute/tasks/noop_upload_file.rb b/lib/astute/tasks/noop_upload_file.rb new file mode 100644 index 00000000..d22bbdbe --- /dev/null +++ b/lib/astute/tasks/noop_upload_file.rb @@ -0,0 +1,19 @@ +# Copyright 2015 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. +require 'astute/tasks/noop' + +module Astute + class NoopUploadFile < Noop + end +end diff --git a/lib/astute/tasks/noop_upload_files.rb b/lib/astute/tasks/noop_upload_files.rb new file mode 100644 index 00000000..6ec68c8b --- /dev/null +++ b/lib/astute/tasks/noop_upload_files.rb @@ -0,0 +1,19 @@ +# Copyright 2015 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. +require 'astute/tasks/noop' + +module Astute + class NoopUploadFiles < Noop + end +end diff --git a/mcagents/puppetd.rb b/mcagents/puppetd.rb index 67ff1165..d1bc3db6 100644 --- a/mcagents/puppetd.rb +++ b/mcagents/puppetd.rb @@ -211,8 +211,11 @@ module MCollective end end - cmd << '--debug' if request[:puppet_debug] - cmd << '--evaltrace' if request[:puppet_debug] + if request[:puppet_noop_run] + cmd << '--noop' + else + cmd << '--debug' << '--evaltrace' if request[:puppet_debug] + end cmd << "--logdest #{@log}" if @log cmd = cmd.join(" ") diff --git a/spec/unit/task_cluster_spec.rb b/spec/unit/task_cluster_spec.rb index 854671bc..54f4ed8a 100644 --- a/spec/unit/task_cluster_spec.rb +++ b/spec/unit/task_cluster_spec.rb @@ -33,6 +33,13 @@ describe Astute::TaskCluster do end end + describe "#noop_run" do + it 'should set cluster noop mode' do + subject.noop_run = true + expect(subject.noop_run).to eq true + end + end + describe "#gracefully_stop" do it 'should check if node should be stopped' do subject.expects(:gracefully_stop?).returns(false) diff --git a/spec/unit/task_deployment_spec.rb b/spec/unit/task_deployment_spec.rb index 153b0bed..eeeb0eb1 100644 --- a/spec/unit/task_deployment_spec.rb +++ b/spec/unit/task_deployment_spec.rb @@ -297,6 +297,20 @@ describe Astute::TaskDeployment do end end + context 'noop_run' do + it 'should run noop deployment without error states' do + task_deployment.stubs(:fail_offline_nodes).returns([]) + task_deployment.stubs(:write_graph_to_file) + ctx.stubs(:report) + + Astute::TaskCluster.any_instance.expects(:run).returns({:success => true}) + task_deployment.deploy( + tasks_metadata: tasks_metadata.merge({'noop_run' => true}), + tasks_graph: tasks_graph, + tasks_directory: tasks_directory) + end + end + context 'config' do around(:each) do |example| max_nodes_old_value = Astute.config.max_nodes_per_call diff --git a/spec/unit/task_node_spec.rb b/spec/unit/task_node_spec.rb index 8d2c3a08..a2e77693 100644 --- a/spec/unit/task_node_spec.rb +++ b/spec/unit/task_node_spec.rb @@ -19,7 +19,7 @@ describe Astute::TaskNode do include SpecHelpers let(:cluster) do - Deployment::Cluster.new + Astute::TaskCluster.new end let(:ctx) do @@ -66,6 +66,20 @@ describe Astute::TaskNode do task_node.run(task) end + it 'should run noop puppet task' do + cluster_new = Astute::TaskCluster.new + cluster_new.id = 'test2' + cluster_new.noop_run = true + task_node_new = Astute::TaskNode.new('node_id', cluster_new) + task_node_new.context = ctx + task_node_new.graph.create_task( + task_data['id'], + task_data.merge({'node_id' => 'node_id'}) + ) + Astute::NoopPuppet.any_instance.expects(:run) + task_node_new.run(task) + end + it 'should mark node as busy' do Astute::Puppet.any_instance.stubs(:run) task_node.run(task)