scalemail 0.1.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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7afb9d2cc8a19c8510d3eee98915d87ee123e78d
4
+ data.tar.gz: ca48eb9cf1a05b3e5c859ba7f0bbc61d437bd307
5
+ SHA512:
6
+ metadata.gz: 314c9eda18923f751d95619f438e6da41ef2d6f7075290197109769a992e308267aba05baf59153b889f543a1589eae799f15d8c23502a856a9a42dc264f7333
7
+ data.tar.gz: 46363add0a2fb8c4389a20a1e5e604236da497699cb847dbc759aebf5ab46141a770b40671ab6e45eb210f401fa30a9c08b065d9827e31445b8dbdb4c79b7f74
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'scalemail'
4
+ Scalemail.new(ARGV)
@@ -0,0 +1,148 @@
1
+ require 'yaml'
2
+ require 'erb'
3
+ require_relative 'hosts'
4
+
5
+ module Configurator
6
+ class Config
7
+ attr_reader :loaded_configuration, :driver, :config_tree
8
+ @@known_drivers = ['amazonec2']
9
+ @@known_host_types = %w(generic swarm-master swarm-node)
10
+
11
+ def initialize(config_file_path)
12
+ abort("Docker Machine configuration file not found: #{config_file_path}") unless File.exist?(config_file_path)
13
+ abort("Can't read Docker Machine configuration file: #{config_file_path}") unless File.readable?(config_file_path)
14
+
15
+ template = ERB.new File.new(config_file_path).read
16
+ @loaded_configuration = YAML.load template.result(binding)
17
+
18
+ # Checking 'options' section from Docker Machine config file
19
+ @driver = get_option('driver')
20
+ abort(build_wrong_config_format_error('options => driver parameter not found')) unless @driver
21
+ abort(build_invalid_config_error("unknown driver 'aws'")) unless @@known_drivers.include?(@driver)
22
+ abort(build_invalid_config_error("driver set as 'amazonec2', but 'aws-credentials-profile' parameter not set")) \
23
+ unless get_option('aws-credentials-profile')
24
+
25
+ # Loading 'hosts' section from Docker Machine config file
26
+ hosts = @loaded_configuration['hosts']
27
+ abort(build_invalid_config_error('hosts are not defined')) unless hosts
28
+
29
+ hosts.each do |host|
30
+ host_name = host.first.to_s
31
+ host_config = get_host_config(host_name)
32
+ host_type = host_config['host-type']
33
+
34
+ # Checking 'host' section from Docker Machine config file
35
+ abort(build_invalid_config_error("host-type is not defined for host '#{host_name}'")) unless host_type
36
+ abort(build_invalid_config_error("unknown host-type '#{host_type}' for host '#{host_name}'")) \
37
+ unless @@known_host_types.include?(host_type)
38
+ abort(build_invalid_config_error("hosts-amount not defined for host '#{host_name}'")) \
39
+ unless host_config['hosts-amount']
40
+
41
+ is_hosts_amount_int = Integer(host_config['hosts-amount']) rescue false
42
+ abort(build_invalid_config_error("hosts-amount must be integer. Host: '#{host_name}'")) \
43
+ unless is_hosts_amount_int
44
+
45
+ engine_opts = host_config['engine-opts']
46
+ abort(build_invalid_config_error("engine-opts must be an array in yml notation. Host: '#{host_name}'")) \
47
+ unless engine_opts.nil? || engine_opts.kind_of?(Array)
48
+
49
+ commands_to_execute = host_config['commands-to-execute']
50
+ abort(build_invalid_config_error("commands-to-execute must be an array in yml notation. Host: '#{host_name}'")) \
51
+ unless commands_to_execute.nil? || commands_to_execute.kind_of?(Array)
52
+
53
+ engine_install_url = host_config['engine-install-url']
54
+ abort(build_invalid_config_error("engine-install-url must be a string. Host: '#{host_name}'")) \
55
+ unless engine_install_url.nil? || engine_install_url.kind_of?(String)
56
+
57
+ # Checking 'host' section from Docker Machine config file for 'swarm-node' host type
58
+ if (host_type == 'swarm-node')
59
+ abort(build_invalid_config_error("host-type is swarm-node, but swarm-discovery is not set. Host: '#{host_name}'")) \
60
+ unless host_config['swarm-discovery']
61
+ abort(build_invalid_config_error("swarm-discovery must be a string. Host: '#{host_name}'")) \
62
+ unless host_config['swarm-discovery'].kind_of?(String)
63
+ end
64
+
65
+ # Checking 'host' section from Docker Machine config file for 'amazonec2' driver
66
+ validate_amazonec2_options(host_config, host_name)
67
+
68
+ @config_tree ||= {}
69
+ hosts_amount = host_config['hosts-amount']
70
+ if hosts_amount > 1
71
+ for i in 1..hosts_amount
72
+ create_host_in_config_tree(host_name+"-#{i}", host_config, host_type, @driver)
73
+ end
74
+ else
75
+ create_host_in_config_tree(host_name, host_config, host_type, @driver)
76
+ end
77
+ end
78
+ end
79
+
80
+ def validate_amazonec2_options(host_config, host_name)
81
+ abort(build_invalid_config_error("amazonec2-region not defined for host '#{host_name}'")) unless host_config['amazonec2-region']
82
+
83
+ amazonec2_region = host_config['amazonec2-region']
84
+ abort(build_invalid_config_error("amazonec2-region must be a string. Host: '#{host_name}'")) \
85
+ unless amazonec2_region.kind_of?(String)
86
+
87
+ abort(build_invalid_config_error("amazonec2-zone not defined for host '#{host_name}'")) unless host_config['amazonec2-zone']
88
+
89
+ amazonec2_zone = host_config['amazonec2-zone']
90
+ abort(build_invalid_config_error("amazonec2-zone must be a string. Host: '#{host_name}'")) \
91
+ unless amazonec2_zone.kind_of?(String)
92
+
93
+ abort(build_invalid_config_error("amazonec2-vpc-id not defined for host '#{host_name}'")) unless host_config['amazonec2-vpc-id']
94
+
95
+ amazonec2_vpc_id = host_config['amazonec2-vpc-id']
96
+ abort(build_invalid_config_error("amazonec2-vpc-id must be a string. Host: '#{host_name}'")) \
97
+ unless amazonec2_vpc_id.kind_of?(String)
98
+
99
+ abort(build_invalid_config_error("amazonec2-subnet-id not defined for host '#{host_name}'")) unless host_config['amazonec2-subnet-id']
100
+
101
+ amazonec2_subnet_id = host_config['amazonec2-subnet-id']
102
+ abort(build_invalid_config_error("amazonec2-subnet-id must be a string. Host: '#{host_name}'")) \
103
+ unless amazonec2_subnet_id.kind_of?(String)
104
+
105
+ abort(build_invalid_config_error("amazonec2-security-group not defined for host '#{host_name}'")) unless host_config['amazonec2-security-group']
106
+
107
+ amazonec2_security_group = host_config['amazonec2-security-group']
108
+ abort(build_invalid_config_error("amazonec2-security-group must be a string. Host: '#{host_name}'")) \
109
+ unless amazonec2_security_group.kind_of?(String)
110
+
111
+ abort(build_invalid_config_error("amazonec2-instance-type not defined for host '#{host_name}'")) unless host_config['amazonec2-instance-type']
112
+
113
+ amazonec2_instance_type = host_config['amazonec2-instance-type']
114
+ abort(build_invalid_config_error("amazonec2-instance-type must be a string. Host: '#{host_name}'")) \
115
+ unless amazonec2_instance_type.kind_of?(String)
116
+
117
+ amazonec2_ami = host_config['amazonec2-ami']
118
+ abort(build_invalid_config_error("amazonec2-ami must be a string. Host: '#{host_name}'")) \
119
+ unless amazonec2_ami.nil? || amazonec2_ami.kind_of?(String)
120
+ end
121
+
122
+ private
123
+ def get_option(key)
124
+ options_hash = @loaded_configuration['options']
125
+ options_hash ? options_hash[key] : nil
126
+ end
127
+
128
+ def build_wrong_config_format_error(reason)
129
+ "Wrong Docker Machine config format: #{reason}."
130
+ end
131
+
132
+ def build_invalid_config_error(reason)
133
+ "Invalid Docker Machine config: #{reason}."
134
+ end
135
+
136
+ def get_host_config(host_node_name)
137
+ hosts_hash = @loaded_configuration['hosts']
138
+ hosts_hash ? hosts_hash[host_node_name] : nil
139
+ end
140
+
141
+ def create_host_in_config_tree(host_name, host_config, host_type, driver)
142
+ case driver
143
+ when 'amazonec2'
144
+ @config_tree[host_name] = Hosts::AmazonHost.new(host_config, host_type)
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,4 @@
1
+ require_relative './scalemail'
2
+
3
+ Scalemail.new(ARGV)
4
+ # raise Exception.new("File not found #{ARGV[1]}") unless File.exist?(ARGV[0])
@@ -0,0 +1,7 @@
1
+ class Host
2
+ attr_reader :engine_install_url, :engine_opts, :engine_insecure_registries, \
3
+ :engine_registy_mirrors, :engine_labels, :engine_storage_driver, :engine_env_vars
4
+
5
+ def initialize(config)
6
+ end
7
+ end
@@ -0,0 +1,48 @@
1
+ require_relative 'configurator'
2
+ module Hosts
3
+ class BasicHost
4
+ attr_reader :creation_string
5
+ # , :engine_insecure_registries, \
6
+ # :engine_registy_mirrors, :engine_labels, :engine_storage_driver, :engine_env_vars
7
+
8
+ def initialize(config, host_type)
9
+ @creation_string ||= []
10
+ engine_install_url = config['engine-install-url']
11
+ engine_opts = config['engine-opts']
12
+
13
+ @creation_string.push("--engine-install-url '#{engine_install_url}'") if engine_install_url
14
+ if engine_opts
15
+ engine_opts.each {|opt| @creation_string.push("--engine-opt='"+opt+"'")}
16
+ end
17
+
18
+ add_swarm_node_fields config, host_type if host_type=='swarm-node' || host_type=='swarm-master'
19
+ end
20
+
21
+ def add_swarm_node_fields(config, host_type)
22
+ swarm_discovery = config['swarm-discovery']
23
+ @creation_string.push('--swarm') if host_type=='swarm-node'
24
+ @creation_string.push('--swarm-master') if host_type=='swarm-master'
25
+ @creation_string.push("--swarm-discovery='#{swarm_discovery}'")
26
+ end
27
+
28
+ def get_creation_string
29
+ @creation_string.join(' ')
30
+ end
31
+ end
32
+
33
+ class AmazonHost < BasicHost
34
+ def initialize(config, host_type)
35
+ super(config, host_type)
36
+ @creation_string.unshift('--driver amazonec2')
37
+ @creation_string.push("--amazonec2-region #{config['amazonec2-region']}")
38
+ @creation_string.push("--amazonec2-zone #{config['amazonec2-zone']}")
39
+ @creation_string.push("--amazonec2-vpc-id #{config['amazonec2-vpc-id']}")
40
+ @creation_string.push("--amazonec2-subnet-id #{config['amazonec2-subnet-id']}")
41
+ @creation_string.push("--amazonec2-security-group #{config['amazonec2-security-group']}")
42
+ @creation_string.push("--amazonec2-instance-type #{config['amazonec2-instance-type']}")
43
+ @creation_string.push("--amazonec2-ami #{config['amazonec2-ami']}")
44
+ end
45
+ end
46
+
47
+ end
48
+
@@ -0,0 +1,132 @@
1
+ require 'open4'
2
+ require 'yaml'
3
+ require_relative 'configurator'
4
+
5
+ class Provisioner
6
+ attr_reader :config_to_provision, :hosts, :config
7
+ def initialize(config)
8
+ @config = config
9
+ @config_to_provision = @config.config_tree
10
+ @hosts = {}
11
+ end
12
+
13
+ def provision_hosts
14
+ threads = []
15
+ @config_to_provision.each do |host|
16
+ host_name = host[0]
17
+ host_config = host[1]
18
+
19
+ host_node_name = host_name.sub /\-\d*$/, ''
20
+ host_config_node = @config.loaded_configuration['hosts'][host_node_name]
21
+ placeholders = host_config_node['placeholders']
22
+ if placeholders
23
+ placeholders.each do |key, value|
24
+ if key=='host_ip' && @hosts[value] && @hosts[value][:ip]
25
+ replacement = @hosts[value][:ip]
26
+ else
27
+ abort("Cant find IP for host '#{value}' to use in placeholder")
28
+ end
29
+ host_config.creation_string.each do |parameter|
30
+ if parameter.respond_to?(:each)
31
+ parameter.each do |subparam|
32
+ if subparam.respond_to?(:sub!)
33
+ subparam.sub! "$#{key}$", replacement
34
+ end
35
+ end
36
+ else
37
+ parameter.sub! "$#{key}$", replacement
38
+ end
39
+ end
40
+ end
41
+ end
42
+ print_provisioning_plan host_name
43
+ synchron = @config.loaded_configuration['hosts'][host_node_name]['synchronous']
44
+ if synchron == true
45
+ create_host(host_name, host_config).join()
46
+ next
47
+ end
48
+ threads.push(create_host host_name, host_config)
49
+ end
50
+ threads.each {|thread| thread.join}
51
+ puts @hosts.to_s
52
+ end
53
+
54
+ def create_host(host_name, host_config)
55
+ host_creation_string = host_config.get_creation_string
56
+ thread = Thread.new do
57
+ process = run_os_command(host_name, "docker-machine create #{host_creation_string} #{host_name}")
58
+ if process[:process].exitstatus != 0
59
+ abort("#{host_name} creation failed. Check log for details.")
60
+ end
61
+ @hosts[host_name] = {:ip => get_host_ip(host_name)}
62
+ commands = @config.loaded_configuration['hosts'][host_name]['commands-to-execute']
63
+ if commands
64
+ commands.each do |command|
65
+ process = run_os_command(host_name, "docker-machine ssh #{host_name} #{command}")
66
+ if process[:process].exitstatus != 0
67
+ abort("#{host_name} provisioning failed. Check log for details.")
68
+ end
69
+ end
70
+ end
71
+ end
72
+ thread
73
+ end
74
+
75
+ def formatted_log_to_stdout(prefix, string, timestamp=true)
76
+ time = Time.new
77
+ time_string = time.strftime("%H:%M:%S")
78
+ puts "#{time_string if timestamp} #{prefix} #{string}"
79
+ end
80
+
81
+ def formatted_log_to_stderr(prefix, string, timestamp=true)
82
+ time = Time.new
83
+ time_string = time.strftime("%H:%M:%S")
84
+ STDERR.puts "#{time_string if timestamp} #{prefix} #{string}"
85
+ end
86
+
87
+ def get_host_ip(host_name)
88
+ while true
89
+ process = run_os_command host_name, "docker-machine ip #{host_name}"
90
+ if process[:process].exitstatus == 0
91
+ ip = process[:stdout][/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/,0]
92
+ if !ip.nil?
93
+ formatted_log_to_stdout("OUT [#{host_name}]", "Got IP: #{ip}")
94
+ return ip
95
+ end
96
+ else
97
+ formatted_log_to_stdout("OUT [#{host_name}]", 'Waiting 10 seconds for IP.')
98
+ sleep 10
99
+ end
100
+ end
101
+ end
102
+
103
+ def print_provisioning_plan(host_name)
104
+ host_config = @config_to_provision[host_name]
105
+ formatted_log_to_stdout "PLAN [#{host_name}]", "docker machine create #{host_config.get_creation_string} #{host_name}"
106
+ end
107
+
108
+ def run_os_command(host_name, command, stream_stdout=true, stream_stderr=true)
109
+ process_hash = {}
110
+ process = Open4::popen4('sh') do |pid, stdin, stdout, stderr|
111
+ stdin.puts command
112
+ stdin.close
113
+ if stream_stdout
114
+ stdout.each do |line|
115
+ formatted_log_to_stdout("OUT [#{host_name}]", line)
116
+ process_hash[:stdout] ||= ''
117
+ process_hash[:stdout] += line
118
+ end
119
+ end
120
+ if stream_stderr
121
+ stderr.each do |line|
122
+ formatted_log_to_stderr("ERROR [#{host_name}]", line)
123
+ process_hash[:stderr] ||= ''
124
+ process_hash[:stderr] += line
125
+ end
126
+ end
127
+ process_hash[:pid] = pid
128
+ end
129
+ process_hash[:process] = process
130
+ process_hash
131
+ end
132
+ end
@@ -0,0 +1,53 @@
1
+ require 'optparse'
2
+ require 'ostruct'
3
+ require_relative 'configurator'
4
+ require_relative 'provisioner'
5
+
6
+ class Scalemail
7
+ attr_reader :options, :configuration
8
+
9
+ def initialize(args)
10
+ @options = OpenStruct.new
11
+ opt_parser = OptionParser.new do |opts|
12
+ opts.banner = 'Usage: scalemail -m DOCKER_MACHINE_CONFIG_PATH [options]'
13
+ opts.separator ''
14
+ opts.separator 'Specific options:'
15
+
16
+ if args.empty?
17
+ args << '-h'
18
+ end
19
+
20
+ opts.on('-m', '--docker-machine-config FILE', 'Docker Machine config file to load') { |cfile| @options.docker_machine_config_file = cfile }
21
+ # opts.on('-c FILE', 'Docker Compose config file to load') { |cfile| @options.docker_compose_config_file = cfile }
22
+
23
+ opts.on_tail('-h', '--help', 'Show this message') do
24
+ puts opts
25
+ exit
26
+ end
27
+ end
28
+
29
+ opt_parser.parse!(args)
30
+ config = get_config
31
+ provision config
32
+ end
33
+
34
+ def get_config
35
+ if @configuration.nil?
36
+ config = configure @options.docker_machine_config_file
37
+ return config
38
+ else
39
+ return @configuration
40
+ end
41
+ end
42
+
43
+ def configure(config_file)
44
+ configuration = Configurator::Config.new(config_file)
45
+ configuration
46
+ end
47
+
48
+ def provision(config_tree)
49
+ provisioner = Provisioner.new(config_tree)
50
+ provisioner.provision_hosts
51
+ end
52
+
53
+ end
@@ -0,0 +1,20 @@
1
+ require 'yaml'
2
+ require 'open4'
3
+ include Open4
4
+
5
+ stdin = '42'
6
+ stdout = ''
7
+ stderr = ''
8
+
9
+ t = bg 'ruby -e"sleep 4; puts ARGF.read"', 0=>stdin, 1=>stdout, 2=>stderr
10
+
11
+ waiter = Thread.new{ y t.pid => t.exitstatus } # t.exitstatus is a blocking call!
12
+
13
+ while((status = t.status))
14
+ y "status" => status
15
+ sleep 1
16
+ end
17
+
18
+ waiter.join
19
+
20
+ y "stdout" => stdout
@@ -0,0 +1,39 @@
1
+ require 'rspec'
2
+
3
+ describe 'CLI Interaction' do
4
+ before do
5
+ $stdout = StringIO.new
6
+ $stderr = StringIO.new
7
+ @banner_message = "Usage: scalemail -m DOCKER_MACHINE_CONFIG_PATH [options]\n"\
8
+ "\n"\
9
+ "Specific options:\n"\
10
+ " -m, --docker-machine-config FILE Docker Machine config file to load\n"\
11
+ " -h, --help Show this message\n"
12
+ end
13
+ after(:all) do
14
+ $stdout = STDOUT
15
+ $stderr = STDERR
16
+ end
17
+
18
+ it 'should show usage banner if -h option used' do
19
+ expect {Scalemail.new(%w(-h))}.to raise_error(SystemExit)
20
+ out = $stdout.string
21
+ expect(out).to eq(@banner_message)
22
+ end
23
+ it 'should show usage banner if --help option used' do
24
+ expect {Scalemail.new(%w(--help))}.to raise_error(SystemExit)
25
+ out = $stdout.string
26
+ expect(out).to eq(@banner_message)
27
+ end
28
+ it 'should show usage banner if no options provided' do
29
+ expect {Scalemail.new([])}.to raise_error(SystemExit)
30
+ out = $stdout.string
31
+ expect(out).to eq(@banner_message)
32
+ end
33
+ it 'should fail with error if DockerMachine config file not specified' do
34
+ #TODO
35
+ end
36
+ it 'should fail with error if DockerCompose file not specified' do
37
+ #TODO
38
+ end
39
+ end
@@ -0,0 +1,408 @@
1
+ require 'rspec'
2
+ require 'tempfile'
3
+
4
+ def write_to_tmp_file(file_content)
5
+ tmpfile = Tempfile.new('rspec_tmp')
6
+ tmpfile.write(file_content)
7
+ tmpfile.close
8
+ tmpfile
9
+ end
10
+
11
+ describe 'Configuration Loading' do
12
+
13
+ before do
14
+ $stdout = StringIO.new
15
+ $stderr = StringIO.new
16
+ @config_tree_test_file = File.dirname(__FILE__)+ '/../resources/host-tree-generation-test.yml'
17
+ end
18
+ after(:all) do
19
+ $stdout = STDOUT
20
+ $stderr = STDERR
21
+ end
22
+
23
+ it 'should fail with error if DockerMachine config file not found' do
24
+ expect { Configurator::Config.new('fakefile') }.to raise_error(SystemExit, /Docker Machine configuration file not found: fakefile/)
25
+ end
26
+ it 'should fail with error if DockerMachine config file cannot be read' do
27
+ tmpfile = Tempfile.new('fakefile')
28
+ tmpfile.chmod(000)
29
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, /Can't read Docker Machine configuration file: #{tmpfile.path}/)
30
+ end
31
+ it 'should fail with error if DockerCompose file not found' do
32
+ #TODO
33
+ end
34
+ it 'should fail with error if DockerCompose file cannot be read' do
35
+ #TODO
36
+ end
37
+ it 'should fail with error if driver is unknown' do
38
+ file_content = "options:\n driver: aws"
39
+ tmpfile = write_to_tmp_file(file_content)
40
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
41
+ /Invalid Docker Machine config: unknown driver 'aws'./)
42
+ end
43
+ it 'should fail with error if driver is amazonec2 and aws-credentials-profile is nil' do
44
+ file_content = "options:\n driver: amazonec2"
45
+ tmpfile = write_to_tmp_file(file_content)
46
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
47
+ /Invalid Docker Machine config: driver set as 'amazonec2', but 'aws-credentials-profile' parameter not set./)
48
+ end
49
+ it 'should fail with error if hosts section is not defined' do
50
+ file_content = "options:\n"\
51
+ " driver: amazonec2\n" \
52
+ " aws-credentials-profile: default\n"
53
+ tmpfile = write_to_tmp_file(file_content)
54
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
55
+ /Invalid Docker Machine config: hosts are not defined./)
56
+ end
57
+ it 'should fail with error if host-type is not defined in host node' do
58
+ file_content = "options:\n"\
59
+ " driver: amazonec2\n" \
60
+ " aws-credentials-profile: default\n"\
61
+ "hosts:\n"\
62
+ " fail-host:\n"\
63
+ " aparam: something"
64
+ tmpfile = write_to_tmp_file(file_content)
65
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
66
+ /Invalid Docker Machine config: host-type is not defined for host 'fail-host'./)
67
+ end
68
+ it 'should fail with error if host type is unknown' do
69
+ file_content = "options:\n"\
70
+ " driver: amazonec2\n" \
71
+ " aws-credentials-profile: default\n"\
72
+ "hosts:\n"\
73
+ " fail-host:\n"\
74
+ " host-type: something"
75
+ tmpfile = write_to_tmp_file(file_content)
76
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
77
+ /Invalid Docker Machine config: unknown host-type 'something' for host 'fail-host'./)
78
+ end
79
+ it 'should fail with error if hosts-amount is not defined in host node' do
80
+ file_content = "options:\n"\
81
+ " driver: amazonec2\n" \
82
+ " aws-credentials-profile: default\n"\
83
+ "hosts:\n"\
84
+ " fail-host:\n"\
85
+ " host-type: generic"
86
+ tmpfile = write_to_tmp_file(file_content)
87
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
88
+ /Invalid Docker Machine config: hosts-amount not defined for host 'fail-host'./)
89
+ end
90
+ it 'should fail with error if hosts-amount is not integer' do
91
+ file_content = "options:\n"\
92
+ " driver: amazonec2\n" \
93
+ " aws-credentials-profile: default\n"\
94
+ "hosts:\n"\
95
+ " fail-host:\n"\
96
+ " host-type: generic\n"\
97
+ " hosts-amount: fail"
98
+ tmpfile = write_to_tmp_file(file_content)
99
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
100
+ /Invalid Docker Machine config: hosts-amount must be integer. Host: 'fail-host'./)
101
+ end
102
+ it 'should fail with error if AWS region not defined' do
103
+ file_content = "options:\n"\
104
+ " driver: amazonec2\n" \
105
+ " aws-credentials-profile: default\n"\
106
+ "hosts:\n"\
107
+ " fail-host:\n"\
108
+ " host-type: generic\n"\
109
+ " hosts-amount: 1\n"
110
+ tmpfile = write_to_tmp_file(file_content)
111
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
112
+ /Invalid Docker Machine config: amazonec2-region not defined for host 'fail-host'./)
113
+ end
114
+ it 'should fail with error if AWS region is not a string' do
115
+ file_content = "options:\n"\
116
+ " driver: amazonec2\n" \
117
+ " aws-credentials-profile: default\n"\
118
+ "hosts:\n"\
119
+ " fail-host:\n"\
120
+ " host-type: generic\n"\
121
+ " hosts-amount: 1\n"\
122
+ " amazonec2-region: \n"\
123
+ " - test"
124
+ tmpfile = write_to_tmp_file(file_content)
125
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
126
+ /Invalid Docker Machine config: amazonec2-region must be a string. Host: 'fail-host'./)
127
+ end
128
+ it 'should fail with error if AWS availability zone not defined' do
129
+ file_content = "options:\n"\
130
+ " driver: amazonec2\n" \
131
+ " aws-credentials-profile: default\n"\
132
+ "hosts:\n"\
133
+ " fail-host:\n"\
134
+ " host-type: generic\n"\
135
+ " hosts-amount: 1\n"\
136
+ " amazonec2-region: region"
137
+ tmpfile = write_to_tmp_file(file_content)
138
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
139
+ /Invalid Docker Machine config: amazonec2-zone not defined for host 'fail-host'./)
140
+ end
141
+ it 'should fail with error if AWS availability zone is not a string' do
142
+ file_content = "options:\n"\
143
+ " driver: amazonec2\n" \
144
+ " aws-credentials-profile: default\n"\
145
+ "hosts:\n"\
146
+ " fail-host:\n"\
147
+ " host-type: generic\n"\
148
+ " hosts-amount: 1\n"\
149
+ " amazonec2-region: region\n"\
150
+ " amazonec2-zone: \n"\
151
+ " - test"
152
+ tmpfile = write_to_tmp_file(file_content)
153
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
154
+ /Invalid Docker Machine config: amazonec2-zone must be a string. Host: 'fail-host'./)
155
+ end
156
+ it 'should fail with error if AWS VPC ID not defined' do
157
+ file_content = "options:\n"\
158
+ " driver: amazonec2\n" \
159
+ " aws-credentials-profile: default\n"\
160
+ "hosts:\n"\
161
+ " fail-host:\n"\
162
+ " host-type: generic\n"\
163
+ " hosts-amount: 1\n"\
164
+ " amazonec2-region: region\n"\
165
+ " amazonec2-zone: zone"
166
+ tmpfile = write_to_tmp_file(file_content)
167
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
168
+ /Invalid Docker Machine config: amazonec2-vpc-id not defined for host 'fail-host'./)
169
+ end
170
+ it 'should fail with error if AWS VPC ID is not a string' do
171
+ file_content = "options:\n"\
172
+ " driver: amazonec2\n" \
173
+ " aws-credentials-profile: default\n"\
174
+ "hosts:\n"\
175
+ " fail-host:\n"\
176
+ " host-type: generic\n"\
177
+ " hosts-amount: 1\n"\
178
+ " amazonec2-region: region\n"\
179
+ " amazonec2-zone: zone\n"\
180
+ " amazonec2-vpc-id:\n"\
181
+ " - test"
182
+ tmpfile = write_to_tmp_file(file_content)
183
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
184
+ /Invalid Docker Machine config: amazonec2-vpc-id must be a string. Host: 'fail-host'./)
185
+ end
186
+ it 'should fail with error if AWS Subnet ID not defined' do
187
+ file_content = "options:\n"\
188
+ " driver: amazonec2\n" \
189
+ " aws-credentials-profile: default\n"\
190
+ "hosts:\n"\
191
+ " fail-host:\n"\
192
+ " host-type: generic\n"\
193
+ " hosts-amount: 1\n"\
194
+ " amazonec2-region: region\n"\
195
+ " amazonec2-zone: zone\n"\
196
+ " amazonec2-vpc-id: vpc"
197
+ tmpfile = write_to_tmp_file(file_content)
198
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
199
+ /Invalid Docker Machine config: amazonec2-subnet-id not defined for host 'fail-host'./)
200
+ end
201
+ it 'should fail with error if AWS Subnet ID is not a string' do
202
+ file_content = "options:\n"\
203
+ " driver: amazonec2\n" \
204
+ " aws-credentials-profile: default\n"\
205
+ "hosts:\n"\
206
+ " fail-host:\n"\
207
+ " host-type: generic\n"\
208
+ " hosts-amount: 1\n"\
209
+ " amazonec2-region: region\n"\
210
+ " amazonec2-zone: zone\n"\
211
+ " amazonec2-vpc-id: vpc\n"\
212
+ " amazonec2-subnet-id:\n"\
213
+ " - test"
214
+ tmpfile = write_to_tmp_file(file_content)
215
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
216
+ /Invalid Docker Machine config: amazonec2-subnet-id must be a string. Host: 'fail-host'./)
217
+ end
218
+ it 'should fail with error if AWS Security Group not defined' do
219
+ file_content = "options:\n"\
220
+ " driver: amazonec2\n" \
221
+ " aws-credentials-profile: default\n"\
222
+ "hosts:\n"\
223
+ " fail-host:\n"\
224
+ " host-type: generic\n"\
225
+ " hosts-amount: 1\n"\
226
+ " amazonec2-region: region\n"\
227
+ " amazonec2-zone: zone\n"\
228
+ " amazonec2-vpc-id: vpc\n"\
229
+ " amazonec2-subnet-id: subnet"
230
+ tmpfile = write_to_tmp_file(file_content)
231
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
232
+ /Invalid Docker Machine config: amazonec2-security-group not defined for host 'fail-host'./)
233
+ end
234
+ it 'should fail with error if AWS Security Group is not a string' do
235
+ file_content = "options:\n"\
236
+ " driver: amazonec2\n" \
237
+ " aws-credentials-profile: default\n"\
238
+ "hosts:\n"\
239
+ " fail-host:\n"\
240
+ " host-type: generic\n"\
241
+ " hosts-amount: 1\n"\
242
+ " amazonec2-region: region\n"\
243
+ " amazonec2-zone: zone\n"\
244
+ " amazonec2-vpc-id: vpc\n"\
245
+ " amazonec2-subnet-id: subnet\n"\
246
+ " amazonec2-security-group:\n"\
247
+ " - test"
248
+ tmpfile = write_to_tmp_file(file_content)
249
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
250
+ /Invalid Docker Machine config: amazonec2-security-group must be a string. Host: 'fail-host'./)
251
+ end
252
+ it 'should fail with error if AWS Instance Type not defined' do
253
+ file_content = "options:\n"\
254
+ " driver: amazonec2\n" \
255
+ " aws-credentials-profile: default\n"\
256
+ "hosts:\n"\
257
+ " fail-host:\n"\
258
+ " host-type: generic\n"\
259
+ " hosts-amount: 1\n"\
260
+ " amazonec2-region: region\n"\
261
+ " amazonec2-zone: zone\n"\
262
+ " amazonec2-vpc-id: vpc\n"\
263
+ " amazonec2-subnet-id: subnet\n"\
264
+ " amazonec2-security-group: sg"
265
+ tmpfile = write_to_tmp_file(file_content)
266
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
267
+ /Invalid Docker Machine config: amazonec2-instance-type not defined for host 'fail-host'./)
268
+ end
269
+ it 'should fail with error if AWS Instance Type is not a string' do
270
+ file_content = "options:\n"\
271
+ " driver: amazonec2\n" \
272
+ " aws-credentials-profile: default\n"\
273
+ "hosts:\n"\
274
+ " fail-host:\n"\
275
+ " host-type: generic\n"\
276
+ " hosts-amount: 1\n"\
277
+ " amazonec2-region: region\n"\
278
+ " amazonec2-zone: zone\n"\
279
+ " amazonec2-vpc-id: vpc\n"\
280
+ " amazonec2-subnet-id: subnet\n"\
281
+ " amazonec2-security-group: sg\n"\
282
+ " amazonec2-instance-type:\n"\
283
+ " - test"
284
+ tmpfile = write_to_tmp_file(file_content)
285
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
286
+ /Invalid Docker Machine config: amazonec2-instance-type must be a string. Host: 'fail-host'./)
287
+ end
288
+ it 'should fail with error if AWS AMI is not a string' do
289
+ file_content = "options:\n"\
290
+ " driver: amazonec2\n" \
291
+ " aws-credentials-profile: default\n"\
292
+ "hosts:\n"\
293
+ " fail-host:\n"\
294
+ " host-type: generic\n"\
295
+ " hosts-amount: 1\n"\
296
+ " amazonec2-region: region\n"\
297
+ " amazonec2-zone: zone\n"\
298
+ " amazonec2-vpc-id: vpc\n"\
299
+ " amazonec2-subnet-id: subnet\n"\
300
+ " amazonec2-security-group: sg\n"\
301
+ " amazonec2-instance-type: t2.micro\n"\
302
+ " amazonec2-ami:\n"\
303
+ " - test"
304
+ tmpfile = write_to_tmp_file(file_content)
305
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
306
+ /Invalid Docker Machine config: amazonec2-ami must be a string. Host: 'fail-host'./)
307
+ end
308
+ it 'should fail with error if driver is not defined in options section' do
309
+ file_content = "driver: aws"
310
+ tmpfile = write_to_tmp_file(file_content)
311
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
312
+ /Wrong Docker Machine config format: options => driver parameter not found./)
313
+ end
314
+ it 'should fail with error if engine-opts is not an array' do
315
+ file_content = "options:\n"\
316
+ " driver: amazonec2\n" \
317
+ " aws-credentials-profile: default\n"\
318
+ "hosts:\n"\
319
+ " fail-host:\n"\
320
+ " host-type: generic\n"\
321
+ " hosts-amount: 2\n"\
322
+ " engine-opts:\n" \
323
+ " op1: sdf"
324
+ tmpfile = write_to_tmp_file(file_content)
325
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
326
+ /Invalid Docker Machine config: engine-opts must be an array in yml notation. Host: 'fail-host'./)
327
+ end
328
+ it 'should fail with error if commands-to-execute is not an array' do
329
+ file_content = "options:\n"\
330
+ " driver: amazonec2\n" \
331
+ " aws-credentials-profile: default\n"\
332
+ "hosts:\n"\
333
+ " fail-host:\n"\
334
+ " host-type: generic\n"\
335
+ " hosts-amount: 2\n"\
336
+ " commands-to-execute:\n" \
337
+ " op1: sdf"
338
+ tmpfile = write_to_tmp_file(file_content)
339
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
340
+ /Invalid Docker Machine config: commands-to-execute must be an array in yml notation. Host: 'fail-host'./)
341
+ end
342
+ it 'should fail with error if engine-install-url is not a string' do
343
+ file_content = "options:\n"\
344
+ " driver: amazonec2\n" \
345
+ " aws-credentials-profile: default\n"\
346
+ "hosts:\n"\
347
+ " fail-host:\n"\
348
+ " host-type: generic\n"\
349
+ " hosts-amount: 2\n"\
350
+ " engine-install-url:\n" \
351
+ " op1: sdf"
352
+ tmpfile = write_to_tmp_file(file_content)
353
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
354
+ /Invalid Docker Machine config: engine-install-url must be a string. Host: 'fail-host'./)
355
+ end
356
+ it 'should fail with error if host-type is "swarm-node" and swarm-discovery is not defined' do
357
+ file_content = "options:\n"\
358
+ " driver: amazonec2\n" \
359
+ " aws-credentials-profile: default\n"\
360
+ "hosts:\n"\
361
+ " fail-host:\n"\
362
+ " host-type: swarm-node\n"\
363
+ " hosts-amount: 2"
364
+ tmpfile = write_to_tmp_file(file_content)
365
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
366
+ /Invalid Docker Machine config: host-type is swarm-node, but swarm-discovery is not set. Host: 'fail-host'./)
367
+ end
368
+ it 'should fail with error if host-type is "swarm-node" and swarm-discovery is not a string' do
369
+ file_content = "options:\n"\
370
+ " driver: amazonec2\n" \
371
+ " aws-credentials-profile: default\n"\
372
+ "hosts:\n"\
373
+ " fail-host:\n"\
374
+ " host-type: swarm-node\n"\
375
+ " hosts-amount: 2\n"\
376
+ " swarm-discovery:\n" \
377
+ " op1: sdf"
378
+ tmpfile = write_to_tmp_file(file_content)
379
+ expect { Configurator::Config.new(tmpfile.path) }.to raise_error(SystemExit, \
380
+ /Invalid Docker Machine config: swarm-discovery must be a string. Host: 'fail-host'./)
381
+ end
382
+ it 'should return proper creation string for amazonec2 generic host type' do
383
+ test_creation_string = "--driver amazonec2 "\
384
+ "--engine-install-url 'http://test.com' --engine-opt='opt1' --engine-opt='opt2' "\
385
+ "--amazonec2-region region --amazonec2-zone zone --amazonec2-vpc-id vpc "\
386
+ "--amazonec2-subnet-id subnet --amazonec2-security-group sg --amazonec2-instance-type it"
387
+ config = Configurator::Config.new(@config_tree_test_file)
388
+ expect(config.config_tree['generic-host'].get_creation_string).to eq(test_creation_string)
389
+ end
390
+ it 'should return proper creation string for swarm-node host type' do
391
+ test_creation_string = "--driver amazonec2 "\
392
+ "--engine-install-url 'http://test.com' --engine-opt='opt1' --engine-opt='opt2' "\
393
+ "--swarm --swarm-discovery='something_somewhere' "\
394
+ "--amazonec2-region region --amazonec2-zone zone --amazonec2-vpc-id vpc "\
395
+ "--amazonec2-subnet-id subnet --amazonec2-security-group sg --amazonec2-instance-type it"
396
+ config = Configurator::Config.new(@config_tree_test_file)
397
+ expect(config.config_tree['swarm-node'].get_creation_string).to eq(test_creation_string)
398
+ end
399
+ it 'should return proper creation string for swarm-master host type' do
400
+ test_creation_string = "--driver amazonec2 "\
401
+ "--engine-install-url 'http://test.com' --engine-opt='opt1' --engine-opt='opt2' "\
402
+ "--swarm-master --swarm-discovery='something_somewhere' "\
403
+ "--amazonec2-region region --amazonec2-zone zone --amazonec2-vpc-id vpc "\
404
+ "--amazonec2-subnet-id subnet --amazonec2-security-group sg --amazonec2-instance-type it"
405
+ config = Configurator::Config.new(@config_tree_test_file)
406
+ expect(config.config_tree['swarm-master'].get_creation_string).to eq(test_creation_string)
407
+ end
408
+ end
@@ -0,0 +1,25 @@
1
+ require 'rspec'
2
+ require_relative '../../lib/provisioner'
3
+
4
+ describe 'CLI Interaction' do
5
+ before do
6
+ $stdout = StringIO.new
7
+ $stderr = StringIO.new
8
+ end
9
+ after(:all) do
10
+ $stdout = STDOUT
11
+ $stderr = STDERR
12
+ end
13
+
14
+ it 'should print timestamped message in STDOUT' do
15
+ # TODO: fix
16
+ # Provisioner.new(nil).formatted_log_to_stdout('prefix', 'string')
17
+ # expect($stdout.string).to match(/\d{2}:\d{2} prefix string/)
18
+ end
19
+ it 'should print message without timestamp in STDOUT' do
20
+ #TODO: fix
21
+ #Provisioner.new(nil).formatted_log_to_stdout('prefix', 'string', false)
22
+ #expect($stdout.string).to match(/prefix string/)
23
+ end
24
+
25
+ end
@@ -0,0 +1,34 @@
1
+ require 'rspec'
2
+ require_relative '../../lib/scalemail'
3
+ require_relative '../spec_helper'
4
+
5
+
6
+ describe Scalemail do
7
+
8
+ #
9
+ # it 'raises error if configuration file cannot be readed' do
10
+ # begin
11
+ # Scalemail.new(%w(-m fakefile))
12
+ # rescue SystemExit
13
+ # expect($stderr.string).to match("Can't read Docker Machine configuration file: fakefile")
14
+ # end
15
+ # end
16
+ # it 'shows usage banner if no options provided' do
17
+ #
18
+ #
19
+ # end
20
+ # it 'shows usage banner if -h key provided' do
21
+ # begin
22
+ # Scalemail.new(%w(-h))
23
+ # rescue SystemExit
24
+ # expect($stdout.string).to match(@banner_message)
25
+ # end
26
+ # end
27
+ # it 'shows usage banner if --help key provided' do
28
+ # begin
29
+ # Scalemail.new(%w(--help))
30
+ # rescue SystemExit
31
+ # expect($stdout.string).to match(@banner_message)
32
+ # end
33
+ # end
34
+ end
@@ -0,0 +1,62 @@
1
+ options:
2
+ driver: amazonec2
3
+ aws-credentials-profile: default
4
+ hosts:
5
+ generic-host:
6
+ host-type: generic
7
+ hosts-amount: 1
8
+ engine-install-url: http://test.com
9
+ engine-opts:
10
+ - opt1
11
+ - opt2
12
+ amazonec2-region: region
13
+ amazonec2-zone: zone
14
+ amazonec2-vpc-id: vpc
15
+ amazonec2-subnet-id: subnet
16
+ amazonec2-security-group: sg
17
+ amazonec2-instance-type: it
18
+
19
+ swarm-node:
20
+ host-type: swarm-node
21
+ hosts-amount: 1
22
+ engine-install-url: http://test.com
23
+ engine-opts:
24
+ - opt1
25
+ - opt2
26
+ swarm-discovery: something_somewhere
27
+ amazonec2-region: region
28
+ amazonec2-zone: zone
29
+ amazonec2-vpc-id: vpc
30
+ amazonec2-subnet-id: subnet
31
+ amazonec2-security-group: sg
32
+ amazonec2-instance-type: it
33
+
34
+ swarm-node-multiple:
35
+ host-type: swarm-node
36
+ hosts-amount: 3
37
+ engine-install-url: http://test.com
38
+ engine-opts:
39
+ - opt1
40
+ - opt2
41
+ swarm-discovery: something_somewhere
42
+ amazonec2-region: region
43
+ amazonec2-zone: zone
44
+ amazonec2-vpc-id: vpc
45
+ amazonec2-subnet-id: subnet
46
+ amazonec2-security-group: sg
47
+ amazonec2-instance-type: it
48
+
49
+ swarm-master:
50
+ host-type: swarm-master
51
+ hosts-amount: 1
52
+ engine-install-url: http://test.com
53
+ engine-opts:
54
+ - opt1
55
+ - opt2
56
+ swarm-discovery: something_somewhere
57
+ amazonec2-region: region
58
+ amazonec2-zone: zone
59
+ amazonec2-vpc-id: vpc
60
+ amazonec2-subnet-id: subnet
61
+ amazonec2-security-group: sg
62
+ amazonec2-instance-type: it
@@ -0,0 +1,97 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
4
+ # this file to always be loaded, without a need to explicitly require it in any
5
+ # files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need
13
+ # it.
14
+ #
15
+ # The `.rspec` file also contains a few flags that are not defaults but that
16
+ # users commonly want.
17
+ #
18
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
19
+ RSpec.configure do |config|
20
+ # rspec-expectations config goes here. You can use an alternate
21
+ # assertion/expectation library such as wrong or the stdlib/minitest
22
+ # assertions if you prefer.
23
+ config.expect_with :rspec do |expectations|
24
+ # This option will default to `true` in RSpec 4. It makes the `description`
25
+ # and `failure_message` of custom matchers include text for helper methods
26
+ # defined using `chain`, e.g.:
27
+ # be_bigger_than(2).and_smaller_than(4).description
28
+ # # => "be bigger than 2 and smaller than 4"
29
+ # ...rather than:
30
+ # # => "be bigger than 2"
31
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
32
+ end
33
+
34
+ # rspec-mocks config goes here. You can use an alternate test double
35
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
36
+ config.mock_with :rspec do |mocks|
37
+ # Prevents you from mocking or stubbing a method that does not exist on
38
+ # a real object. This is generally recommended, and will default to
39
+ # `true` in RSpec 4.
40
+ mocks.verify_partial_doubles = true
41
+ end
42
+
43
+ # The settings below are suggested to provide a good initial experience
44
+ # with RSpec, but feel free to customize to your heart's content.
45
+ =begin
46
+ # These two settings work together to allow you to limit a spec run
47
+ # to individual examples or groups you care about by tagging them with
48
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
49
+ # get run.
50
+ config.filter_run :focus
51
+ config.run_all_when_everything_filtered = true
52
+
53
+ # Allows RSpec to persist some state between runs in order to support
54
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
55
+ # you configure your source control system to ignore this file.
56
+ config.example_status_persistence_file_path = "spec/examples.txt"
57
+
58
+ # Limits the available syntax to the non-monkey patched syntax that is
59
+ # recommended. For more details, see:
60
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
61
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
62
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
63
+ config.disable_monkey_patching!
64
+
65
+ # This setting enables warnings. It's recommended, but in some cases may
66
+ # be too noisy due to issues in dependencies.
67
+ config.warnings = true
68
+ =end
69
+
70
+ # Many RSpec users commonly either run the entire suite or an individual
71
+ # file, and it's useful to allow more verbose output when running an
72
+ # individual spec file.
73
+ if config.files_to_run.one?
74
+ # Use the documentation formatter for detailed output,
75
+ # unless a formatter has already been configured
76
+ # (e.g. via a command-line flag).
77
+ config.default_formatter = 'doc'
78
+ end
79
+ =begin
80
+ # Print the 10 slowest examples and example groups at the
81
+ # end of the spec run, to help surface which specs are running
82
+ # particularly slow.
83
+ config.profile_examples = 10
84
+
85
+ # Run specs in random order to surface order dependencies. If you find an
86
+ # order dependency and want to debug it, you can fix the order by providing
87
+ # the seed, which is printed after each run.
88
+ # --seed 1234
89
+ config.order = :random
90
+
91
+ # Seed global randomization in this process using the `--seed` CLI option.
92
+ # Setting this allows you to use `--seed` to deterministically reproduce
93
+ # test failures related to randomization by passing the same `--seed` value
94
+ # as the one that triggered the failure.
95
+ Kernel.srand config.seed
96
+ =end
97
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: scalemail
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ievgen Iezhachenko
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-05-13 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Framework for microservises scaling using Docker and cloud platforms.
14
+ email: ievgen.iezhachenko@gmail.com
15
+ executables:
16
+ - scalemail
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - bin/scalemail
21
+ - lib/configurator.rb
22
+ - lib/entry.rb
23
+ - lib/host_types.rb
24
+ - lib/hosts.rb
25
+ - lib/provisioner.rb
26
+ - lib/scalemail.rb
27
+ - lib/test.rb
28
+ - spec/lib/cli_spec.rb
29
+ - spec/lib/configuration_loading_spec.rb
30
+ - spec/lib/provisioner_spec.rb
31
+ - spec/lib/scalemail_spec.rb
32
+ - spec/resources/host-tree-generation-test.yml
33
+ - spec/spec_helper.rb
34
+ homepage: https://github.com/iiezhachenko/scalemail
35
+ licenses:
36
+ - MIT
37
+ metadata: {}
38
+ post_install_message:
39
+ rdoc_options: []
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ requirements: []
53
+ rubyforge_project:
54
+ rubygems_version: 2.5.1
55
+ signing_key:
56
+ specification_version: 4
57
+ summary: Application scaling framework
58
+ test_files: []
59
+ has_rdoc: