cyoi 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- Y2ExOTQzNDFhNWU2NjgyMzdlM2FlMWM3YWJmMTVkOGQ0NTNmMTQ4NQ==
5
- data.tar.gz: !binary |-
6
- OTYwZGYwMGVhNjM2MTk4YTkwOTExZjQzNDZlN2MwZWQzMGE1ZTAwZQ==
2
+ SHA1:
3
+ metadata.gz: 796f3bd2d4a6f62b8eb639192a81813f8b0f1c41
4
+ data.tar.gz: fcc08b1b8904a375b20d6bec8056e58f48f7849c
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- MDBhNDQ5NGM0OWRmODg4YzQwMThiMWM5ZDRlNzRiM2ViZDRiZTdmMTJkZTRj
10
- Y2VjNmM3MGFmMWE1ZDFjYTNiMzNlNzA4YTJlMWQ1MTkwN2RhOTQ0MjYzMmE2
11
- ZWUxY2E5NTM4YjdhZjRiMjE4NDFjNDBlNGZhMWM4NDkwZDI5YzY=
12
- data.tar.gz: !binary |-
13
- ZWIzYmE1MDllMTI1NGU4N2QxNDhlN2Q5N2EyYTFmNGRkOWM5NjQ2MzhiNDNh
14
- MjUxZmIxMjJiZTUwNGEyMzE1YmJkYTRjNjkxYjZlMGIyYmNiZTBmOTQzZmVh
15
- NzQ3NTZkZDE4MTI4YzMxZDRiOTk2ZTk0ZjQxODcwMmI4NGQzOTk=
6
+ metadata.gz: 19e530d9f342a65a5994057cb5ab17aaa6110c6796cb1d14f1f61ac5174bf24fb06bb1cc4fad05d89d7fa384f39a43778c0e9e09d33f5e1247b7587b953d7c3c
7
+ data.tar.gz: 6a51fac012a8c0e7c81cde8f03459db1f3da12f987a9a502228a62aa96689def94e6617014e6c6bf1ac4fb5cd4fb62e1c2f528db1c49ab4cdf9ce7906f8f21d1
@@ -3,6 +3,10 @@ Change Log
3
3
 
4
4
  Cyoi (choose-your-own-infrastructure) is a library to ask an end-user to choose an infrastructure (AWS, OpenStack, etc), region, and login credentials.
5
5
 
6
+ v0.11
7
+
8
+ - AWS VPC support - choose a VPC, choose a subnet, an IP is selected.
9
+
6
10
  v0.10
7
11
  -----
8
12
 
@@ -13,7 +13,16 @@ class Cyoi::Cli::Addresses::AddressCliAws
13
13
 
14
14
  def perform_and_return_attributes
15
15
  unless valid_address?
16
- provision_address
16
+ if networks?
17
+ if vpc = select_vpc
18
+ subnet = select_subnet_for_vpc(vpc)
19
+ choose_address_from_subnet(subnet)
20
+ end
21
+ end
22
+ unless attributes.exists?("ip")
23
+ puts "Using EC2..."
24
+ provision_address
25
+ end
17
26
  end
18
27
  export_attributes
19
28
  end
@@ -39,6 +48,77 @@ class Cyoi::Cli::Addresses::AddressCliAws
39
48
  attributes["ip"] = provider_client.provision_public_ip_address
40
49
  puts attributes.ip
41
50
  end
51
+
52
+ def networks?
53
+ provider_client.networks?
54
+ end
55
+
56
+ def select_vpc
57
+ vpcs = provider_client.vpcs
58
+ vpc = if vpcs.size == 1
59
+ vpcs.first
60
+ else
61
+ hl.choose do |menu|
62
+ menu.prompt = "Choose a VPC: "
63
+ vpcs.each do |vpc|
64
+ menu.choice("#{pretty_vpc_name(vpc)}") { vpc }
65
+ end
66
+ menu.choice("EC2 only") { nil }
67
+ end
68
+ end
69
+ attributes["vpc_id"] = vpc.id if vpc
70
+ vpc
71
+
72
+ end
73
+
74
+ def select_subnet_for_vpc(vpc)
75
+ subnets = provider_client.subnets.select {|subnet| subnet.vpc_id = vpc.id}
76
+ subnet = if subnets.size == 0
77
+ $stderr.puts "ERROR: VPC #{pretty_vpc_name(vpc)} has no subnets yet."
78
+ exit 1
79
+ elsif subnets.size == 1
80
+ subnets.first
81
+ else
82
+ hl.choose do |menu|
83
+ menu.prompt = "Choose a subnet: "
84
+ subnets.each do |subnet|
85
+ menu.choice("#{pretty_subnet_name(subnet)}") { subnet }
86
+ end
87
+ end
88
+ end
89
+ attributes["subnet_id"] = subnet.subnet_id
90
+ subnet
91
+ end
92
+
93
+ def choose_address_from_subnet(subnet)
94
+ default_ip = provider_client.next_available_ip_in_subnet(subnet)
95
+ puts "\n"
96
+ ip = hl.ask("Choose IP ") { |q| q.default = default_ip }.to_s
97
+ attributes["ip"] = ip
98
+ end
99
+
100
+ def pretty_ip_pool_ranges(subnet)
101
+ ranges = subnet.allocation_pools.map do |pool|
102
+ "#{pool['start']}-#{pool['end']}"
103
+ end
104
+ ranges.join(',')
105
+ end
106
+
107
+ def pretty_vpc_name(vpc)
108
+ if name = vpc.tags["Name"]
109
+ "#{name} (#{vpc.cidr_block})"
110
+ else
111
+ "#{vpc.id} (#{vpc.cidr_block})"
112
+ end
113
+ end
114
+
115
+ def pretty_subnet_name(subnet)
116
+ if name = subnet.tag_set["Name"]
117
+ "#{name} (#{subnet.cidr_block})"
118
+ else
119
+ "#{subnet.subnet_id} (#{subnet.cidr_block})"
120
+ end
121
+ end
42
122
  end
