inception-server 0.2.1

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.
Files changed (75) hide show
  1. data/.chef/knife.rb +4 -0
  2. data/.gitignore +21 -0
  3. data/.kitchen.yml +47 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +18 -0
  6. data/Berksfile +8 -0
  7. data/Berksfile.lock +9 -0
  8. data/ChangeLog.md +20 -0
  9. data/Gemfile +27 -0
  10. data/Guardfile +6 -0
  11. data/LICENSE.txt +22 -0
  12. data/README.md +126 -0
  13. data/Rakefile +66 -0
  14. data/TODO.md +25 -0
  15. data/bin/inception +8 -0
  16. data/bin/inception-server +8 -0
  17. data/config/ssh/kitchen-aws +23 -0
  18. data/cookbooks/bosh_inception/README.md +15 -0
  19. data/cookbooks/bosh_inception/attributes/default.rb +25 -0
  20. data/cookbooks/bosh_inception/files/default/Gemfile.cf +5 -0
  21. data/cookbooks/bosh_inception/files/default/Gemfile.micro +5 -0
  22. data/cookbooks/bosh_inception/metadata.rb +32 -0
  23. data/cookbooks/bosh_inception/recipes/default.rb +16 -0
  24. data/cookbooks/bosh_inception/recipes/install_bosh.rb +37 -0
  25. data/cookbooks/bosh_inception/recipes/install_ruby.rb +10 -0
  26. data/cookbooks/bosh_inception/recipes/mount_store_volume.rb +24 -0
  27. data/cookbooks/bosh_inception/recipes/packages.rb +23 -0
  28. data/cookbooks/bosh_inception/recipes/setup_dotfog.rb +29 -0
  29. data/cookbooks/bosh_inception/recipes/setup_git.rb +34 -0
  30. data/cookbooks/bosh_inception/recipes/useful_dirs.rb +13 -0
  31. data/inception-server.gemspec +43 -0
  32. data/lib/inception/cli.rb +141 -0
  33. data/lib/inception/cli_helpers/display.rb +26 -0
  34. data/lib/inception/cli_helpers/interactions.rb +15 -0
  35. data/lib/inception/cli_helpers/prepare_deploy_settings.rb +89 -0
  36. data/lib/inception/cli_helpers/provider.rb +14 -0
  37. data/lib/inception/cli_helpers/settings.rb +53 -0
  38. data/lib/inception/inception_server.rb +304 -0
  39. data/lib/inception/inception_server_cookbook.rb +90 -0
  40. data/lib/inception/next_deploy_actions.rb +20 -0
  41. data/lib/inception/providers/README.md +5 -0
  42. data/lib/inception/providers/clients/aws_provider_client.rb +144 -0
  43. data/lib/inception/providers/clients/fog_provider_client.rb +185 -0
  44. data/lib/inception/providers/clients/openstack_provider_client.rb +84 -0
  45. data/lib/inception/providers/constants/aws_constants.rb +25 -0
  46. data/lib/inception/providers/constants/openstack_constants.rb +12 -0
  47. data/lib/inception/providers.rb +28 -0
  48. data/lib/inception/version.rb +3 -0
  49. data/lib/inception.rb +9 -0
  50. data/nodes/.gitkeep +0 -0
  51. data/spec/assets/.gitkeep +0 -0
  52. data/spec/assets/gitconfig +5 -0
  53. data/spec/assets/settings/aws-before-server.yml +14 -0
  54. data/spec/assets/settings/aws-created-server.yml +31 -0
  55. data/spec/integration/.gitkeep +0 -0
  56. data/spec/integration/aws/aws_basic_spec.rb +38 -0
  57. data/spec/spec_helper.rb +50 -0
  58. data/spec/support/aws/aws_helpers.rb +73 -0
  59. data/spec/support/settings_helper.rb +20 -0
  60. data/spec/support/stdout_capture.rb +17 -0
  61. data/spec/unit/.gitkeep +0 -0
  62. data/spec/unit/cli_delete_spec.rb +39 -0
  63. data/spec/unit/cli_deploy_aws_spec.rb +83 -0
  64. data/spec/unit/cli_ssh_spec.rb +80 -0
  65. data/spec/unit/inception_server_cookbook_spec.rb +62 -0
  66. data/spec/unit/inception_server_spec.rb +58 -0
  67. data/spec/unit/providers/aws_spec.rb +198 -0
  68. data/test/integration/default/bats/discover_user.bash +2 -0
  69. data/test/integration/default/bats/dotfog.bats +11 -0
  70. data/test/integration/default/bats/install_ruby.bats +8 -0
  71. data/test/integration/default/bats/useful_dirs.bats +8 -0
  72. data/test/integration/default/bats/user.bats +9 -0
  73. data/test/integration/default/bats/verify_bosh.bats +18 -0
  74. data/test/integration/default/bats/verify_git.bats +18 -0
  75. metadata +361 -0
@@ -0,0 +1,185 @@
1
+ # Copyright (c) 2012-2013 Stark & Wayne, LLC
2
+
3
+ require "fog"
4
+ module Inception; module Providers; module Clients; end; end; end
5
+
6
+ class Inception::Providers::Clients::FogProviderClient
7
+ attr_reader :fog_compute
8
+ attr_reader :attributes
9
+
10
+ def initialize(attributes)
11
+ @attributes = attributes.is_a?(Hash) ? ReadWriteSettings.new(attributes) : attributes
12
+ raise "@attributes must be ReadWriteSettings (or Hash)" unless @attributes.is_a?(ReadWriteSettings)
13
+ setup_fog_connection
14
+ end
15
+
16
+ def flavor_id(flavor_name)
17
+ if flavor = fog_compute.flavors.find { |fl| fl.name == flavor_name }
18
+ flavor.id
19
+ end
20
+ end
21
+
22
+ def setup_fog_connection
23
+ raise "must implement"
24
+ end
25
+
26
+ def create_key_pair(key_pair_name)
27
+ fog_compute.key_pairs.create(:name => key_pair_name)
28
+ end
29
+
30
+ # set_resource_name(fog_server, "inception")
31
+ # set_resource_name(volume, "inception-root")
32
+ # set_resource_name(volume, "inception-store")
33
+ def set_resource_name(resource, name)
34
+ fog_compute.tags.create :key => "Name", :value => name, :resource_id => resource.id
35
+ end
36
+
37
+ def delete_key_pair_if_exists(key_pair_name)
38
+ if fog_key_pair = fog_compute.key_pairs.get(key_pair_name)
39
+ fog_key_pair.destroy
40
+ end
41
+ end
42
+
43
+ def delete_servers_with_name(name)
44
+ fog_compute.servers.select {|s| s.tags["Name"] && (s.tags["Name"].downcase == name.downcase) }.each do |server|
45
+ puts "Destroying server #{server.id}... "
46
+ server.destroy
47
+ end
48
+ end
49
+
50
+ def delete_volumes_with_name(name)
51
+ fog_compute.volumes.select do |v|
52
+ volume_name = v.tags["Name"]
53
+ volume_name && volume_name.downcase == name.downcase
54
+ end.each do |volume|
55
+ puts "Destroying volume #{volume.id}... "
56
+ volume.destroy
57
+ end
58
+ end
59
+
60
+ # Destroy all IP addresses that aren't bound to a server
61
+ def cleanup_unused_ip_addresses
62
+ fog_compute.addresses.each do |a|
63
+ unless a.server
64
+ puts "Deleting unused IP address #{a.public_ip}... "
65
+ a.destroy
66
+ end
67
+ end
68
+ end
69
+
70
+ # Creates or reuses an security group and opens ports.
71
+ #
72
+ # +security_group_name+ is the name to be created or reused
73
+ # +ports+ is a hash of name/port for ports to open, for example:
74
+ # {
75
+ # ssh: 22,
76
+ # http: 80,
77
+ # https: 443
78
+ # }
79
+ # protocol defaults to TCP
80
+ # You can also use a more verbose +ports+ using the format:
81
+ # {
82
+ # ssh: 22,
83
+ # http: { ports: (80..82) },
84
+ # mosh: { protocol: "udp", ports: (60000..60050) }
85
+ # mosh: { protocol: "rdp", ports: (3398..3398), ip_ranges: [ { cidrIp: "196.212.12.34/32" } ] }
86
+ # }
87
+ # In this example,
88
+ # * TCP 22 will be opened for ssh from any ip_range,
89
+ # * TCP ports 80, 81, 82 for http from any ip_range,
90
+ # * UDP 60000 -> 60050 for mosh from any ip_range and
91
+ # * TCP 3398 for RDP from ip range: 96.212.12.34/32
92
+ def create_security_group(security_group_name, description, ports)
93
+ security_groups = fog_compute.security_groups
94
+ unless sg = security_groups.find { |s| s.name == security_group_name }
95
+ sg = fog_compute.security_groups.create(name: security_group_name, description: description)
96
+ puts "Created security group #{security_group_name}"
97
+ ip_permissions = ip_permissions(sg)
98
+ ports_opened = 0
99
+ ports.each do |name, port_defn|
100
+ (protocol, port_range, ip_range) = extract_port_definition(port_defn)
101
+ unless port_open?(ip_permissions, port_range, protocol, ip_range)
102
+ authorize_port_range(sg, port_range, protocol, ip_range)
103
+ puts " -> opened #{name} ports #{protocol.upcase} #{port_range.min}..#{port_range.max} from IP range #{ip_range}"
104
+ ports_opened += 1
105
+ end
106
+ end
107
+ else
108
+ puts "Reusing security group #{security_group_name}"
109
+ end
110
+ true
111
+ end
112
+
113
+ def port_open?(ip_permissions, port_range, protocol, ip_range)
114
+ ip_permissions && ip_permissions.find do |ip|
115
+ ip["ipProtocol"] == protocol \
116
+ && ip["ipRanges"].detect { |range| range["cidrIp"] == ip_range } \
117
+ && ip["fromPort"] <= port_range.min \
118
+ && ip["toPort"] >= port_range.max
119
+ end
120
+ end
121
+
122
+ def authorize_port_range(sg, port_range, protocol, ip_range)
123
+ sg.authorize_port_range(port_range, {:ip_protocol => protocol, :cidr_ip => ip_range})
124
+ end
125
+
126
+ def ip_permissions(sg)
127
+ sg.ip_permissions
128
+ end
129
+
130
+ # Any of the following +port_defn+ can be used:
131
+ # {
132
+ # ssh: 22,
133
+ # http: { ports: (80..82) },
134
+ # mosh: { protocol: "udp", ports: (60000..60050) }
135
+ # mosh: { protocol: "rdp", ports: (3398..3398), ip_range: "196.212.12.34/32" }
136
+ # }
137
+ # In this example,
138
+ # * TCP 22 will be opened for ssh from any ip_range,
139
+ # * TCP ports 80, 81, 82 for http from any ip_range,
140
+ # * UDP 60000 -> 60050 for mosh from any ip_range and
141
+ # * TCP 3398 for RDP from ip range: 96.212.12.34/32
142
+ def extract_port_definition(port_defn)
143
+ protocol = "tcp"
144
+ ip_range = "0.0.0.0/0"
145
+ if port_defn.is_a? Integer
146
+ port_range = (port_defn..port_defn)
147
+ elsif port_defn.is_a? Range
148
+ port_range = port_defn
149
+ elsif port_defn.is_a? Hash
150
+ protocol = port_defn[:protocol] if port_defn[:protocol]
151
+ port_range = port_defn[:ports] if port_defn[:ports]
152
+ ip_range = port_defn[:ip_range] if port_defn[:ip_range]
153
+ end
154
+ [protocol, port_range, ip_range]
155
+ end
156
+
157
+ def provision_or_reuse_public_ip_address(options={})
158
+ provision_public_ip_address(options) || find_unused_public_ip_address(options)
159
+ end
160
+
161
+ def find_unused_public_ip_address(options={})
162
+ if address = fog_compute.addresses.find { |s| s.server_id.nil? }
163
+ address.public_ip
164
+ end
165
+ end
166
+
167
+ def bootstrap(new_attributes)
168
+ server = fog_compute.servers.new(new_attributes)
169
+
170
+ unless new_attributes[:key_name]
171
+ raise "please provide :key_name attribute"
172
+ end
173
+ unless private_key_path = new_attributes.delete(:private_key_path)
174
+ raise "please provide :private_key_path attribute"
175
+ end
176
+
177
+ server.save
178
+ unless Fog.mocking?
179
+ server.wait_for { ready? }
180
+ server.setup(keys: [private_key_path])
181
+ end
182
+ server
183
+ end
184
+
185
+ end
@@ -0,0 +1,84 @@
1
+ # Copyright (c) 2012-2013 Stark & Wayne, LLC
2
+
3
+ module Inception; module Providers; module Clients; end; end; end
4
+
5
+ require "inception/providers/clients/fog_provider_client"
6
+ require "inception/providers/constants/openstack_constants"
7
+
8
+ class Inception::Providers::Clients::OpenStackProviderClient < Inception::Providers::Clients::FogProviderClient
9
+ # @return [String] provisions a new public IP address in target region
10
+ # TODO nil if none available
11
+ def provision_public_ip_address(options={})
12
+ address = fog_compute.addresses.create
13
+ address.ip
14
+ # TODO catch error and return nil
15
+ end
16
+
17
+ def associate_ip_address_with_server(ip_address, server)
18
+ address = fog_compute.addresses.find { |a| a.ip == ip_address }
19
+ address.server = server
20
+ end
21
+
22
+ # Hook method for FogProviderClient#create_security_group
23
+ def ip_permissions(sg)
24
+ sg.rules
25
+ end
26
+
27
+ # Hook method for FogProviderClient#create_security_group
28
+ def authorize_port_range(sg, port_range, protocol, ip_range)
29
+ sg.create_security_group_rule(port_range.min, port_range.max, protocol, ip_range)
30
+ end
31
+
32
+ def find_server_device(server, device)
33
+ va = fog_compute.get_server_volumes(server.id).body['volumeAttachments']
34
+ va.find { |v| v["device"] == device }
35
+ end
36
+
37
+ def create_and_attach_volume(name, disk_size, server, device)
38
+ volume = fog_compute.volumes.create(:name => name,
39
+ :description => "",
40
+ :size => disk_size,
41
+ :availability_zone => server.availability_zone)
42
+ volume.wait_for { volume.status == 'available' }
43
+ volume.attach(server.id, device)
44
+ volume.wait_for { volume.status == 'in-use' }
45
+ end
46
+
47
+ def image_id
48
+ raise "Not yet implemented"
49
+ end
50
+
51
+ # Construct a Fog::Compute object
52
+ # Uses +attributes+ which normally originates from +settings.provider+
53
+ def setup_fog_connection
54
+ configuration = Fog.symbolize_credentials(attributes.credentials)
55
+ configuration[:provider] = "OpenStack"
56
+ @fog_compute = Fog::Compute.new(configuration)
57
+ end
58
+
59
+ def fog_attributes(inception_server)
60
+ # :name => "Inception VM",
61
+ # :key_name => key_name,
62
+ # :private_key_path => inception_vm_private_key_path,
63
+ # :flavor_ref => inception_flavor.id,
64
+ # :image_ref => inception_image.id,
65
+ # :security_groups => [settings["inception"]["security_group"]],
66
+ # :username => username
67
+ {
68
+ name: inception_server.server_name,
69
+ key_name: inception_server.key_name,
70
+ private_key_path: inception_server.private_key_path,
71
+ image_ref: inception_server.image_id,
72
+ flavor_ref: flavor_id(inception_server.flavor),
73
+ security_groups: inception_server.security_groups,
74
+ public_key: inception_server.public_key,
75
+ public_ip_address: inception_server.ip_address,
76
+ bits: 64,
77
+ username: "ubuntu",
78
+ }
79
+ end
80
+
81
+ def openstack_constants
82
+ Inception::Providers::Constants::OpenStackConstants
83
+ end
84
+ end
@@ -0,0 +1,25 @@
1
+ # Copyright (c) 2012-2013 Stark & Wayne, LLC
2
+
3
+ module Inception; module Providers; module Constants; end; end; end
4
+
5
+ module Inception::Providers::Constants::AwsConstants
6
+ extend self
7
+
8
+ # http://docs.aws.amazon.com/general/latest/gr/rande.html#region
9
+ def region_labels
10
+ [
11
+ { label: "US East (Northern Virginia) Region", code: "us-east-1" },
12
+ { label: "US West (Oregon) Region", code: "us-west-2" },
13
+ { label: "US West (Northern California) Region", code: "us-west-1" },
14
+ { label: "EU (Ireland) Region", code: "eu-west-1" },
15
+ { label: "Asia Pacific (Singapore) Region", code: "ap-southeast-1" },
16
+ { label: "Asia Pacific (Sydney) Region", code: "ap-southeast-2" },
17
+ { label: "Asia Pacific (Tokyo) Region", code: "ap-northeast-1" },
18
+ { label: "South America (Sao Paulo) Region", code: "sa-east-1" },
19
+ ]
20
+ end
21
+
22
+ def default_region_code
23
+ "us-east-1"
24
+ end
25
+ end
@@ -0,0 +1,12 @@
1
+ # Copyright (c) 2012-2013 Stark & Wayne, LLC
2
+
3
+ module Inception; module Providers; module Constants; end; end; end
4
+
5
+ module Inception::Providers::Constants::OpenStackConstants
6
+ extend self
7
+
8
+ # explicit value representing "no region requested"
9
+ def no_region_code
10
+ "no-region-requested"
11
+ end
12
+ end
@@ -0,0 +1,28 @@
1
+ # Copyright (c) 2012-2013 Stark & Wayne, LLC
2
+
3
+ module Inception; end
4
+
5
+ module Inception::Providers
6
+ extend self
7
+
8
+ # returns a BOSH provider (CPI) specific object
9
+ # with helpers related to that provider
10
+ # returns nil if +provider_name+ is unknown
11
+ def provider_client(attributes)
12
+ attributes = attributes.is_a?(Hash) ? ReadWriteSettings.new(attributes) : attributes
13
+ case attributes.name.to_sym
14
+ when :aws
15
+ @aws_provider_client ||= begin
16
+ require "inception/providers/clients/aws_provider_client"
17
+ Inception::Providers::Clients::AwsProviderClient.new(attributes)
18
+ end
19
+ when :openstack
20
+ @openstack_provider_client ||= begin
21
+ require "inception/providers/clients/openstack_provider_client"
22
+ Inception::Providers::Clients::OpenStackProviderClient.new(attributes)
23
+ end
24
+ else
25
+ nil
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module Inception
2
+ VERSION = "0.2.1"
3
+ end
data/lib/inception.rb ADDED
@@ -0,0 +1,9 @@
1
+ require "inception/version"
2
+
3
+ module Inception
4
+ end
5
+
6
+ require "inception/providers"
7
+ require "inception/inception_server"
8
+ require "inception/inception_server_cookbook"
9
+ require "inception/next_deploy_actions"
data/nodes/.gitkeep ADDED
File without changes
File without changes
@@ -0,0 +1,5 @@
1
+ [user]
2
+ name = Dr Nic Williams
3
+ email = drnicwilliams@gmail.com
4
+ [github]
5
+ user = drnic
@@ -0,0 +1,14 @@
1
+ ---
2
+ provider:
3
+ name: aws
4
+ region: us-west-2
5
+ credentials:
6
+ aws_access_key_id: MOCK_AWS_ACCESS_KEY_ID
7
+ aws_secret_access_key: MOCK_AWS_SECRET_ACCESS_KEY
8
+ inception:
9
+ ip_address: 54.214.15.178
10
+ key_pair:
11
+ name: inception
12
+ private_key: private_key
13
+ extensions:
14
+ - mosh
@@ -0,0 +1,31 @@
1
+ ---
2
+ provider:
3
+ name: aws
4
+ region: us-west-2
5
+ credentials:
6
+ aws_access_key_id: MOCK_AWS_ACCESS_KEY_ID
7
+ aws_secret_access_key: MOCK_AWS_SECRET_ACCESS_KEY
8
+ git:
9
+ name: Dr Nic Williams
10
+ email: drnicwilliams@gmail.com
11
+ inception:
12
+ key_pair:
13
+ name: inception
14
+ private_key: private_key
15
+ extensions:
16
+ - mosh
17
+ size: m1.small
18
+ disk_size: 16
19
+ provisioned:
20
+ ip_address: 54.214.15.178
21
+ image_id: ami-123456
22
+ server_id: i-e7f005d2
23
+ security_groups:
24
+ - ssh
25
+ - mosh
26
+ username: vcap
27
+ disk_device:
28
+ volume_id: vol-123456
29
+ external: /dev/sdf
30
+ internal: /dev/xvdf
31
+ host: ec2-54-214-15-178.us-west-2.compute.amazonaws.com
File without changes
@@ -0,0 +1,38 @@
1
+ require File.expand_path("../../../support/aws/aws_helpers", __FILE__)
2
+
3
+ describe "AWS deployment without Chef run" do
4
+ include FileUtils
5
+ include AwsHelpers
6
+
7
+ if AwsHelpers.aws_credentials?
8
+ before do
9
+ prepare_aws("basic", aws_region, "next_deploy_actions.no_converge" => true)
10
+ end
11
+ after(:all) do
12
+ destroy_test_constructs unless keep_after_test?
13
+ end
14
+
15
+ def aws_region
16
+ ENV['AWS_REGION'] || "us-west-2"
17
+ end
18
+
19
+ it "creates an EC2 inception/microbosh with the associated resources" do
20
+ create_manifest
21
+
22
+ manifest_file = home_file(".inception_server", "settings.yml")
23
+ File.should be_exists(manifest_file)
24
+
25
+ cmd.deploy
26
+
27
+ inception_servers = fog.servers.select { |s| s.tags["Name"] == test_server_name && s.ready? }
28
+ inception_servers.size.should == 1
29
+
30
+ server = inception_servers.first
31
+ server.volumes.size.should == 2
32
+ named_volume = server.volumes.select { |s| s.tags["Name"] == test_server_name }
33
+ named_volume.should_not be_nil
34
+ end
35
+ else
36
+ it "no AWS integration specs run; missing $AWS_ACCESS_KEY_ID etc"
37
+ end
38
+ end
@@ -0,0 +1,50 @@
1
+ # Copyright (c) 2012-2013 Stark & Wayne, LLC
2
+
3
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
4
+
5
+ require "rubygems"
6
+ require "bundler"
7
+ Bundler.setup(:default, :test)
8
+
9
+ $:.unshift(File.expand_path("../../lib", __FILE__))
10
+
11
+ require "rspec/core"
12
+ require "inception/providers"
13
+ require "inception"
14
+ require "inception/cli"
15
+
16
+ # for the #sh helper
17
+ require "rake"
18
+ require "rake/file_utils"
19
+
20
+ # load all files in spec/support/* (but not lower down)
21
+ Dir[File.dirname(__FILE__) + '/support/*'].each do |path|
22
+ require path unless File.directory?(path)
23
+ end
24
+
25
+ def spec_asset(filename)
26
+ File.expand_path("../assets/#{filename}", __FILE__)
27
+ end
28
+
29
+ def setup_home_dir
30
+ home_dir = File.expand_path("../../tmp/home", __FILE__)
31
+ FileUtils.rm_rf(home_dir)
32
+ FileUtils.mkdir_p(home_dir)
33
+ ENV['HOME'] = home_dir
34
+ FileUtils.cp_r(spec_asset("gitconfig"), home_file(".gitconfig"))
35
+ end
36
+
37
+ # returns the file path to a file
38
+ # in the fake $HOME folder
39
+ def home_file(*path)
40
+ File.join(ENV['HOME'], *path)
41
+ end
42
+
43
+ RSpec.configure do |c|
44
+ c.before do
45
+ setup_home_dir
46
+ Fog::Mock.reset
47
+ end
48
+
49
+ c.color_enabled = true
50
+ end
@@ -0,0 +1,73 @@
1
+ require "active_support/core_ext/hash/keys"
2
+ module AwsHelpers
3
+ extend self
4
+ include SettingsHelper
5
+
6
+ def keep_after_test?
7
+ ENV['KEEP_AFTER_TEST']
8
+ end
9
+
10
+ def region
11
+ @region ||= "us-west-2"
12
+ end
13
+
14
+ def fog
15
+ @fog ||= Fog::Compute.new(fog_credentials.merge(:region => region))
16
+ end
17
+
18
+ def aws_credentials?
19
+ access_key = ENV['AWS_ACCESS_KEY_ID']
20
+ secret_key = ENV["AWS_SECRET_ACCESS_KEY"]
21
+ access_key && secret_key
22
+ end
23
+
24
+ def fog_credentials
25
+ @fog_credentials ||= begin
26
+ access_key = ENV['AWS_ACCESS_KEY_ID']
27
+ secret_key = ENV["AWS_SECRET_ACCESS_KEY"]
28
+ unless access_key && secret_key
29
+ raise "Please provided $AWS_ACCESS_KEY_ID and $AWS_SECRET_ACCESS_KEY"
30
+ end
31
+ credentials = {
32
+ :provider => 'AWS',
33
+ :aws_access_key_id => access_key,
34
+ :aws_secret_access_key => secret_key
35
+ }
36
+ end
37
+ end
38
+
39
+ def prepare_aws(spec_name, aws_region, options={})
40
+ setup_home_dir
41
+ @cmd = nil
42
+ @fog = nil
43
+ create_manifest(options)
44
+ destroy_test_constructs
45
+ end
46
+
47
+ def unique_number
48
+ ENV['UNIQUE_NUMBER'] || Random.rand(100000)
49
+ end
50
+
51
+ def test_server_name
52
+ "test-inception"
53
+ end
54
+
55
+ def create_manifest(options = {})
56
+ credentials = options.delete(:credentials) || fog_credentials
57
+ setting "provider.name", "aws"
58
+ setting "provider.credentials", credentials.stringify_keys
59
+ setting "provider.region", region
60
+ setting "inception.name", test_server_name
61
+ options.each { |key, value| setting(key, value) }
62
+ cmd.save_settings!
63
+ end
64
+
65
+ def destroy_test_constructs
66
+ puts "Destroying everything created by previous test... "
67
+ # destroy servers using inception-vm SG
68
+ provider.delete_servers_with_name(test_server_name)
69
+ provider.delete_volumes_with_name(test_server_name)
70
+ provider.delete_key_pair_if_exists(test_server_name)
71
+ provider.cleanup_unused_ip_addresses
72
+ end
73
+ end
@@ -0,0 +1,20 @@
1
+ # assumes @cmd is Inception::Cli instance
2
+ module SettingsHelper
3
+ def cmd
4
+ @cmd ||= Inception::Cli.new
5
+ end
6
+
7
+ def provider
8
+ cmd.provider_client
9
+ end
10
+
11
+ # Set a nested setting with "key1.key2.key3" notation
12
+ def setting(nested_key, value)
13
+ settings.set(nested_key, value)
14
+ end
15
+
16
+ # used by +SettingsSetter+ to access the settings
17
+ def settings
18
+ cmd.settings
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ module StdoutCapture
2
+ # Captures stdout within the block
3
+ # Usage:
4
+ #
5
+ # out = capture_stdout do
6
+ # puts "this will not be shown"
7
+ # end
8
+ # out.should == "this will not be shown"
9
+ def capture_stdout(&block)
10
+ out = StringIO.new
11
+ $stdout = out
12
+ yield
13
+ return out
14
+ ensure
15
+ $stdout = STDOUT
16
+ end
17
+ end
File without changes
@@ -0,0 +1,39 @@
1
+ require File.expand_path("../../support/aws/aws_helpers", __FILE__)
2
+
3
+ require "fog"
4
+
5
+ describe "AWS deployment deletion" do
6
+ include FileUtils
7
+ include StdoutCapture
8
+ include SettingsHelper
9
+ include AwsHelpers
10
+
11
+ before do
12
+ setup_home_dir
13
+ Fog.mock!
14
+ @cmd = Inception::Cli.new
15
+ setting "provider.name", "aws"
16
+ setting "provider.credentials.aws_access_key_id", "aws_access_key_id"
17
+ setting "provider.credentials.aws_secret_access_key", "aws_secret_access_key"
18
+ setting "provider.region", "us-west-2"
19
+ setting "next_deploy_actions.no_converge", true
20
+ capture_stdout { @cmd.deploy }
21
+ end
22
+
23
+ def perform_delete
24
+ config = { shell: Thor::Base.shell.new }
25
+ capture_stdout { @cmd.class.send(:dispatch, :delete, [], {:"non-interactive" => true}, config) }
26
+ end
27
+
28
+ it "clears out settings.yml" do
29
+ perform_delete
30
+ settings = ReadWriteSettings.new(File.expand_path("~/.inception_server/settings.yml"))
31
+ settings.exists?("provider").should_not be_nil
32
+ settings.exists?("git").should_not be_nil
33
+ settings.exists?("inception.provisioned.disk_device").should be_nil
34
+ settings.exists?("inception.provisioned.host").should be_nil
35
+ settings.exists?("inception.provisioned.ip_address").should be_nil
36
+ settings.exists?("inception.key_pair").should be_nil
37
+ settings.exists?("inception.provisioned.disk_device").should be_nil
38
+ end
39
+ end