mccloud 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,5 +1,9 @@
1
- Mccloudfile
2
- .mccloud
3
- *.pp
4
- puppet/*
5
- chef/*
1
+ /Mccloudfile
2
+ /.mccloud
3
+ /*.pp
4
+ /puppet/*
5
+ /chef/*
6
+ /.fog
7
+ /bootstrap*
8
+ Mccloudfile.*
9
+ pkg/*
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mccloud (0.0.2)
4
+ mccloud (0.0.3)
5
5
  cucumber (= 0.8.5)
6
6
  fog
7
7
  highline (~> 1.6.1)
@@ -18,100 +18,109 @@ class MccloudCLI < Thor
18
18
 
19
19
  end
20
20
 
21
- desc "init", "creates a Mccloud Config File"
21
+ desc "init", "Creates a Mccloud Config File"
22
22
  method_options :force => :boolean
23
23
  def init(amiId=nil)
24
24
  Mccloud::Command.init(amiId,options)
25
25
  end
26
26
 
27
- desc "up", "bring a machine up"
27
+ desc "up [NAME]", "Fires up a machine, bootstrap and provision"
28
28
  method_options :force => :boolean
29
29
  def up(selection=nil)
30
30
  create_session
31
31
  @session.up(selection,options)
32
32
  end
33
33
 
34
- desc "status", "show a status of all machines that are configured"
34
+ desc "status", "Show a status of all machines that are configured"
35
35
  method_options :verbose => false
36
36
  def status(selection=nil)
37
37
  create_session
38
38
  @session.status(selection,options)
39
39
  end
40
40
 
41
- desc "halt [NAME]", "shutdown the machine"
41
+ desc "halt [NAME]", "Shutdown the machine"
42
42
  method_options :force => :boolean
43
43
  def halt(selection=nil)
44
44
  create_session
45
45
  @session.halt(selection,options)
46
46
  end
47
47
 
48
- desc "ssh [NAME]", "spawns an ssh to the machine"
48
+ desc "ssh [NAME]", "Spawns an ssh client to the machine"
49
49
  method_options :screen => :boolean
50
50
  def ssh(selection=nil,command=nil)
51
51
  create_session
52
52
  @session.ssh(selection,command,options)
53
53
  end
54
54
 
55
- desc "suspend", "freeze"
55
+ desc "suspend [NAME]", "Shutdown of the machine"
56
56
  method_options :force => :boolean
57
57
  def suspend(selection=nil)
58
58
  create_session
59
59
  @session.suspend(selection,options)
60
60
  end
61
61
 
62
- desc "boot", "freeze"
63
- method_options :force => :boolean
64
- def boot(selection=nil)
65
- create_session
66
- @session.boot(selection,options)
67
- end
62
+ # desc "boot", "same a"
63
+ # method_options :force => :boolean
64
+ # def boot(selection=nil)
65
+ # create_session
66
+ # @session.boot(selection,options)
67
+ # end
68
68
 
69
- desc "destroy [NAME]", "destroys the machine"
69
+ desc "destroy [NAME]", "Destroys the machine"
70
70
  method_options :force => :boolean
71
71
  def destroy(selection=nil)
72
72
  create_session
73
73
  @session.destroy(selection,options)
74
74
  end
75
75
 
76
- desc "reload [NAME]", "reloads the machine"
76
+ desc "reload [NAME]", "Reboots the machine"
77
77
  method_options :force => :boolean
78
78
  def reload(selection=nil?)
79
79
  create_session
80
80
  @session.reload(selection,options)
81
81
  end
82
82
 
83
- desc "command [NAME] [COMMAND]", "exec a command on a box"
84
- method_options :parallel => :boolean
85
- def command(selection=nil,command="who am i")
86
- create_session
87
- @session.command(selection,command,options)
88
- end
83
+ # desc "command [NAME] [COMMAND]", "exec a command on a box"
84
+ # method_options :parallel => :boolean
85
+ # def command(selection=nil,command="who am i")
86
+ # create_session
87
+ # @session.command(selection,command,options)
88
+ # end
89
89
 
90
- desc "bootstrap [NAME]", "exec a command on a box"
90
+ desc "bootstrap [NAME]", "Executes the bootstrap sequence"
91
91
  method_options :sudo => :boolean
92
92
  def bootstrap(selection=nil,script="who am i")
93
93
  create_session
94
94
  @session.bootstrap(selection,script,options)
95
95
  end
96
96
 
97
- desc "multi","multi"
98
- method_options :verbose => :boolean
99
- def multi(selection=nil,command="who am i")
100
- create_session
101
- @session.multi(selection,command,options)
102
- end
97
+ # desc "multi","multi"
98
+ # method_options :verbose => :boolean
99
+ # def multi(selection=nil,command="who am i")
100
+ # create_session
101
+ # @session.multi(selection,command,options)
102
+ # end
103
103
 
104
- desc "provision", "provision the machine"
104
+ desc "provision [NAME]", "Runs the provisioner the machine"
105
105
  def provision(selection=nil)
106
106
  create_session
107
107
  @session.provision(selection,options)
108
108
  end
109
109
 
110
- desc "server", "runs a server+ forwards"
110
+ desc "server", "Runs a server+ forwards network ports"
111
111
  def server(selection=nil)
112
112
  create_session
113
113
  @session.server(selection,options)
114
114
  end
115
115
  end
116
116
 
117
- MccloudCLI.start
117
+ puts
118
+ 80.times { |i| printf "*" } ; puts
119
+ myversion="* Mccloud v#{Mccloud::VERSION} - alpha - use at your own risk"
120
+ puts "#{myversion}"
121
+ 80.times { |i| printf "*" } ; puts
122
+ puts
123
+
124
+
125
+ MccloudCLI.start
126
+ puts
@@ -25,7 +25,7 @@ module Mccloud
25
25
  #options={ :port => 22, :keys => [ vm.key ], :paranoid => false, :keys_only => true}
26
26
  #Mccloud::Ssh.execute(instance.public_ip_address,vm.user,options,"sudo /tmp/bootstrap.sh")
27
27
  end
28
- multi(selection,"sudo /tmp/bootstrap.sh",options)
28
+ multi(selection,"sudo /tmp/bootstrap.sh",options.merge({ "sudo" => true}))
29
29
  end
30
30
  end
31
31
  end
@@ -4,14 +4,14 @@ module Mccloud
4
4
  module Command
5
5
  def destroy(selection=nil,options=nil)
6
6
  on_selected_machines(selection) do |id,vm|
7
- unless vm.instance.state == "shutting-down" || vm.instance.state =="terminated"
8
- puts "Destroying #{vm.name} with id - #{id}"
7
+ unless vm.instance.nil? || vm.instance.state == "shutting-down" || vm.instance.state =="terminated"
8
+ puts "Destroying machine #{vm.name} (#{id})"
9
9
  vm.instance.destroy
10
10
 
11
11
  vm.instance.wait_for { print "."; STDOUT.flush; state=="terminated"}
12
12
  puts
13
13
  else
14
- puts "Server #{vm.name} - Id: #{id} has state #{vm.instance.state} so not destroying it "
14
+ puts "Machine #{vm.name} is already terminated"
15
15
  end
16
16
  end
17
17
  end
@@ -1,9 +1,509 @@
1
1
  require 'mccloud/generators'
2
+ require 'highline/import'
3
+ require 'mccloud/util/sshkey'
4
+
5
+ require 'erb'
2
6
 
3
7
  module Mccloud
4
8
  module Command
5
- def self.init(amiId=nil,options=nil)
6
- Mccloud::Generators.run_cli Dir.pwd, File.basename(__FILE__), Mccloud::VERSION, ARGV
9
+ include Mccloud::Util
10
+ def self.init(amiId=nil,options=nil)
11
+
12
+ trap("INT") { puts
13
+ puts ""; exit }
14
+
15
+ init_options=ARGV
16
+
17
+ puts "Welcome to the Mccloud configurator: "
18
+ init_options<< "--mcPrefix"
19
+ init_options<< "mccloud"
20
+
21
+ init_options<< "--providerId"
22
+ init_options<< "AWS"
23
+
24
+ create_fog('AWS')
25
+
26
+ template=ERB.new File.new("lib/mccloud/templates/Mccloudfile.erb").read,nil,"%"
27
+ mcPrefix="mccloud"
28
+ providerId="AWS"
29
+ mcEnvironment=select_environment
30
+ mcIdentity=select_identity
31
+
32
+ serverName=select_servername
33
+
34
+ #strip all
35
+ serverName.gsub!(/[^[:alnum:]]/, '_')
36
+
37
+ image_selection=select_image
38
+ imageId=image_selection['imageId']
39
+ userName=image_selection['userName']
40
+ imageDescription=image_selection['imageDescription']
41
+ arch=image_selection['arch']
42
+
43
+ full_bootstrapScript=image_selection['bootstrap']
44
+ copy_bootstrap(full_bootstrapScript)
45
+ bootstrapScript=File.basename("#{full_bootstrapScript}")
46
+
47
+ availabilityZone=select_zone
48
+ flavorId=select_flavor(arch)
49
+
50
+ fullIdentity=Array.new
51
+ if !mcPrefix.nil?
52
+ fullIdentity << mcPrefix
53
+ end
54
+ if mcEnvironment!=""
55
+ fullIdentity << mcEnvironment
56
+ end
57
+ if mcIdentity!=""
58
+ fullIdentity << mcIdentity
59
+ end
60
+ full_identity=fullIdentity.join("-")
61
+
62
+ securityGroup=select_security_group(full_identity)
63
+
64
+ keypair_selection=select_keypair
65
+ keyName=keypair_selection['keyName']
66
+ privateKeyPath=keypair_selection['privateKeyPath']
67
+ publicKeyPath=keypair_selection['publicKeyPath']
68
+
69
+ confirmed=false
70
+ content=template.result(binding)
71
+ if File.exists?("Mccloudfile")
72
+ confirmed=agree("\nDo you want to overwrite your existing config?: ") { |q| q.default="no"}
73
+ else
74
+ confirmed=true
75
+ end
76
+ if confirmed
77
+ puts
78
+ puts "Writing your config file Mccloudfile"
79
+ mccloudfile=File.new("Mccloudfile","w")
80
+ mccloudfile.puts(content)
81
+ mccloudfile.close
82
+ else
83
+ puts "Ok did not overwrite the config, moving along"
84
+ end
85
+
86
+
87
+ #Mccloud::Generators.run_cli Dir.pwd, File.basename(__FILE__), Mccloud::VERSION, init_options
88
+ end
89
+
90
+ private
91
+
92
+ def self.copy_bootstrap(filename=nil)
93
+
94
+ unless filename.nil?
95
+
96
+ FileUtils.cp(filename,File.basename(filename))
97
+ puts "Copied bootstrap - #{File.basename(filename)} to your current directory"
98
+ end
99
+ end
100
+
101
+ def self.generate_key(comment=nil)
102
+ keyset=SSHKey.generate(:comment => comment)
103
+ return keyset
104
+ end
105
+ def self.select_image()
106
+
107
+ # Canonical
108
+ # http://uec-images.ubuntu.com/releases/10.04/release/
109
+ # http://jonathanhui.com/create-and-launch-amazon-ec2-instance-ubuntu-and-centos
110
+
111
+ suggestions=[
112
+ { "Name" => "Ubuntu 10.10 - Maverick 64-bit (Canonical/EBS)", "ImageId" => "ami-cef405a7",
113
+ "UserName" => "ubuntu" ,"Arch" => "64", "Bootstraps" =>
114
+ [ {"Description" => "Ruby via standard .deb packages + rubygems from source + (chef,puppet) as gems", "Filename" => "bootstrap-ubuntu-system.sh"},
115
+ {"Description" => "Ruby 1.8.7 via rvm + (chef,puppet) as gems", "Filename" => "bootstrap-ubuntu-rvm-1.8.7.sh"},
116
+ {"Description" => "Empty bootstrap you can customize", "Filename" => "bootstrap-custom.sh"},
117
+ ]
118
+ },
119
+ { "Name" => "Ubuntu 10.10 - Maverick 32-bit (Canonical/EBS)", "ImageId" => "ami-ccf405a5",
120
+ "UserName" => "ubuntu" ,"Arch" => "32", "Bootstraps" =>
121
+ [ {"Description" => "Ruby via standard .deb packages + rubygems from source + (chef,puppet) as gems", "Filename" => "bootstrap-ubuntu-system.sh"},
122
+ {"Description" => "Ruby 1.8.7 via rvm + (chef,puppet) as gems", "Filename" => "bootstrap-ubuntu-rvm-1.8.7.sh"},
123
+ {"Description" => "Empty bootstrap you can customize", "Filename" => "bootstrap-custom.sh"},
124
+
125
+ ]},
126
+ { "Name" => "Ubuntu 10.04 - Lucid 64-bit (Canonical/EBS)", "ImageId" => "ami-3202f25b",
127
+ "UserName" => "ubuntu" ,"Arch" => "64", "Bootstraps" =>
128
+ [ {"Description" => "Ruby via standard .deb packages + rubygems from source + (chef,puppet) as gems", "Filename" => "bootstrap-ubuntu-system.sh"},
129
+ {"Description" => "Ruby 1.8.7 via rvm + (chef,puppet) as gems", "Filename" => "bootstrap-ubuntu-rvm-1.8.7.sh"},
130
+ {"Description" => "Empty bootstrap you can customize", "Filename" => "bootstrap-custom.sh"},
131
+
132
+ ]},
133
+ { "Name" => "Ubuntu 10.04 - Lucid 32-bit (Canonical/EBS)", "ImageId" => "ami-3e02f257",
134
+ "UserName" => "ubuntu" ,"Arch" => "32", "Bootstraps" =>
135
+ [ {"Description" => "Ruby via standard .deb packages + rubygems from source + (chef,puppet) as gems", "Filename" => "bootstrap-ubuntu-system.sh"},
136
+ {"Description" => "Ruby 1.8.7 via rvm + (chef,puppet) as gems", "Filename" => "bootstrap-ubuntu-rvm-1.8.7.sh"},
137
+ {"Description" => "Empty bootstrap you can customize", "Filename" => "bootstrap-custom.sh"},
138
+
139
+ ]},
140
+ { "Name" => "Centos 5.4 - 64-bit (Rightscale/EBS)", "ImageId" => "ami-4d42a924",
141
+ "UserName" => "root" ,"Arch" => "64", "Bootstraps" =>
142
+ [ {"Description" => "Ruby 1.8.7 from source + (chef,puppet) as gems", "Filename" => "bootstrap-centos-rubysource-1.8.7.sh"},
143
+ {"Description" => "Ruby 1.8.7 via rvm + (chef,puppet) as gems", "Filename" => "bootstrap-centos-rvm-1.8.7.sh"},
144
+ {"Description" => "Ruby REE 1.8.7 via rvm + (chef,puppet) as gems", "Filename" => "bootstrap-centos-rvm-ree-1.8.7.sh"},
145
+
146
+ {"Description" => "Ruby 1.9.2 via rvm + (chef,puppet) as gems", "Filename" => "bootstrap-centos-rvm-1.9.2.sh"},
147
+ {"Description" => "Empty bootstrap you can customize", "Filename" => "bootstrap-custom.sh"},
148
+
149
+ ]},
150
+ { "Name" => "Centos 5.4 - 32-bit (Rightscale/EBS)", "ImageId" => "ami-2342a94a",
151
+ "UserName" => "root" ,"Arch" => "32", "Bootstraps" =>
152
+ [ {"Description" => "Ruby 1.8.7 from source + (chef,puppet) as gems", "Filename" => "bootstrap-centos-rubysource-1.8.7.sh"},
153
+ {"Description" => "Ruby 1.8.7 via rvm + (chef,puppet) as gems", "Filename" => "bootstrap-centos-rvm-1.8.7.sh"},
154
+ {"Description" => "Ruby REE 1.8.7 via rvm + (chef,puppet) as gems", "Filename" => "bootstrap-centos-rvm-ree-1.8.7.sh"},
155
+
156
+ {"Description" => "Ruby 1.9.2 via rvm + (chef,puppet) as gems", "Filename" => "bootstrap-centos-rvm-1.9.2.sh"},
157
+ {"Description" => "Empty bootstrap you can customize", "Filename" => "bootstrap-custom.sh"},
158
+
159
+ ]},
160
+
161
+ ]
162
+
163
+ imageId=""
164
+ userName="root"
165
+ imageDescription=""
166
+ arch="0"
167
+ bootstrap=""
168
+
169
+ choose do |menu|
170
+ menu.index_suffix =") "
171
+ menu.header="\nSuggested image Ids"
172
+ menu.default="1"
173
+ menu.prompt="\nSelect the Image Id (aka AMI-ID on EC2): |1| "
174
+ suggestions.each do |suggestion|
175
+ menu.choice "#{suggestion['Name']} - #{suggestion['ImageId']}" do
176
+ imageId=suggestion['ImageId']
177
+ userName=suggestion['UserName']
178
+ imageDescription=suggestion['Name']
179
+ arch=suggestion['Arch']
180
+
181
+ choose do |bootstrap_menu|
182
+ bootstrap_menu.index_suffix =") "
183
+ bootstrap_menu.header="\nSuggested bootstraps"
184
+ bootstrap_menu.default="1"
185
+ bootstrap_menu.prompt="\nSelect the Image Id (aka AMI-ID on EC2): |1| "
186
+ suggestion["Bootstraps"].each do |bootstrap_file|
187
+ bootstrap_menu.choice "#{bootstrap_file['Description']}" do
188
+ bootstrap=File.expand_path(File.join(File.dirname(__FILE__),'..','templates',"#{bootstrap_file["Filename"]}"))
189
+ end
190
+ end
191
+ end
192
+
193
+ end
194
+ end
195
+ menu.choice "Specify your own:" do
196
+ imageId=ask("Image Id: ")
197
+ userName=ask("Username to login: ")
198
+ imageDescription=ask("Description: ")
199
+ arch=ask("Architecture (32,64): "){|q| q.default="64"}
200
+ bootstrap=ask("Path to Bootstrap script: ")
201
+ end
202
+
203
+ end
204
+
205
+ return { "imageId"=>imageId,"userName" =>userName,"imageDescription" => imageDescription,"arch" => arch,"bootstrap" => bootstrap}
206
+
207
+ end
208
+
209
+ def self.select_identity()
210
+
211
+ puts "If you share the same cloud provider account, you can specify an identity"
212
+ puts "to uniquely identify *your* servers (ex. firstname.lastname)"
213
+ puts "Leave blank if you want to work in a team "
214
+ puts ""
215
+ mcIdentity=ask("Identity: ") {|q| q.default="#{ENV['USER']}"}
216
+ puts
217
+ return mcIdentity
218
+
219
+ end
220
+
221
+ def self.select_servername()
222
+
223
+ puts "Provide an short name to identify your server (ex. web,db) "
224
+ mcIdentity=ask("Servername: ") { |q| q.default="web"}
225
+ puts
226
+ return mcIdentity
227
+
228
+ end
229
+
230
+ def self.select_environment()
231
+
232
+ puts "Provide a name for the environment your are using (ex. development, test, demo)"
233
+ mcEnvironment=ask("Environment: "){|q| q.default="development"}
234
+ puts
235
+ return mcEnvironment
236
+
237
+ end
238
+
239
+
240
+ def self.select_flavor(filter=nil)
241
+ flavorId="t1.micro"
242
+ choose do |menu|
243
+ menu.index_suffix =") "
244
+ menu.header="\nAvailable machine flavors"
245
+ menu.default="1"
246
+ menu.prompt="\nSelect the flavor for your machine: |1| "
247
+ @provider.flavors.each do |flavor|
248
+ if "#{flavor.bits}"==filter || "#{flavor.bits}"=="0"
249
+ menu.choice "#{flavor.name} - #{flavor.id} - #{flavor.cores} cores" do
250
+ flavorId=flavor.id
251
+ end
252
+ end
253
+ end
254
+ end
255
+ return flavorId
256
+
257
+ end
258
+
259
+ def self.select_security_group(identity=nil)
260
+
261
+ securityGroup="default"
262
+ choose do |menu|
263
+ menu.index_suffix =") "
264
+ menu.header="\nAvailable security groups"
265
+ menu.default="1"
266
+ menu.prompt="\nSelect the security group for your machine: |1| "
267
+
268
+ mcgroup=@provider.security_groups.get("#{identity}-securitygroup")
269
+ if mcgroup.nil?
270
+ menu.choice "[Create new] #{identity}-securitygroup" do
271
+ sg=@provider.security_groups.new
272
+ sg.name="#{identity}-securitygroup"
273
+ sg.description="#{identity}-securitygroup"
274
+ sg.save
275
+
276
+ puts "Authorizing access to port 22"
277
+ sg.authorize_port_range(22..22)
278
+
279
+ securityGroup="#{identity}-securitygroup"
280
+ end
281
+ else
282
+ menu.choice "#{identity}-securitygroup" do
283
+ securityGroup="#{identity}-securitygroup"
284
+ end
285
+ end
286
+
287
+ @provider.security_groups.each do |group|
288
+ unless "#{group.name}"=="#{identity}-securitygroup"
289
+ menu.choice "#{group.name} - #{group.description}" do
290
+ puts "Make sure this security group has ssh/port 22 enabled\n"
291
+ securityGroup=group.name
292
+ end
293
+ end
294
+ end
295
+ end
296
+
297
+ # We should check to see if 22 is enabled for that zone
298
+ #(AWS.security_groups.get("JMETER").ip_permissions[0]["fromPort"]..AWS.security_groups.get("JMETER").ip_permissions[0]["toPort"]) === 22
299
+ # make sure port 22 is open in the first security group
300
+ # security_group = connection.security_groups.get(server.groups.first)
301
+ # authorized = security_group.ip_permissions.detect do |ip_permission|
302
+ # ip_permission['ipRanges'].first && ip_permission['ipRanges'].first['cidrIp'] == '0.0.0.0/0' &&
303
+ # ip_permission['fromPort'] == 22 &&
304
+ # ip_permission['ipProtocol'] == 'tcp' &&
305
+ # ip_permission['toPort'] == 22
306
+ # end
307
+ # unless authorized
308
+ # security_group.authorize_port_range(22..22)
309
+ # end
310
+ return securityGroup
311
+
312
+ end
313
+
314
+ def self.select_zone()
315
+
316
+
317
+ zone="default"
318
+
319
+ choose do |menu|
320
+ menu.index_suffix =") "
321
+ menu.header="\nAvailable zones"
322
+ menu.default="us-east-1b"
323
+ menu.prompt="\nSelect the zone for your machine: |#{menu.default}| "
324
+
325
+ @provider.describe_availability_zones.body["availabilityZoneInfo"].each do |region|
326
+ menu.choice "#{region['zoneName']} - #{region['regionName']}" do
327
+ zone=region['zoneName']
328
+ end
329
+ end
330
+
331
+ [ {"zoneName" => "eu-west-1a", "regionName" => "eu-west-1"}, {"zoneName" => "eu-west-1b", "regionName" => "eu-west-1"}].each do |region|
332
+ menu.choice "#{region['zoneName']} - #{region['regionName']}" do
333
+ zone=region['zoneName']
334
+ end
335
+ end
336
+ end
337
+
338
+ return zone
339
+
340
+ end
341
+
342
+ def self.create_fog(provider='AWS')
343
+ begin
344
+ @provider=Fog::Compute.new(:provider => provider)
345
+ rescue ArgumentError => e
346
+ # Missing required arguments:
347
+ required_string=e.message
348
+ required_string["Missing required arguments: "]=""
349
+ required_options=required_string.split(", ")
350
+ puts "Please provide credentials for provider [#{provider}]:"
351
+ answer=Hash.new
352
+ for fog_option in required_options do
353
+ answer["#{fog_option}".to_sym]=ask("- #{fog_option}: ")
354
+ #{ |q| q.validate = /\A\d{5}(?:-?\d{4})?\Z/ }
355
+ end
356
+ puts "\nThe following snippet will be written to #{File.join(ENV['HOME'],".fog")}"
357
+
358
+ snippet=":default:\n"
359
+ for fog_option in required_options do
360
+ snippet=snippet+" :#{fog_option}: #{answer[fog_option.to_sym]}\n"
361
+ end
362
+
363
+ puts "======== snippit start ====="
364
+ puts "#{snippet}"
365
+ puts "======== snippit end ======="
366
+ confirmed=agree("Do you want to save this?: ") {|q| q.default="yes"}
367
+ puts
368
+
369
+ if (confirmed)
370
+ fogfile=File.new("#{File.join(ENV['HOME'],".fog")}","w")
371
+ FileUtils.chmod(0600,fogfile)
372
+ fogfile.puts "#{snippet}"
373
+ fogfile.close
374
+ else
375
+ #puts "Ok, we won't write it, but we continue with your credentials in memory"
376
+ exit -1
377
+ end
378
+ begin
379
+ answer[:provider]= provider
380
+ @provider=Fog::Compute.new(answer)
381
+ rescue
382
+ puts "We tried to create the provider but failed again, sorry we give up"
383
+ exit -1
384
+ end
385
+ end
386
+ end
387
+
388
+ def self.select_keypair()
389
+
390
+
391
+ valid_private_key=false
392
+ valid_public_key=false
393
+ private_key_path=""
394
+ public_key_path=""
395
+
396
+ keyName=nil
397
+ choose do |menu|
398
+ menu.index_suffix =") "
399
+ menu.header="\nAvailable keypairs"
400
+ menu.default="1"
401
+ menu.prompt="\nSelect a keypair: |1| "
402
+
403
+ menu.choice "Use/Generate a new (mccloud) keypair (RSA)" do
404
+
405
+ private_key_path=File.join("#{ENV['HOME']}",".ssh","mccloud_rsa")
406
+ public_key_path=File.join("#{ENV['HOME']}",".ssh","mccloud_rsa.pub")
407
+
408
+ if File.exists?(private_key_path)
409
+ reuse=agree("\nReuse existing (mccloud) keypair?: ") { |q| q.default="yes"}
410
+ else
411
+ reuse=false
412
+ end
413
+
414
+ rsa_key=nil
415
+ unless reuse
416
+ keyName=ask("\nPlease enter a name for your new key: "){|q| q.default="mccloud-key-#{ENV['USER']}"}
417
+ rsa_key=generate_key(keyName)
418
+
419
+ unless File.exists?(File.dirname(public_key_path))
420
+ puts "Creating directory #{File.dirname(public_key_path)}"
421
+ FileUtils.mkdir_p(File.dirname(public_key_path))
422
+ FileUtils.chmod(0700,File.dirname(public_key_path))
423
+ end
424
+
425
+ unless File.exists?(File.dirname(private_key_path))
426
+ puts "Creating directory #{File.dirname(private_key_path)}"
427
+
428
+ FileUtils.mkdir_p(File.dirname(private_key_path))
429
+ FileUtils.chmod(0700,File.dirname(private_key_path))
430
+ end
431
+
432
+
433
+ File.open(public_key_path, 'w') {|f| f.write(rsa_key.ssh_public_key) }
434
+ File.open(private_key_path, 'w') {|f| f.write(rsa_key.rsa_private_key) }
435
+ FileUtils.chmod(0600,private_key_path)
436
+ FileUtils.chmod(0600,public_key_path)
437
+
438
+ puts
439
+ puts "Created a new public key in #{public_key_path}"
440
+ puts "Created a new private key in #{private_key_path}"
441
+ puts "I suggest you backup these later."
442
+ puts
443
+
444
+ provider_keypair=@provider.key_pairs.get(keyName)
445
+ unless (provider_keypair.nil?)
446
+ puts "Updating your existing key #{keyName} with cloud provider"
447
+ provider_keypair.destroy()
448
+ end
449
+ provider_keypair=@provider.key_pairs.create(
450
+ :name => keyName,
451
+ :public_key => rsa_key.ssh_public_key )
452
+ puts "Registered #{keyName} with your cloud provider"
453
+
454
+ else
455
+ keyName=ask("\nPlease enter a name for your key: "){|q| q.default="mccloud-key-#{ENV['USER']}"}
456
+ end
457
+
458
+ valid_public_key=true
459
+ valid_private_key=true
460
+ end
461
+
462
+ menu.choice "Provide your own keypair (RSA)" do
463
+ keyName=nil
464
+ end
465
+ @provider.key_pairs.each do |keypair|
466
+ menu.choice "#{keypair.name} - #{keypair.fingerprint}" do
467
+ keyName=keypair.name
468
+ end
469
+ end
470
+ end
471
+
472
+
473
+ if keyName.nil?
474
+ puts "You selected to provide a custom keypair. Note that only RSA keys are supported"
475
+ puts
476
+ keyName=ask("Please enter a name for your custom key: (ex. ec2key-firstname.lastname) "){|q| q.default="mccloud-key-#{ENV['USER']}"}
477
+ else
478
+ valid_public_key=true
479
+ end
480
+
481
+ while (valid_private_key==false) do
482
+ private_key_path=ask("Enter full path to private key: "){|q| q.default="#{File.join(ENV['HOME'],'.ssh','mccloud-id_rsa')}"}
483
+ if File.exists?(private_key_path)
484
+ valid_private_key=true
485
+ else
486
+ puts "#{private_key_path} does not exist"
487
+ end
488
+ end
489
+
490
+ while (valid_public_key==false) do
491
+ public_key_path=ask("Enter full path to public key: "){|q| q.default="#{File.join(ENV['HOME'],'.ssh','mccloud-id_rsa.pub')}"}
492
+ if File.exists?(public_key_path)
493
+ valid_public_key=true
494
+ else
495
+ puts "#{public_key_path} does not exist"
496
+ end
497
+ end
498
+
499
+
500
+ if private_key_path==""
501
+ return {"keyName" => keyName,"privateKeyPath" => private_key_path}
502
+
503
+ else
504
+ return {"keyName" => keyName,"publicKeyPath" => public_key_path,"privateKeyPath" => private_key_path}
505
+ end
506
+ end
507
+
7
508
  end
8
509
  end
9
- end