ansible_spec_plus 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,34 @@
1
+ module AnsibleSpecHelper
2
+ def self.get_properties
3
+ playbook, inventoryfile = AnsibleSpec.load_ansiblespec
4
+
5
+ hosts = AnsibleSpec.load_targets(inventoryfile)
6
+ properties = AnsibleSpec.load_playbook(playbook)
7
+
8
+ properties.each do |var|
9
+ var["hosts_childrens"] = hosts["hosts_childrens"]
10
+ var["group"] = var["hosts"]
11
+ if var["hosts"].to_s == "all"
12
+ var["hosts"] = hosts.values.flatten
13
+ elsif hosts.has_key?("#{var["hosts"]}")
14
+ var["hosts"] = hosts["#{var["hosts"]}"]
15
+ elsif var["hosts"].instance_of?(Array)
16
+ tmp_host = var["hosts"]
17
+ var["hosts"] = []
18
+ tmp_host.each do |v|
19
+ if hosts.has_key?("#{v}")
20
+ hosts["#{v}"].map {|target_server| target_server["hosts"] = v}
21
+ var["hosts"].concat hosts["#{v}"]
22
+ end
23
+ end
24
+ if var["hosts"].size == 0
25
+ properties = properties.compact.reject{|e| e["hosts"].length == 0}
26
+ end
27
+ else
28
+ var["hosts"] = []
29
+ end
30
+ end
31
+
32
+ return properties
33
+ end
34
+ end
@@ -0,0 +1,110 @@
1
+ require 'logger'
2
+ require_relative 'ring_buffer'
3
+
4
+ module Helpers
5
+
6
+ class BufferedLogger < Logger
7
+
8
+ #
9
+ # :call-seq:
10
+ # Logger.new(name, shift_age = 7, shift_size = 1048576)
11
+ # Logger.new(name, shift_age = 'weekly')
12
+ #
13
+ # === Args
14
+ #
15
+ # +logdev+::
16
+ # The log device. This is a filename (String) or IO object (typically
17
+ # +STDOUT+, +STDERR+, or an open file).
18
+ # +shift_age+::
19
+ # Number of old log files to keep, *or* frequency of rotation (+daily+,
20
+ # +weekly+ or +monthly+).
21
+ # +shift_size+::
22
+ # Maximum logfile size (only applies when +shift_age+ is a number).
23
+ #
24
+ # === Description
25
+ #
26
+ # Create an instance.
27
+ #
28
+ def initialize(logdev, shift_age = 0, shift_size = 1048576)
29
+ super
30
+ if logdev == STDOUT
31
+ @stdout = STDOUT
32
+ end
33
+
34
+ @last_messages = RingBuffer.new(200)
35
+ end
36
+
37
+ #
38
+ # :call-seq:
39
+ # Logger#add(severity, message = nil, progname = nil) { ... }
40
+ #
41
+ # === Args
42
+ #
43
+ # +severity+::
44
+ # Severity. Constants are defined in Logger namespace: +DEBUG+, +INFO+,
45
+ # +WARN+, +ERROR+, +FATAL+, or +UNKNOWN+.
46
+ # +message+::
47
+ # The log message. A String or Exception.
48
+ # +progname+::
49
+ # Program name string. Can be omitted. Treated as a message if no
50
+ # +message+ and +block+ are given.
51
+ # +block+::
52
+ # Can be omitted. Called to get a message string if +message+ is nil.
53
+ #
54
+ # === Return
55
+ #
56
+ # When the given severity is not high enough (for this particular logger),
57
+ # log no message, and return +true+. Even if the severity is not high enough
58
+ # we save each message in a ring buffer.
59
+ #
60
+ # === Description
61
+ #
62
+ # Log a message if the given severity is high enough. This is the generic
63
+ # logging method. Users will be more inclined to use #debug, #info, #warn,
64
+ # #error, and #fatal.
65
+ #
66
+ # <b>Message format</b>: +message+ can be any object, but it has to be
67
+ # converted to a String in order to log it. Generally, +inspect+ is used
68
+ # if the given object is not a String.
69
+ # A special case is an +Exception+ object, which will be printed in detail,
70
+ # including message, class, and backtrace. See #msg2str for the
71
+ # implementation if required.
72
+ #
73
+ # === Bugs
74
+ #
75
+ # * Logfile is not locked.
76
+ # * Append open does not need to lock file.
77
+ # * If the OS supports multi I/O, records possibly may be mixed.
78
+ #
79
+ def add(severity, message = nil, progname = nil, &block)
80
+ super
81
+ severity ||= UNKNOWN
82
+ progname ||= @progname
83
+ if message.nil?
84
+ if block_given?
85
+ message = yield
86
+ else
87
+ message = progname
88
+ progname = @progname
89
+ end
90
+ end
91
+ @last_messages.push(format_message(format_severity(severity), Time.now, progname, message))
92
+ @stdout.flush if @stdout
93
+ true
94
+ end
95
+
96
+ #
97
+ # === Return
98
+ #
99
+ # Get array of last log messages. Even log messages with low severity are included.
100
+ # The number of returned messages is limited by the size of the underlying ring buffer.
101
+ #
102
+ # === Description
103
+ #
104
+ # After calling this method the underling ring buffer is empty.
105
+ #
106
+ def last_messages
107
+ @last_messages.flush
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'colorize'
2
+ require 'logger'
3
+
4
+ module Helpers
5
+ # colorful log formatter, also logs thread object id instead of process id
6
+ class ColorFormatter < Logger::Formatter
7
+
8
+ SCHEMA = %w(nothing green yellow red purple cyan)
9
+
10
+ def call(severity, time, progname, msg)
11
+ level = ::Logger::Severity.const_get(severity)
12
+ color = SCHEMA[level]
13
+ text = Format % [severity[0..0], format_datetime(time), Thread.current.object_id, severity, progname,
14
+ msg2str(msg)]
15
+ color ? Colorize.colorize(color, text) : text
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,52 @@
1
+ module Helpers
2
+ module Colorize
3
+ module Colors
4
+ NOTHING = '0;0'
5
+ BLACK = '0;30'
6
+ DARK_RED = '0;31'
7
+ DARK_GREEN = '0;32'
8
+ BROWN = '0;33'
9
+ BLUE = '0;34'
10
+ PURPLE = '0;35'
11
+ CYAN = '0;36'
12
+ GRAY = '0;37'
13
+ LIGHT_GRAY = '0;37'
14
+ DARK_GRAY = '1;30'
15
+ RED = '1;31'
16
+ GREEN = '1;32'
17
+ YELLOW = '1;33'
18
+ LIGHT_BLUE = '1;34'
19
+ LIGHT_PURPLE = '1;35'
20
+ LIGHT_CYAN = '1;36'
21
+ WHITE = '1;37'
22
+ end
23
+
24
+ class << self
25
+ def colorize(color, text)
26
+ color = Colorize::Colors.const_get(color.to_s.upcase)
27
+ color ? colorful_text(color, text) : text
28
+ rescue
29
+ # puts color
30
+ # puts $?
31
+ text
32
+ end
33
+
34
+ def method_missing(symbol, *args)
35
+ color = Colorize::Colors.const_get(color.to_s.upcase)
36
+ return colorful_text(color, *args) if color
37
+ super
38
+ rescue
39
+ super
40
+ # puts symbol
41
+ # puts $?
42
+ # args
43
+ end
44
+
45
+ private
46
+
47
+ def colorful_text(color, text)
48
+ "\e[#{color}m#{text}\e[0;0m"
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,80 @@
1
+ require 'logger'
2
+ require_relative 'color_formatter'
3
+ require_relative 'buffered_logger'
4
+
5
+ module Helpers
6
+ module Log
7
+ class << self
8
+ def log
9
+ unless @logger
10
+ @logger = BufferedLogger.new($stdout)
11
+ @logger.formatter = ColorFormatter.new if $stdout.tty?
12
+ end
13
+ @logger
14
+ end
15
+
16
+ def log=(logger)
17
+ @logger = logger
18
+ log.info('changed logger')
19
+ end
20
+
21
+ def debug?
22
+ !@no_debug
23
+ end
24
+
25
+ def set_debug(debug, level = ::Logger::INFO)
26
+ @no_debug = !debug
27
+ log.level = level
28
+ end
29
+
30
+ def last_messages
31
+ return [] unless @logger
32
+ @logger.last_messages
33
+ end
34
+ end
35
+
36
+ def self.included(base)
37
+ class << base
38
+ def log
39
+ Log.log
40
+ end
41
+
42
+ def log=(logger)
43
+ Log.log=(logger)
44
+ end
45
+
46
+ def debug?
47
+ Log.debug?
48
+ end
49
+
50
+ def set_debug(debug, level = Logger::INFO)
51
+ Log.set_debug(debug, level)
52
+ end
53
+
54
+ def last_messages
55
+ Log.last_messages
56
+ end
57
+ end
58
+ end
59
+
60
+ def log
61
+ Log.log
62
+ end
63
+
64
+ def log=(logger)
65
+ Log.log=(logger)
66
+ end
67
+
68
+ def debug?
69
+ Log.debug?
70
+ end
71
+
72
+ def set_debug(debug, level = ::Logger::INFO)
73
+ Log.set_debug(debug, level)
74
+ end
75
+
76
+ def last_messages
77
+ Log.last_messages
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,65 @@
1
+ module Helpers
2
+ class RingBuffer
3
+ def initialize(size)
4
+ @size = size
5
+ @start = 0
6
+ @count = 0
7
+ @buffer = Array.new(size)
8
+ @mutex = Mutex.new
9
+ end
10
+
11
+ def full?
12
+ @count == @size
13
+ end
14
+
15
+ def empty?
16
+ @count == 0
17
+ end
18
+
19
+ def push(value)
20
+ @mutex.synchronize do
21
+ stop = (@start + @count) % @size
22
+ @buffer[stop] = value
23
+ if full?
24
+ @start = (@start + 1) % @size
25
+ else
26
+ @count += 1
27
+ end
28
+ value
29
+ end
30
+ end
31
+ alias :<< :push
32
+
33
+ def shift
34
+ @mutex.synchronize do
35
+ remove_element
36
+ end
37
+ end
38
+
39
+ def flush
40
+ values = []
41
+ @mutex.synchronize do
42
+ until empty?
43
+ values << remove_element
44
+ end
45
+ end
46
+ values
47
+ end
48
+
49
+ def clear
50
+ @buffer = Array.new(@size)
51
+ @start = 0
52
+ @count = 0
53
+ end
54
+
55
+ private
56
+
57
+ def remove_element
58
+ return nil if empty?
59
+ value, @buffer[@start] = @buffer[@start], nil
60
+ @start = (@start + 1) % @size
61
+ @count -= 1
62
+ value
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,5 @@
1
+ ---
2
+
3
+ - playbook: site.yml
4
+ inventory: hosts
5
+ hash_behaviour: merge
data/lib/src/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format documentation
3
+ --format json --out report.json
@@ -0,0 +1,92 @@
1
+ require 'serverspec'
2
+ require 'net/ssh'
3
+ require 'ansible_spec'
4
+ require 'winrm'
5
+
6
+ ENV['BACKEND'] = 'ssh' if ! ENV['BACKEND'] || ENV['BACKEND'] == ''
7
+
8
+ #
9
+ # Set ansible variables to serverspec property
10
+ #
11
+
12
+ host = ENV['TARGET_HOST']
13
+ hosts = ENV["TARGET_HOSTS"]
14
+
15
+ group_idx = ENV['TARGET_GROUP_INDEX'].to_i
16
+ ssh_config_file = AnsibleSpec.get_ssh_config_file
17
+
18
+ connection = ENV['TARGET_CONNECTION']
19
+
20
+ if connection != 'winrm'
21
+ #
22
+ # OS type: UN*X
23
+ #
24
+ set :backend, :"#{ENV['BACKEND']}"
25
+
26
+ if ENV['ASK_SUDO_PASSWORD']
27
+ begin
28
+ require 'highline/import'
29
+ rescue LoadError
30
+ fail "highline is not available. Try installing it."
31
+ end
32
+ set :sudo_password, ask("Enter sudo password: ") { |q| q.echo = false }
33
+ else
34
+ set :sudo_password, ENV['SUDO_PASSWORD']
35
+ end
36
+
37
+ unless ssh_config_file
38
+ options = Net::SSH::Config.for(host)
39
+ else
40
+ options = Net::SSH::Config.for(host,files=[ssh_config_file])
41
+ end
42
+
43
+ options[:user] ||= ENV['TARGET_USER']
44
+ options[:port] ||= ENV['TARGET_PORT']
45
+ options[:keys] ||= ENV['TARGET_PRIVATE_KEY']
46
+
47
+ set :host, options[:host_name] || host
48
+ set :ssh_options, options
49
+
50
+ # Disable sudo
51
+ # set :disable_sudo, true
52
+
53
+ # Set environment variables
54
+ # set :env, :LANG => 'C', :LC_MESSAGES => 'C'
55
+
56
+ # Set PATH
57
+ # set :path, '/sbin:/usr/local/sbin:$PATH'
58
+ else
59
+ #
60
+ # OS type: Windows
61
+ #
62
+ set :backend, :winrm
63
+ set :os, :family => 'windows'
64
+
65
+ user = ENV['TARGET_USER']
66
+ port = ENV['TARGET_PORT']
67
+ pass = ENV['TARGET_PASSWORD']
68
+
69
+ if user.nil?
70
+ begin
71
+ require 'highline/import'
72
+ rescue LoadError
73
+ fail "highline is not available. Try installing it."
74
+ end
75
+ user = ask("\nEnter #{host}'s login user: ") { |q| q.echo = true }
76
+ end
77
+ if pass.nil?
78
+ begin
79
+ require 'highline/import'
80
+ rescue LoadError
81
+ fail "highline is not available. Try installing it."
82
+ end
83
+ pass = ask("\nEnter #{user}@#{host}'s login password: ") { |q| q.echo = false }
84
+ end
85
+
86
+ endpoint = "http://#{host}:#{port}/wsman"
87
+
88
+ winrm = ::WinRM::WinRMWebService.new(endpoint, :ssl, :user => user, :pass => pass, :basic_auth_only => true)
89
+ winrm.set_timeout 300 # 5 minutes max timeout for any operation
90
+ Specinfra.configuration.winrm = winrm
91
+
92
+ end