tugboat 0.0.9 → 0.2.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.
@@ -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