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

View File

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

View File

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

View File

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

View File

@ -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
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
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(" ")

View File

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

View File

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

View File

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