fuel-astute/lib/astute/mclients/puppet_mclient.rb
Vladimir Sharshov (warpc) 7c0485eb1a Network problem tolerance puppet status check
Connection between node and Astute can be lost some
times, so we need more tries to get info about task
status on node.

Two changes:

- instead of 1 try Astute will run 6 tries with 10
timeout for every attempt;
- it will process such behavior for puppet using separately
  retries: puppet_undefined_retries

Instead of full puppet retry status retry is safety because
it is idempotent.

Puppet undefined retries can be setup using Astute config
or sending undefined_retries in puppet task parameters same
way as for usual retries. Most important thing: it will refresh
to original value every time when Astute get defined answer.

Change-Id: Ie86576a3400be5a6b11041c8e6acf89abf3bbd51
Related-Bug: #1653210
Closes-Bug: #1653737
2017-01-05 18:02:18 +03:00

138 lines
4.1 KiB
Ruby

# 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.
module Astute
class PuppetMClient
PUPPET_STATUSES = [
'running', 'stopped', 'disabled'
]
attr_reader :summary, :node_id
def initialize(ctx, node_id, options)
@ctx = ctx
@node_id = node_id
@options = options
@summary = {}
end
# Return actual status of puppet using mcollective puppet agent
# @return [String] status: succeed, one of PUPPET_STATUSES or undefined
def status
last_run_summary
succeed? ? 'succeed' : @summary.fetch(:status, 'undefined')
end
# Run puppet on node if available
# @return [true, false]
def run
is_succeed, err_msg = runonce
return true if is_succeed
Astute.logger.warn "Fail to start puppet on node #{@node_id}. "\
"Reason: #{err_msg}"
false
end
# Return path to manifest using by mcollective puppet agent
# @return [String] path to manifest
def manifest
File.join(@options['cwd'], @options['puppet_manifest'])
end
private
# Create configured puppet mcollective agent
# @return [Astute::MClient]
def puppetd(timeout=nil, retries=1)
puppetd = MClient.new(
@ctx,
"puppetd",
[@node_id],
_check_result=true,
_timeout=timeout,
_retries=retries,
_enable_result_logging=false
)
puppetd.on_respond_timeout do |uids|
msg = "Nodes #{uids} reached the response timeout"
Astute.logger.error msg
raise MClientTimeout, msg
end
puppetd
end
# Run last_run_summary action using mcollective puppet agent
# @return [Hash] return hash with status and resources
def last_run_summary
@summary = puppetd(_timeout=10, _retries=6).last_run_summary(
:puppet_noop_run => @options['puppet_noop_run'],
:raw_report => @options['raw_report']
).first[:data]
validate_status!(@summary[:status])
@summary
rescue MClientError, MClientTimeout => e
Astute.logger.warn "Unable to get actual status of puppet on "\
"node #{@node_id}. Reason: #{e.message}"
@summary = {}
end
# Run runonce action using mcollective puppet agent
# @return [[true, false], String] boolean status of run and error message
def runonce
result = puppetd.runonce(
:puppet_debug => @options['puppet_debug'],
:manifest => @options['puppet_manifest'],
:modules => @options['puppet_modules'],
:cwd => @options['cwd'],
:puppet_noop_run => @options['puppet_noop_run'],
).first
return result[:statuscode] == 0, result[:statusmsg]
rescue MClientError, MClientTimeout => e
return false, e.message
end
# Validate puppet status
# @param [String] status The puppet status
# @return [void]
# @raise [MClientError] Unknown status
def validate_status!(status)
unless PUPPET_STATUSES.include?(status)
raise MClientError, "Unknow status '#{status}' from mcollective agent"
end
end
# Detect succeed of puppet run using summary from last_run_summary call
# @return [true, false]
def succeed?
return false if @summary.blank?
@summary[:status] == 'stopped' &&
@summary[:resources] &&
@summary[:resources]['failed'].to_i == 0 &&
@summary[:resources]['failed_to_restart'].to_i == 0
end
# Generate shell cmd for file deletion
# @return [String] shell cmd for deletion
def rm_cmd
PUPPET_FILES_TO_CLEANUP.inject([]) do
|cmd, file| cmd << "rm -f #{file}"
end.join(" && ")
end
end # PuppetMclient
end