ansible_spec_plus 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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