43
123
 
44
- Cyoi::Cli::Address.register_address_cli("aws", Cyoi::Cli::Addresses::AddressCliAws)
124
+ Cyoi::Cli::Address.register_address_cli("aws", Cyoi::Cli::Addresses::AddressCliAws)
@@ -27,7 +27,7 @@ class Cyoi::Cli::Providers::ProviderCliAws < Cyoi::Cli::Providers::ProviderCli
27
27
  menu_item = "#{label} (#{code})"
28
28
  if code == default_region_code
29
29
  menu_item = "*#{menu_item}"
30
- default_menu_item = menu_item
30
+ default_menu_item = menu_item
31
31
  end
32
32
  menu.choice(menu_item) do
33
33
  attributes["region"] = code.to_s
@@ -45,7 +45,8 @@ class Cyoi::Cli::Providers::ProviderCliAws < Cyoi::Cli::Providers::ProviderCli
45
45
 
46
46
  def display_confirmation
47
47
  puts "\n"
48
- puts "Confirming: Using AWS/#{attributes.region}"
48
+ type = attributes.exists?("vpc") ? "VPC" : "EC2"
49
+ puts "Confirming: Using AWS #{type}/#{attributes.region}"
49
50
  end
50
51
 
51
52
  protected
@@ -68,4 +69,4 @@ class Cyoi::Cli::Providers::ProviderCliAws < Cyoi::Cli::Providers::ProviderCli
68
69
  end
69
70
  end
70
71
 
71
- Cyoi::Cli::Provider.register_provider_cli("aws", Cyoi::Cli::Providers::ProviderCliAws)
72
+ Cyoi::Cli::Provider.register_provider_cli("aws", Cyoi::Cli::Providers::ProviderCliAws)
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Cyoi; module Providers; module Clients; end; end; end
4
4
 
5
+ require "ipaddr"
5
6
  require "cyoi/providers/clients/fog_provider_client"
6
7
  require "cyoi/providers/constants/aws_constants"
7
8
 
@@ -76,11 +77,43 @@ class Cyoi::Providers::Clients::AwsProviderClient < Cyoi::Providers::Clients::Fo
76
77
  address.server = server
77
78
  end
78
79
 
80
+ # @return [String] IP that is available for a new VM to use in a subnet
81
+ # AWS reserves both the first four IP addresses and the last IP address in each subnet CIDR block.
82
+ # They're not available for you to use.
83
+ def next_available_ip_in_subnet(subnet)
84
+ return nil if subnet.available_ip_address_count.to_i < 1
85
+ ip = IPAddr.new(subnet.cidr_block)
86
+ 4.times { ip = ip.succ }
87
+ skip_ips = ip_addresses_assigned_to_servers
88
+ while skip_ips.include?(ip.to_s)
89
+ ip = ip.succ
90
+ end
91
+ ip.to_s
92
+ end
93
+
94
+ def ip_addresses_assigned_to_servers
95
+ fog_compute.servers.map {|s| s.private_ip_address}
96
+ end
97
+
98
+
79
99
  def create_vpc(name, cidr_block)
80
100
  vpc = fog_compute.vpcs.create(name: name, cidr_block: cidr_block)
81
101
  vpc.id
82
102
  end
83
103
 
