tugboat 0.0.9 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,6 +10,12 @@ module Tugboat
10
10
  exit 1
11
11
  end
12
12
 
13
+ # If the user passes the global `-q/--quiet` flag, redirect
14
+ # stdout
15
+ if env["user_quiet"]
16
+ $stdout = File.new('/dev/null', 'w')
17
+ end
18
+
13
19
  @app.call(env)
14
20
  end
15
21
  end
@@ -26,12 +26,18 @@ module Tugboat
26
26
  droplet_private_networking = env["create_droplet_private_networking"] :
27
27
  droplet_private_networking = env["config"].default_private_networking
28
28
 
29
+ env["create_droplet_backups_enabled"] ?
30
+ droplet_backups_enabled = env["create_droplet_backups_enabled"] :
31
+ droplet_backups_enabled = env["config"].default_backups_enabled
32
+
33
+
29
34
  req = ocean.droplets.create :name => env["create_droplet_name"],
30
35
  :size_id => droplet_size_id,
31
36
  :image_id => droplet_image_id,
32
37
  :region_id => droplet_region_id,
33
38
  :ssh_key_ids => droplet_ssh_key_id,
34
- :private_networking => droplet_private_networking
39
+ :private_networking => droplet_private_networking,
40
+ :backups_enabled => droplet_backups_enabled
35
41
 
36
42
  if req.status == "ERROR"
37
43
  say req.error_message, :red
@@ -0,0 +1,23 @@
1
+ module Tugboat
2
+ module Middleware
3
+ class DestroyImage < Base
4
+ def call(env)
5
+ ocean = env["ocean"]
6
+
7
+ say "Queuing destroy image for #{env["image_id"]} #{env["image_name"]}...", nil, false
8
+
9
+ req = ocean.images.delete env["image_id"]
10
+
11
+ if req.status == "ERROR"
12
+ say "#{req.status}: #{req.error_message}", :red
13
+ exit 1
14
+ end
15
+
16
+ say "done", :green
17
+
18
+ @app.call(env)
19
+ end
20
+ end
21
+ end
22
+ end
23
+
@@ -72,7 +72,7 @@ module Tugboat
72
72
 
73
73
  ocean.droplets.list.droplets.each_with_index do |d, i|
74
74
  # Check to see if one of the droplet names have the fuzzy string.
75
- if d.name.include? user_fuzzy_name
75
+ if d.name.upcase.include? user_fuzzy_name.upcase
76
76
  found_droplets << d
77
77
  end
78
78
  end
