Add ability to run puppet with noop

This patch adds ability to run deployment graph with noop option.
In same time, this option will be applied only to 'shell' and
'puppet' types only.

Change-Id: Ibcb275bb84dfd553ab07e6d58af753ecf96ab3a5
This commit is contained in:
Denis Egorenko 2016-08-04 19:30:23 +03:00
parent bf1f8abc40
commit 30e09c10f9
17 changed files with 268 additions and 14 deletions

View File

@ -61,6 +61,7 @@ module Astute
conf[:puppet_retries] = 2 # how many times astute will try to run puppet 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_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_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_retries] = 10 # MClient tries to call mcagent before failure
conf[:mc_retry_interval] = 1 # MClient sleeps for ## sec between retries 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 conf[:puppet_fade_interval] = 30 # retry every ## seconds to check puppet state if it was running

View File

@ -27,7 +27,8 @@ module Astute
:timeout => Astute.config.puppet_timeout, :timeout => Astute.config.puppet_timeout,
:puppet_debug => false, :puppet_debug => false,
:succeed_retries => Astute.config.puppet_succeed_retries, :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 = options.compact.reverse_merge(default_options)
@options.freeze @options.freeze
@ -125,7 +126,8 @@ module Astute
:puppet_debug => @options[:puppet_debug], :puppet_debug => @options[:puppet_debug],
:manifest => @options[:puppet_manifest], :manifest => @options[:puppet_manifest],
:modules => @options[:puppet_modules], :modules => @options[:puppet_modules],
:cwd => @options[:cwd] :cwd => @options[:cwd],
:puppet_noop_run => @options[:puppet_noop_run],
) )
end end

View File

@ -15,6 +15,7 @@ require 'fuel_deployment'
module Astute module Astute
class TaskCluster < Deployment::Cluster class TaskCluster < Deployment::Cluster
attr_accessor :noop_run
def hook_post_gracefully_stop(*args) def hook_post_gracefully_stop(*args)
report_new_node_status(args[0]) report_new_node_status(args[0])

View File

@ -39,6 +39,10 @@ module Astute
'fault_tolerance_groups', 'fault_tolerance_groups',
[] []
) )
cluster.noop_run = tasks_metadata.fetch(
'noop_run',
false
)
offline_uids = fail_offline_nodes(tasks_graph) offline_uids = fail_offline_nodes(tasks_graph)
critical_uids = critical_node_uids(cluster.fault_tolerance_groups) 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) node.set_status_failed if offline_uids.include?(node_id)
end end
setup_fail_behavior(tasks_graph, cluster)
setup_tasks(tasks_graph, cluster) setup_tasks(tasks_graph, cluster)
setup_task_depends(tasks_graph, cluster) setup_task_depends(tasks_graph, cluster)
setup_task_concurrency(tasks_graph, cluster) setup_task_concurrency(tasks_graph, cluster)
@ -67,6 +72,8 @@ module Astute
result[:success] = true result[:success] = true
else else
result = cluster.run result = cluster.run
# imitate dry_run results for noop run after deployment
result = {:success => true } if cluster.noop_run
end end
report_deploy_result(result) report_deploy_result(result)
end end
@ -87,6 +94,15 @@ module Astute
tasks_graph tasks_graph
end 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) def setup_tasks(tasks_graph, cluster)
tasks_graph.each do |node_id, tasks| tasks_graph.each do |node_id, tasks|
tasks.each do |task| tasks.each do |task|

View File

@ -113,14 +113,14 @@ module Astute
def select_task_engine(data) def select_task_engine(data)
# TODO: replace by Object.const_get(type.split('_').collect(&:capitalize).join) # TODO: replace by Object.const_get(type.split('_').collect(&:capitalize).join)
case data['type'] case data['type']
when 'shell' then Shell.new(data, @ctx) when 'shell' then noop_run? ? NoopShell.new(data, @ctx) : Shell.new(data, @ctx)
when 'puppet' then Puppet.new(data, @ctx) when 'puppet' then noop_run? ? NoopPuppet.new(data, @ctx) : Puppet.new(data, @ctx)
when 'upload_file' then UploadFile.new(data, @ctx) when 'upload_file' then noop_run? ? NoopUploadFile.new(data, @ctx) : UploadFile.new(data, @ctx)
when 'upload_files' then UploadFiles.new(data, @ctx) when 'upload_files' then noop_run? ? NoopUploadFiles.new(data, @ctx) : UploadFiles.new(data, @ctx)
when 'reboot' then Reboot.new(data, @ctx) when 'reboot' then noop_run? ? NoopReboot.new(data, @ctx) : Reboot.new(data, @ctx)
when 'sync' then Sync.new(data, @ctx) when 'sync' then noop_run? ? NoopSync.new(data, @ctx) : Sync.new(data, @ctx)
when 'cobbler_sync' then CobblerSync.new(data, @ctx) when 'cobbler_sync' then noop_run? ? NoopCobblerSync.new(data, @ctx) : CobblerSync.new(data, @ctx)
when 'copy_files' then CopyFiles.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 'noop' then Noop.new(data, @ctx)
when 'stage' then Noop.new(data, @ctx) when 'stage' then Noop.new(data, @ctx)
when 'skipped' then Noop.new(data, @ctx) when 'skipped' then Noop.new(data, @ctx)
@ -132,5 +132,8 @@ module Astute
!['noop', 'stage', 'skipped'].include?(data['type']) !['noop', 'stage', 'skipped'].include?(data['type'])
end end
def noop_run?
cluster.noop_run
end
end end
end end

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -211,8 +211,11 @@ module MCollective
end end
end end
cmd << '--debug' if request[:puppet_debug] if request[:puppet_noop_run]
cmd << '--evaltrace' if request[:puppet_debug] cmd << '--noop'
else
cmd << '--debug' << '--evaltrace' if request[:puppet_debug]
end
cmd << "--logdest #{@log}" if @log cmd << "--logdest #{@log}" if @log
cmd = cmd.join(" ") cmd = cmd.join(" ")

View File

@ -33,6 +33,13 @@ describe Astute::TaskCluster do
end end
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 describe "#gracefully_stop" do
it 'should check if node should be stopped' do it 'should check if node should be stopped' do
subject.expects(:gracefully_stop?).returns(false) subject.expects(:gracefully_stop?).returns(false)

View File

@ -297,6 +297,20 @@ describe Astute::TaskDeployment do
end end
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 context 'config' do
around(:each) do |example| around(:each) do |example|
max_nodes_old_value = Astute.config.max_nodes_per_call max_nodes_old_value = Astute.config.max_nodes_per_call

View File

@ -19,7 +19,7 @@ describe Astute::TaskNode do
include SpecHelpers include SpecHelpers
let(:cluster) do let(:cluster) do
Deployment::Cluster.new Astute::TaskCluster.new
end end
let(:ctx) do let(:ctx) do
@ -66,6 +66,20 @@ describe Astute::TaskNode do
task_node.run(task) task_node.run(task)
end 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 it 'should mark node as busy' do
Astute::Puppet.any_instance.stubs(:run) Astute::Puppet.any_instance.stubs(:run)
task_node.run(task) task_node.run(task)