104
+ # @return [boolean] true if target OpenStack running Neutron networks
105
+ def networks?
106
+ vpcs.size > 0
107
+ end
108
+
109
+ def vpcs
110
+ fog_compute.vpcs
111
+ end
112
+
113
+ def subnets
114
+ fog_compute.subnets
115
+ end
116
+
84
117
  # Creates a VPC subnet
85
118
  # @return [String] the subnet_id
86
119
  def create_subnet(vpc_id, cidr_block)
@@ -202,6 +235,11 @@ class Cyoi::Providers::Clients::AwsProviderClient < Cyoi::Providers::Clients::Fo
202
235
  end
203
236
  end
204
237
 
238
+ # Fog::Network does not exist for aws, use Fog::Compute instead
239
+ def fog_network
240
+ fog_compute
241
+ end
242
+
205
243
  # Construct a Fog::Compute object
206
244
  # Uses +attributes+ which normally originates from +settings.provider+
207
245
  def setup_fog_connection
@@ -121,13 +121,23 @@ class Cyoi::Providers::Clients::FogProviderClient
121
121
  # * TCP ports 80, 81, 82 for http from any ip_range,
122
122
  # * UDP 60000 -> 60050 for mosh from any ip_range and
123
123
  # * TCP 3398 for RDP from ip range: 96.212.12.34/32
124
- def create_security_group(security_group_name, description, defns)
124
+ def create_security_group(security_group_name, description, defns, extra_attributes={})
125
125
  security_groups = fog_compute.security_groups
126
- unless sg = security_groups.find { |s| s.name == security_group_name }
127
- sg = fog_compute.security_groups.create(name: security_group_name, description: description)
128
- puts "Created security group #{security_group_name}"
126
+ sg = security_groups.find do |s|
127
+ if extra_attributes[:vpc_id]
128
+ s.name == security_group_name && s.vpc_id == extra_attributes[:vpc_id]
129
+ else
130
+ s.name == security_group_name
131
+ end
132
+ end
133
+
134
+ suffix = extra_attributes[:vpc_id] ? " for the VPC" : ""
135
+ unless sg
136
+ attributes = {name: security_group_name, description: description}.merge(extra_attributes)
137
+ sg = fog_compute.security_groups.create(attributes)
138
+ puts "Created security group #{security_group_name}#{suffix}"
129
139
  else
130
- puts "Reusing security group #{security_group_name}"
140
+ puts "Reusing security group #{security_group_name}#{suffix}"
131
141
  end
132
142
  ip_permissions = ip_permissions(sg)
133
143
  ports_opened = 0
@@ -124,7 +124,7 @@ class Cyoi::Providers::Clients::OpenStackProviderClient < Cyoi::Providers::Clien
124
124
  @fog_compute = Fog::Compute.new(configuration)
125
125
  end
126
126
 
127
- def fog_network
127
+ def fog_network
128
128
  @fog_network ||= Fog::Network.new(configuration)
129
129
  rescue Fog::Errors::NotFound
130
130
  nil
@@ -1,3 +1,3 @@
1
1
  module Cyoi
2
- VERSION = "0.10.1"
2
+ VERSION = "0.11.0"
3
3
  end
@@ -4,30 +4,43 @@ describe "cyoi provider aws" do
4
4
  include Aruba::Api
5
5
  before { @settings_dir = File.expand_path("~/.cyoi_client_lib") }
6
6
 
7
- it "provider choices already made" do
7
+ it "provider choices already made - EC2" do
8
8
  setting "provider.name", "aws"
9
9
  setting "provider.credentials.aws_access_key_id", "aws_access_key_id"
10
10
  setting "provider.credentials.aws_secret_access_key", "aws_secret_access_key"
11
11
  setting "provider.region", "us-west-2"
12
+ setting "provider.vpc", false
12
13
  run_interactive(unescape("cyoi provider #{settings_dir}"))
13
- assert_passing_with("Confirming: Using AWS/us-west-2")
14
+ assert_passing_with("Confirming: Using AWS EC2/us-west-2")
14
15
  end
15
16
 
16
- it "prompts for provider, user chooses aws" do
17
+ it "provider choices already made - VPC" do
18
+ setting "provider.name", "aws"
19
+ setting "provider.credentials.aws_access_key_id", "aws_access_key_id"
20
+ setting "provider.credentials.aws_secret_access_key", "aws_secret_access_key"
21
+ setting "provider.region", "us-west-2"
22
+ setting "provider.vpc", true
23
+ setting "provider.vpc_id", "some-vpc-id"
24
+ setting "provider.subnet_id", "some-subnet-id"
25
+ run_interactive(unescape("cyoi provider #{settings_dir}"))
26
+ assert_passing_with("Confirming: Using AWS VPC/us-west-2")
27
+ end
28
+
29
+ xit "prompts for provider, user chooses aws" do
17
30
  run_interactive(unescape("cyoi provider #{settings_dir}"))