@@ -0,0 +1,113 @@
1
+ module Tugboat
2
+ module Middleware
3
+ # Check if the client has set-up configuration yet.
4
+ class FindImage < Base
5
+ def call(env)
6
+ ocean = env["ocean"]
7
+ user_fuzzy_name = env['user_image_fuzzy_name']
8
+ user_image_name = env['user_image_name']
9
+ user_image_id = env['user_image_id']
10
+
11
+ # First, if nothing is provided to us, we should quit and
12
+ # let the user know.
13
+ if !user_fuzzy_name && !user_image_name && !user_image_id
14
+ say "Tugboat attempted to find an image with no arguments. Try `tugboat help`", :red
15
+ exit 1
16
+ end
17
+
18
+ # If you were to `tugboat restart foo -n foo-server-001` then we'd use
19
+ # 'foo-server-001' without looking up the fuzzy name.
20
+ #
21
+ # This is why we check in this order.
22
+
23
+ # Easy for us if they provide an id. Just set it to the image_id
24
+ if user_image_id
25
+ say "Image id provided. Finding Image...", nil, false
26
+ req = ocean.images.show user_image_id
27
+
28
+ if req.status == "ERROR"
29
+ say "#{req.status}: #{req.error_message}", :red
30
+ exit 1
31
+ end
32
+
33
+ env["image_id"] = req.image.id
34
+ env["image_name"] = "(#{req.image.name})"
35
+ end
36
+
37
+ # If they provide a name, we need to get the ID for it.
38
+ # This requires a lookup.
39
+ if user_image_name && !env["image_id"]
40
+ say "Image name provided. Finding image ID...", nil, false
41
+
42
+ # Look for the image by an exact name match.
43
+ ocean.images.list.images.each do |d|
44
+ if d.name == user_image_name
45
+ env["image_id"] = d.id
46
+ env["image_name"] = "(#{d.name})"
47
+ end
48
+ end
49
+
50
+ # If we coulnd't find it, tell the user and drop out of the
51
+ # sequence.
52
+ if !env["image_id"]
53
+ say "error\nUnable to find a image named '#{user_image_name}'.", :red
54
+ exit 1
55
+ end
56
+ end
57
+
58
+ # We only need to "fuzzy find" a image if a fuzzy name is provided,
59
+ # and we don't want to fuzzy search if an id or name is provided
60
+ # with a flag.
61
+ #
62
+ # This requires a lookup.
63
+ if user_fuzzy_name && !env["image_id"]
64
+ say "Image fuzzy name provided. Finding image ID...", nil, false
65
+
66
+ found_images = []
67
+ choices = []
68
+
69
+ ocean.images.list.images.each_with_index do |d, i|
70
+ # Check to see if one of the image names have the fuzzy string.
71
+ if d.name.upcase.include? user_fuzzy_name.upcase
72
+ found_images << d
73
+ end
74
+ end
75
+
76
+ # Check to see if we have more then one image, and prompt
77
+ # a user to choose otherwise.
78
+ if found_images.length == 1
79
+ env["image_id"] = found_images.first.id
80
+ env["image_name"] = "(#{found_images.first.name})"
81
+ elsif found_images.length > 1
82
+ # Did we run the multiple questionairre?
83
+ did_run_multiple = true
84
+
85
+ say "Multiple images found."
86
+ say
87
+ found_images.each_with_index do |d, i|
88
+ say "#{i}) #{d.name} (#{d.id})"
89
+ choices << i.to_s
90
+ end
91
+ say
92
+ choice = ask "Please choose a image:", :limited_to => choices
93
+ env["image_id"] = found_images[choice.to_i].id
94
+ env["image_name"] = found_images[choice.to_i].name
95
+ end
96
+
97
+ # If we coulnd't find it, tell the user and drop out of the
98
+ # sequence.
99
+ if !env["image_id"]
100
+ say "error\nUnable to find an image named '#{user_fuzzy_name}'.", :red
101
+ exit 1
102
+ end
103
+ end
104
+
105
+ if !did_run_multiple
106
+ say "done#{CLEAR}, #{env["image_id"]} #{env["image_name"]}", :green
107
+ end
108
+ @app.call(env)
109
+ end
110
+ end
111
+ end
112
+ end
113
+
@@ -0,0 +1,25 @@
1
+ module Tugboat
2
+ module Middleware
3
+ class InfoImage < Base
4
+ def call(env)
5
+ ocean = env["ocean"]
6
+
7
+ req = ocean.images.show env["image_id"]
8
+
9
+ if req.status == "ERROR"
10
+ say "#{req.status}: #{req.error_message}", :red
11
+ exit 1
12
+ end
13
+
14
+ image = req.image
15
+
16
+ say
17
+ say "Name: #{image.name}"
18
+ say "ID: #{image.id}"
19
+ say "Distribution: #{image.distribution}"
20
+
21
+ @app.call(env)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,23 @@
1
+ module Tugboat
2
+ module Middleware
3
+ class RebuildDroplet < Base
4
+ def call(env)
5
+ ocean = env["ocean"]
6
+
7
+ say "Queuing rebuild for droplet #{env["droplet_id"]} #{env["droplet_name"]} with image #{env["image_id"]} #{env["image_name"]}...", nil, false
8
+
9
+ req = ocean.droplets.rebuild env["droplet_id"],
10
+ :image_id => env["image_id"]
11
+
12
+ if req.status == "ERROR"
13
+ say req.error_message, :red
14
+ exit 1
15
+ end
16
+
17
+ say "done", :green
18
+
19
+ @app.call(env)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,3 +1,3 @@
1
1
  module Tugboat
2
- VERSION = "0.0.9"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -34,12 +34,15 @@ describe Tugboat::CLI do
34
34
  $stdin.should_receive(:gets).and_return(ssh_key_id)
35
35
  $stdout.should_receive(:print).with("Enter your default for private networking (optional, defaults to false): ")
36
36
  $stdin.should_receive(:gets).and_return(private_networking)
37
+ $stdout.should_receive(:print).with("Enter your default for enabling backups (optional, defaults to false): ")
38
+ $stdin.should_receive(:gets).and_return(backups_enabled)
39
+
37
40
 
38
41
  @cli.authorize
39
42
 
