161 lines
6.0 KiB
Ruby
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
|