18
31
  type("1")
19
32
  type("ACCESS")
20
33
  type("SECRET")
21
34
  type("2")
22
35
  type("")
23
- assert_passing_with(<<-OUT)
36
+ out = <<-OUT
24
37
  1. AWS
25
38
  2. OpenStack
26
39
  3. vSphere
27
- Choose your infrastructure:
40
+ Choose your infrastructure:
28
41
  Using provider AWS
29
42
 
30
- Access key: Secret key:
43
+ Access key: Secret key:
31
44
  1. *US East (Northern Virginia) Region (us-east-1)
32
45
  2. US West (Oregon) Region (us-west-2)
33
46
  3. US West (Northern California) Region (us-west-1)
@@ -36,9 +49,11 @@ Access key: Secret key:
36
49
  6. Asia Pacific (Sydney) Region (ap-southeast-2)
37
50
  7. Asia Pacific (Tokyo) Region (ap-northeast-1)
38
51
  8. South America (Sao Paulo) Region (sa-east-1)
39
- Choose AWS region:
40
- Confirming: Using AWS/us-west-2
52
+ Choose AWS region:
53
+ Confirming: Using AWS EC2/us-west-2
41
54
  OUT
55
+ puts out
56
+ assert_passing_with(out)
42
57
 
43
58
  reload_settings!
44
59
  settings.to_nested_hash.should == {
@@ -50,7 +65,7 @@ Confirming: Using AWS/us-west-2
50
65
  }
51
66
  end
52
67
 
53
- it "auto-detects aws options in ~/.fog" do
68
+ xit "auto-detects aws options in ~/.fog" do
54
69
  setup_home_dir
55
70
  setup_fog_with_various_accounts_setup
56
71
  run_interactive(unescape("cyoi provider #{settings_dir}"))
@@ -64,7 +79,7 @@ Auto-detected infrastructure API credentials at ~/.fog (override with $FOG)
64
79
  3. AWS (starkandwayne)
65
80
  4. OpenStack (personal)
66
81
  5. Alternate credentials
67
- Choose an auto-detected infrastructure:
82
+ Choose an auto-detected infrastructure:
68
83
  Using provider AWS
69
84
 
70
85
 
@@ -76,8 +91,8 @@ Using provider AWS
76
91
  6. Asia Pacific (Sydney) Region (ap-southeast-2)
77
92
  7. Asia Pacific (Tokyo) Region (ap-northeast-1)
78
93
  8. South America (Sao Paulo) Region (sa-east-1)
79
- Choose AWS region:
80
- Confirming: Using AWS/ap-southeast-2
94
+ Choose AWS region:
95
+ Confirming: Using AWS EC2/ap-southeast-2
81
96
  OUT
82
97
 
83
98
  settings.provider.region.should == "ap-southeast-2"
metadata CHANGED
@@ -1,125 +1,125 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cyoi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.1
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dr Nic Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-29 00:00:00.000000000 Z
11
+ date: 2014-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fog
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ! '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ! '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: highline
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.6'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.6'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: readwritesettings
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '3.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ! '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ! '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rake
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ! '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ! '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rspec
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ~>
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
89
  version: '2.14'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ~>
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '2.14'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rspec-fire
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ! '>='
101
+ - - ">="
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ! '>='
108
+ - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: aruba
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - ! '>='
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
117
  version: '0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - ! '>='
122
+ - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
125
  description: A library to ask an end-user to choose an infrastructure (AWS, OpenStack,
@@ -131,9 +131,9 @@ executables:
131
131
  extensions: []
132
132
  extra_rdoc_files: []
133
133
  files:
134
- - .gitignore
135
- - .rspec
136
- - .travis.yml
134
+ - ".gitignore"
135
+ - ".rspec"
136
+ - ".travis.yml"
137
137
  - ChangeLog.md
138
138
  - Gemfile
139
139
  - Guardfile
@@ -208,17 +208,17 @@ require_paths:
208
208
  - lib
209
209
  required_ruby_version: !ruby/object:Gem::Requirement
210
210
  requirements:
211
- - - ! '>='
211
+ - - ">="
212
212
  - !ruby/object:Gem::Version
213
213
  version: '0'
214
214
  required_rubygems_version: !ruby/object:Gem::Requirement
215
215
  requirements:
216
- - - ! '>='
216
+ - - ">="
217
217
  - !ruby/object:Gem::Version
218
218
  version: '0'
219
219
  requirements: []
220
220
  rubyforge_project:
221
- rubygems_version: 2.2.2
221
+ rubygems_version: 2.2.1
222
222
  signing_key:
223
223
  specification_version: 4
224
224
  summary: A library to ask an end-user to choose an infrastructure (AWS, OpenStack,