40
43
  expect(a_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
41
44
 
42
- File.read(tmp_path).should include "image: '#{image}'", "region: '#{region}'", "size: '#{size}'", "ssh_user: #{ssh_user}", "ssh_key_path: #{ssh_key_path}", "ssh_port: '#{ssh_port}'", "ssh_key: '#{ssh_key_id}'", "private_networking: '#{private_networking}'"
45
+ File.read(tmp_path).should include "image: '#{image}'", "region: '#{region}'", "size: '#{size}'", "ssh_user: #{ssh_user}", "ssh_key_path: #{ssh_key_path}", "ssh_port: '#{ssh_port}'", "ssh_key: '#{ssh_key_id}'", "private_networking: '#{private_networking}'", "backups_enabled: '#{backups_enabled}'"
43
46
 
44
47
  end
45
48
 
@@ -66,6 +69,9 @@ describe Tugboat::CLI do
66
69
  $stdin.should_receive(:gets).and_return('')
67
70
  $stdout.should_receive(:print).with("Enter your default for private networking (optional, defaults to false): ")
68
71
  $stdin.should_receive(:gets).and_return('')
72
+ $stdout.should_receive(:print).with("Enter your default for enabling backups (optional, defaults to false): ")
73
+ $stdin.should_receive(:gets).and_return('')
74
+
69
75
 
70
76
  @cli.authorize
71
77
 
@@ -5,7 +5,7 @@ describe Tugboat::CLI do
5
5
 
6
6
  describe "create a droplet" do
7
7
  it "with a name, uses defaults from configuration" do
8
- stub_request(:get, "https://api.digitalocean.com/droplets/new?api_key=#{api_key}&client_id=#{client_key}&image_id=#{image}&name=#{droplet_name}&private_networking=#{private_networking}&region_id=#{region}&size_id=#{size}&ssh_key_ids=#{ssh_key_id}").
8
+ stub_request(:get, "https://api.digitalocean.com/droplets/new?api_key=#{api_key}&client_id=#{client_key}&image_id=#{image}&name=#{droplet_name}&backups_enabled=#{backups_enabled}&private_networking=#{private_networking}&region_id=#{region}&size_id=#{size}&ssh_key_ids=#{ssh_key_id}").
9
9
  to_return(:status => 200, :body => '{"status":"OK"}')
10
10
 
11
11
  @cli.create(droplet_name)
@@ -13,11 +13,11 @@ describe Tugboat::CLI do
13
13
  expect($stdout.string).to eq <<-eos
14
14
  Queueing creation of droplet '#{droplet_name}'...done
15
15
  eos
16
- expect(a_request(:get, "https://api.digitalocean.com/droplets/new?api_key=#{api_key}&client_id=#{client_key}&image_id=#{image}&name=#{droplet_name}&private_networking=#{private_networking}&region_id=#{region}&size_id=#{size}&ssh_key_ids=#{ssh_key_id}")).to have_been_made
16
+ expect(a_request(:get, "https://api.digitalocean.com/droplets/new?api_key=#{api_key}&client_id=#{client_key}&image_id=#{image}&name=#{droplet_name}&backups_enabled=#{backups_enabled}&private_networking=#{private_networking}&region_id=#{region}&size_id=#{size}&ssh_key_ids=#{ssh_key_id}")).to have_been_made
17
17
  end
18
18
 
19
19
  it "with args does not use defaults from configuration" do
20
- stub_request(:get, "https://api.digitalocean.com/droplets/new?api_key=#{api_key}&client_id=#{client_key}&image_id=555&name=foo&private_networking=#{private_networking}&region_id=3&size_id=666&ssh_key_ids=4321").
20
+ stub_request(:get, "https://api.digitalocean.com/droplets/new?api_key=#{api_key}&client_id=#{client_key}&image_id=555&name=foo&backups_enabled=#{backups_enabled}&private_networking=#{private_networking}&region_id=3&size_id=666&ssh_key_ids=4321").
21
21
  to_return(:status => 200, :body => '{"status":"OK"}')
22
22
 
23
23
  @cli.options = @cli.options.merge(:image => '555', :size => '666', :region => '3', :keys => '4321')
@@ -27,7 +27,7 @@ Queueing creation of droplet '#{droplet_name}'...done
27
27
  Queueing creation of droplet '#{droplet_name}'...done
28
28
  eos
29
29
 
30
- expect(a_request(:get, "https://api.digitalocean.com/droplets/new?api_key=#{api_key}&client_id=#{client_key}&image_id=555&name=foo&private_networking=#{private_networking}&region_id=3&size_id=666&ssh_key_ids=4321")).to have_been_made
30
+ expect(a_request(:get, "https://api.digitalocean.com/droplets/new?api_key=#{api_key}&client_id=#{client_key}&image_id=555&name=foo&backups_enabled=#{backups_enabled}&private_networking=#{private_networking}&region_id=3&size_id=666&ssh_key_ids=4321")).to have_been_made
31
31
  end
32
32
  end
33
33
 
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+
3
+ describe Tugboat::CLI do
4
+ include_context "spec"
5
+
6
+ describe "destroy image" do
7
+ it "destroys an image with a fuzzy name" do
8
+ stub_request(:get, "https://api.digitalocean.com/images?api_key=#{api_key}&client_id=#{client_key}").
9
+ to_return(:status => 200, :body => fixture("show_images"))
10
+
11
+ stub_request(:get, "https://api.digitalocean.com/images/478/destroy?api_key=#{api_key}&client_id=#{client_key}").
12
+ to_return(:status => 200, :body => fixture("show_image"))
13
+
14
+ $stdin.should_receive(:gets).and_return("y")
15
+
16
+ @cli.destroy_image("NLP Final")
17
+
18
+ expect($stdout.string).to eq <<-eos
19
+ Image fuzzy name provided. Finding image ID...done\e[0m, 478 (NLP Final)\nWarning! Potentially destructive action. Please confirm [y/n]: Queuing destroy image for 478 (NLP Final)...done
20
+ eos
21
+
22
+ expect(a_request(:get, "https://api.digitalocean.com/images?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
23
+ expect(a_request(:get, "https://api.digitalocean.com/images/478/destroy?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
24
+ end
25
+
26
+ it "destroys an image with an id" do
27
+ stub_request(:get, "https://api.digitalocean.com/images/478?api_key=#{api_key}&client_id=#{client_key}").
28
+ to_return(:status => 200, :body => fixture("show_image"))
29
+
30
+ stub_request(:get, "https://api.digitalocean.com/images/478/destroy?api_key=#{api_key}&client_id=#{client_key}").
31
+ to_return(:status => 200, :body => fixture("show_image"))
32
+
33
+ $stdin.should_receive(:gets).and_return("y")
34
+
35
+ @cli.options = @cli.options.merge(:id => 478)
36
+ @cli.destroy_image
37
+
38
+ expect($stdout.string).to eq <<-eos
39
+ Image id provided. Finding Image...done\e[0m, 478 (NLP Final)\nWarning! Potentially destructive action. Please confirm [y/n]: Queuing destroy image for 478 (NLP Final)...done
40
+ eos
41
+
42
+ expect(a_request(:get, "https://api.digitalocean.com/images/478?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
43
+ expect(a_request(:get, "https://api.digitalocean.com/images/478/destroy?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
44
+ end
45
+
46
+
47
+ it "destroys an image with a name" do
48
+ stub_request(:get, "https://api.digitalocean.com/images?api_key=#{api_key}&client_id=#{client_key}").
49
+ to_return(:status => 200, :body => fixture("show_images"))
50
+
51
+ stub_request(:get, "https://api.digitalocean.com/images/478/destroy?api_key=#{api_key}&client_id=#{client_key}").
52
+ to_return(:status => 200, :body => fixture("show_image"))
53
+
54
+ $stdin.should_receive(:gets).and_return("y")
55
+
56
+ @cli.options = @cli.options.merge(:name => "NLP Final")
57
+ @cli.destroy_image
58
+
59
+ expect($stdout.string).to eq <<-eos
60
+ Image name provided. Finding image ID...done\e[0m, 478 (NLP Final)\nWarning! Potentially destructive action. Please confirm [y/n]: Queuing destroy image for 478 (NLP Final)...done
61
+ eos
62
+
63
+ expect(a_request(:get, "https://api.digitalocean.com/images?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
64
+ expect(a_request(:get, "https://api.digitalocean.com/images/478/destroy?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
65
+ end
66
+
67
+
68
+ it "destroys an image with confirm flag set" do
69
+ stub_request(:get, "https://api.digitalocean.com/images?api_key=#{api_key}&client_id=#{client_key}").
70
+ to_return(:status => 200, :body => fixture("show_images"))
71
+
72
+ stub_request(:get, "https://api.digitalocean.com/images/478/destroy?api_key=#{api_key}&client_id=#{client_key}").
73
+ to_return(:status => 200, :body => fixture("show_image"))
74
+
75
+ @cli.options = @cli.options.merge(:name => "NLP Final")
76
+ @cli.options = @cli.options.merge(:confirm => true)
77
+ @cli.destroy_image("NLP Final")
78
+
79
+ expect($stdout.string).to eq <<-eos
80
+ Image name provided. Finding image ID...done\e[0m, 478 (NLP Final)\nQueuing destroy image for 478 (NLP Final)...done
81
+ eos
82
+
83
+ expect(a_request(:get, "https://api.digitalocean.com/images?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
84
+ expect(a_request(:get, "https://api.digitalocean.com/images/478/destroy?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
85
+ end
86
+ end
87
+
88
+ end
@@ -30,6 +30,18 @@ You don't appear to have any droplets.
30
30
  Try creating one with \e[32m`tugboat create`\e[0m
31
31
  eos
32
32
 
33
+ expect(a_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
34
+ end
35
+ it "shows no output when --quiet is set" do
36
+ stub_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}").
37
+ to_return(:status => 200, :body => fixture("show_droplets_empty"))
38
+
39
+ @cli.options = @cli.options.merge(:quiet => true)
40
+ @cli.droplets
41
+
42
+ # Should be /dev/null not stringIO
43
+ expect($stdout).to be_a File
44
+
33
45
  expect(a_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
34
46
  end
35
47
  end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe Tugboat::CLI do
4
+ include_context "spec"
5
+
6
+ describe "show" do
7
+ it "shows an image with a fuzzy name" do
8
+ stub_request(:get, "https://api.digitalocean.com/images?api_key=#{api_key}&client_id=#{client_key}").
9
+ to_return(:status => 200, :body => fixture("show_images"))
10
+
11
+ stub_request(:get, "https://api.digitalocean.com/images/478?api_key=#{api_key}&client_id=#{client_key}").
12
+ to_return(:status => 200, :body => fixture("show_image"))
13
+
14
+ @cli.info_image("NLP Final")
15
+
16
+ expect($stdout.string).to eq <<-eos
17
+ Image fuzzy name provided. Finding image ID...done\e[0m, 478 (NLP Final)\n\nName: NLP Final\nID: 478\nDistribution: Ubuntu
18
+ eos
19
+
20
+ expect(a_request(:get, "https://api.digitalocean.com/images?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
21
+ expect(a_request(:get, "https://api.digitalocean.com/images/478?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
22
+ end
23
+
24
+ it "shows an image with an id" do
25
+ stub_request(:get, "https://api.digitalocean.com/images/478?api_key=#{api_key}&client_id=#{client_key}").
26
+ to_return(:status => 200, :body => fixture("show_image"))
27
+
28
+ stub_request(:get, "https://api.digitalocean.com/images/478?api_key=#{api_key}&client_id=#{client_key}").
29
+ to_return(:status => 200, :body => fixture("show_image"))
30
+
31
+ @cli.options = @cli.options.merge(:id => 478)
32
+ @cli.info_image
33
+
34
+ expect($stdout.string).to eq <<-eos
35
+ Image id provided. Finding Image...done\e[0m, 478 (NLP Final)\n\nName: NLP Final\nID: 478\nDistribution: Ubuntu
36
+ eos
37
+
38
+ expect(a_request(:get, "https://api.digitalocean.com/images/478?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made.times(2)
39
+ end
40
+
41
+ it "shows an image with a name" do
42
+ stub_request(:get, "https://api.digitalocean.com/images?api_key=#{api_key}&client_id=#{client_key}").
43
+ to_return(:status => 200, :body => fixture("show_images"))
44
+
45
+ stub_request(:get, "https://api.digitalocean.com/images/478?api_key=#{api_key}&client_id=#{client_key}").
46
+ to_return(:status => 200, :body => fixture("show_image"))
47
+
48
+ @cli.options = @cli.options.merge(:name => "NLP Final")
49
+ @cli.info_image
50
+
51
+ expect($stdout.string).to eq <<-eos
52
+ Image name provided. Finding image ID...done\e[0m, 478 (NLP Final)\n\nName: NLP Final\nID: 478\nDistribution: Ubuntu
53
+ eos
54
+
55
+ expect(a_request(:get, "https://api.digitalocean.com/images/478?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
56
+ expect(a_request(:get, "https://api.digitalocean.com/images?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
57
+ end
58
+
59
+ end
60
+
61
+ end