fuel-astute/lib/astute/logparser/deployment.rb

161 lines
6.0 KiB
Ruby

# 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 Astute
module LogParser
class ParseDeployLogs < ParseNodeLogs
attr_reader :deploy_type
def deploy_type=(deploy_type)
@deploy_type = deploy_type
@nodes_patterns = {}
end
def get_pattern_for_node(node)
role = node['role']
node_pattern = Patterns::get_default_pattern(
"puppet-log-components-list-#{@deploy_type}-#{role}")
node_pattern['path_prefix'] ||= PATH_PREFIX.to_s
node_pattern['separator'] ||= SEPARATOR.to_s
node_pattern
end
private
def calculate(fo, node_pattern_spec)
case node_pattern_spec['type']
when 'count-lines'
progress = simple_line_counter(fo, node_pattern_spec)
when 'components-list'
progress = component_parser(fo, node_pattern_spec)
end
return progress
end
def simple_line_counter(fo, pattern_spec)
# Pattern specification example:
# pattern_spec = {'type' => 'count-lines',
# 'endlog_patterns' => [{'pattern' => /Finished catalog run in [0-9]+\.[0-9]* seconds\n/, 'progress' => 1.0}],
# 'expected_line_number' => 500}
# Use custom separator if defined.
separator = pattern_spec['separator']
counter = 0
end_of_scope = false
previous_subchunk = ''
until end_of_scope
chunk = get_chunk(fo, pattern_spec['chunk_size'])
break unless chunk
# Trying to find separator on border between chunks.
subchunk = chunk.slice((1-separator.size)..-1)
# End of file reached. Exit from cycle.
end_of_scope = true unless subchunk
if subchunk and (subchunk + previous_subchunk).include?(separator)
# Separator found on border between chunks. Exit from cycle.
end_of_scope = true
continue
end
pos = chunk.rindex(separator)
if pos
end_of_scope = true
chunk = chunk.slice((pos + separator.size)..-1)
end
counter += chunk.count("\n")
end
number = pattern_spec['expected_line_number']
unless number
Astute.logger.warn("Wrong pattern\n#{pattern_spec.pretty_inspect} defined for calculating progress via log.")
return 0
end
progress = counter.to_f / number
progress = 1 if progress > 1
return progress
end
def component_parser(fo, pattern_spec)
# Pattern specification example:
# pattern_spec = {'type' => 'components-list',
# 'chunk_size' => 40000,
# 'components_list' => [
# {'name' => 'Horizon', 'weight' => 10, 'patterns' => [
# {'pattern' => '/Stage[main]/Horizon/Package[mod_wsgi]/ensure) created', 'progress' => 0.1},
# {'pattern' => '/Stage[main]/Horizon/File_line[horizon_redirect_rule]/ensure) created', 'progress' => 0.3},
# {'pattern' => '/Stage[main]/Horizon/File[/etc/openstack-dashboard/local_settings]/group)', 'progress' => 0.7},
# {'pattern' => '/Stage[main]/Horizon/Service[$::horizon::params::http_service]/ensure)'\
# ' ensure changed \'stopped\' to \'running\'', 'progress' => 1},
# ]
# },
# ]
# }
# Use custom separator if defined.
separator = pattern_spec['separator']
components_list = pattern_spec['components_list']
unless components_list
Astute.logger.warn("Wrong pattern\n#{pattern_spec.pretty_inspect} defined for calculating progress via logs.")
return 0
end
chunk = get_chunk(fo, pos=pattern_spec['file_pos'])
return 0 unless chunk
pos = chunk.rindex(separator)
chunk = chunk.slice((pos + separator.size)..-1) if pos
block = chunk.split("\n")
# Update progress of each component.
while block.any?
string = block.pop
components_list.each do |component|
matched_pattern = nil
component['patterns'].each do |pattern|
if pattern['regexp']
matched_pattern = pattern if string.match(pattern['pattern'])
else
matched_pattern = pattern if string.include?(pattern['pattern'])
end
break if matched_pattern
end
if matched_pattern and
(not component['_progress'] or matched_pattern['progress'] > component['_progress'])
component['_progress'] = matched_pattern['progress']
end
end
end
# Calculate integral progress.
weighted_components = components_list.select{|n| n['weight']}
weight_sum = 0.0
if weighted_components.any?
weighted_components.each{|n| weight_sum += n['weight']}
weight_sum = weight_sum * components_list.length / weighted_components.length
raise "Total weight of weighted components equal to zero." if weight_sum == 0
end
nonweighted_delta = 1.0 / components_list.length
progress = 0
components_list.each do |component|
component['_progress'] = 0.0 unless component['_progress']
weight = component['weight']
if weight
progress += component['_progress'] * weight / weight_sum
else
progress += component['_progress'] * nonweighted_delta
end
end
return progress
end
end
end
end