tugboat 2.2.2 → 2.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +520 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +0 -6
- data/README.md +34 -2
- data/Rakefile +6 -1
- data/bin/tugboat +2 -2
- data/features/cassettes/config/Array_of_SSH_Keys_in_Config.yml +1 -1
- data/features/cassettes/config/Single_SSH_key_as_number_in_config.yml +1 -1
- data/features/step_definitions/steps.rb +1 -1
- data/features/support/env.rb +7 -3
- data/lib/tugboat.rb +2 -2
- data/lib/tugboat/cli.rb +394 -444
- data/lib/tugboat/config.rb +43 -61
- data/lib/tugboat/middleware.rb +33 -33
- data/lib/tugboat/middleware/add_key.rb +12 -13
- data/lib/tugboat/middleware/ask_for_credentials.rb +12 -13
- data/lib/tugboat/middleware/base.rb +25 -20
- data/lib/tugboat/middleware/check_configuration.rb +3 -6
- data/lib/tugboat/middleware/check_credentials.rb +0 -1
- data/lib/tugboat/middleware/check_droplet_active.rb +2 -4
- data/lib/tugboat/middleware/check_droplet_inactive.rb +2 -4
- data/lib/tugboat/middleware/config.rb +3 -5
- data/lib/tugboat/middleware/confirm_action.rb +4 -6
- data/lib/tugboat/middleware/create_droplet.rb +27 -44
- data/lib/tugboat/middleware/custom_logger.rb +52 -54
- data/lib/tugboat/middleware/destroy_droplet.rb +5 -6
- data/lib/tugboat/middleware/destroy_image.rb +5 -6
- data/lib/tugboat/middleware/find_droplet.rb +43 -47
- data/lib/tugboat/middleware/find_image.rb +23 -29
- data/lib/tugboat/middleware/halt_droplet.rb +9 -10
- data/lib/tugboat/middleware/info_droplet.rb +30 -33
- data/lib/tugboat/middleware/info_image.rb +1 -1
- data/lib/tugboat/middleware/inject_client.rb +8 -10
- data/lib/tugboat/middleware/inject_configuration.rb +1 -2
- data/lib/tugboat/middleware/list_droplets.rb +9 -10
- data/lib/tugboat/middleware/list_images.rb +9 -9
- data/lib/tugboat/middleware/list_regions.rb +1 -1
- data/lib/tugboat/middleware/list_sizes.rb +1 -1
- data/lib/tugboat/middleware/list_ssh_keys.rb +1 -3
- data/lib/tugboat/middleware/password_reset.rb +6 -7
- data/lib/tugboat/middleware/rebuild_droplet.rb +7 -7
- data/lib/tugboat/middleware/resize_droplet.rb +6 -7
- data/lib/tugboat/middleware/restart_droplet.rb +4 -11
- data/lib/tugboat/middleware/snapshot_droplet.rb +7 -8
- data/lib/tugboat/middleware/ssh_droplet.rb +30 -31
- data/lib/tugboat/middleware/start_droplet.rb +5 -5
- data/lib/tugboat/middleware/wait_for_state.rb +2 -3
- data/lib/tugboat/version.rb +1 -1
- data/spec/cli/add_key_spec.rb +25 -28
- data/spec/cli/authorize_cli_spec.rb +57 -60
- data/spec/cli/config_cli_spec.rb +8 -11
- data/spec/cli/create_cli_spec.rb +40 -46
- data/spec/cli/debug_cli_spec.rb +29 -29
- data/spec/cli/destroy_cli_spec.rb +58 -60
- data/spec/cli/destroy_image_cli_spec.rb +42 -45
- data/spec/cli/droplets_cli_spec.rb +62 -64
- data/spec/cli/env_variable_spec.rb +14 -15
- data/spec/cli/halt_cli_spec.rb +65 -69
- data/spec/cli/help_cli_spec.rb +8 -8
- data/spec/cli/images_cli_spec.rb +28 -30
- data/spec/cli/info_cli_spec.rb +144 -147
- data/spec/cli/info_image_cli_spec.rb +57 -60
- data/spec/cli/keys_cli_spec.rb +8 -10
- data/spec/cli/password_reset_cli_spec.rb +56 -56
- data/spec/cli/rebuild_cli_spec.rb +194 -198
- data/spec/cli/regions_cli_spec.rb +8 -8
- data/spec/cli/resize_cli_spec.rb +54 -56
- data/spec/cli/restart_cli_spec.rb +53 -57
- data/spec/cli/sizes_cli_spec.rb +7 -8
- data/spec/cli/snapshot_cli_spec.rb +50 -53
- data/spec/cli/ssh_cli_spec.rb +41 -42
- data/spec/cli/start_cli_spec.rb +48 -52
- data/spec/cli/verify_cli_spec.rb +22 -25
- data/spec/cli/version_cli_spec.rb +6 -8
- data/spec/cli/wait_cli_spec.rb +50 -52
- data/spec/config_spec.rb +56 -57
- data/spec/middleware/base_spec.rb +5 -6
- data/spec/middleware/check_configuration_spec.rb +5 -7
- data/spec/middleware/check_credentials_spec.rb +9 -10
- data/spec/middleware/check_droplet_active_spec.rb +5 -7
- data/spec/middleware/check_droplet_inactive_spec.rb +5 -7
- data/spec/middleware/find_droplet_spec.rb +4 -5
- data/spec/middleware/find_image_spec.rb +4 -5
- data/spec/middleware/inject_client_spec.rb +9 -12
- data/spec/middleware/inject_configuration_spec.rb +4 -7
- data/spec/middleware/ssh_droplet_spec.rb +70 -73
- data/spec/shared/environment.rb +18 -20
- data/spec/spec_helper.rb +4 -4
- data/tugboat.gemspec +10 -6
- metadata +88 -17
@@ -11,7 +11,7 @@ module Tugboat
|
|
11
11
|
# First, if nothing is provided to us, we should quit and
|
12
12
|
# let the user know.
|
13
13
|
if !user_fuzzy_name && !user_image_name && !user_image_id
|
14
|
-
say
|
14
|
+
say 'Tugboat attempted to find an image with no arguments.', :red
|
15
15
|
say "Try running `tugboat #{env['tugboat_action']} imagename`", :green
|
16
16
|
say "For more help run: `tugboat help #{env['tugboat_action']}`", :blue
|
17
17
|
exit 1
|
@@ -24,7 +24,7 @@ module Tugboat
|
|
24
24
|
|
25
25
|
# Easy for us if they provide an id. Just set it to the image_id
|
26
26
|
if user_image_id
|
27
|
-
say
|
27
|
+
say 'Image id provided. Finding Image...', nil, false
|
28
28
|
response = ocean.image.show user_image_id
|
29
29
|
|
30
30
|
unless response.success?
|
@@ -32,26 +32,26 @@ module Tugboat
|
|
32
32
|
exit 1
|
33
33
|
end
|
34
34
|
|
35
|
-
env[
|
36
|
-
env[
|
35
|
+
env['image_id'] = response.image.id
|
36
|
+
env['image_name'] = "(#{response.image.name})"
|
37
37
|
end
|
38
38
|
|
39
39
|
# If they provide a name, we need to get the ID for it.
|
40
40
|
# This requires a lookup.
|
41
|
-
if user_image_name && !env[
|
42
|
-
say
|
41
|
+
if user_image_name && !env['image_id']
|
42
|
+
say 'Image name provided. Finding Image...', nil, false
|
43
43
|
|
44
44
|
# Look for the image by an exact name match.
|
45
45
|
ocean.image.all['images'].each do |d|
|
46
46
|
if d.name == user_image_name
|
47
|
-
env[
|
48
|
-
env[
|
47
|
+
env['image_id'] = d.id
|
48
|
+
env['image_name'] = "(#{d.name})"
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
52
|
# If we coulnd't find it, tell the user and drop out of the
|
53
53
|
# sequence.
|
54
|
-
|
54
|
+
unless env['image_id']
|
55
55
|
say "error\nUnable to find an image named '#{user_image_name}'.", :red
|
56
56
|
exit 1
|
57
57
|
end
|
@@ -62,61 +62,55 @@ module Tugboat
|
|
62
62
|
# with a flag.
|
63
63
|
#
|
64
64
|
# This requires a lookup.
|
65
|
-
if user_fuzzy_name && !env[
|
66
|
-
say
|
65
|
+
if user_fuzzy_name && !env['image_id']
|
66
|
+
say 'Image fuzzy name provided. Finding image ID...', nil, false
|
67
67
|
|
68
68
|
found_images = []
|
69
69
|
choices = []
|
70
70
|
|
71
|
-
ocean.image.all['images'].each_with_index do |d,
|
72
|
-
|
71
|
+
ocean.image.all['images'].each_with_index do |d, _i|
|
73
72
|
# Check to see if one of the image names have the fuzzy string.
|
74
|
-
if d.name.upcase.include? user_fuzzy_name.upcase
|
75
|
-
found_images << d
|
76
|
-
end
|
73
|
+
found_images << d if d.name.upcase.include? user_fuzzy_name.upcase
|
77
74
|
|
78
75
|
unless d.slug.nil?
|
79
|
-
if d.slug.upcase.include? user_fuzzy_name.upcase
|
80
|
-
found_images << d
|
81
|
-
end
|
76
|
+
found_images << d if d.slug.upcase.include? user_fuzzy_name.upcase
|
82
77
|
end
|
83
78
|
end
|
84
79
|
|
85
80
|
# Check to see if we have more then one image, and prompt
|
86
81
|
# a user to choose otherwise.
|
87
82
|
if found_images.length == 1
|
88
|
-
env[
|
89
|
-
env[
|
83
|
+
env['image_id'] = found_images.first.id
|
84
|
+
env['image_name'] = "(#{found_images.first.name})"
|
90
85
|
elsif found_images.length > 1
|
91
86
|
# Did we run the multiple questionairre?
|
92
87
|
did_run_multiple = true
|
93
88
|
|
94
|
-
say
|
89
|
+
say 'Multiple images found.'
|
95
90
|
say
|
96
91
|
found_images.each_with_index do |d, i|
|
97
92
|
say "#{i}) #{d.name} (#{d.id})"
|
98
93
|
choices << i.to_s
|
99
94
|
end
|
100
95
|
say
|
101
|
-
choice = ask
|
102
|
-
env[
|
103
|
-
env[
|
96
|
+
choice = ask 'Please choose a image:', limited_to: choices
|
97
|
+
env['image_id'] = found_images[choice.to_i].id
|
98
|
+
env['image_name'] = found_images[choice.to_i].name
|
104
99
|
end
|
105
100
|
|
106
101
|
# If we coulnd't find it, tell the user and drop out of the
|
107
102
|
# sequence.
|
108
|
-
|
103
|
+
unless env['image_id']
|
109
104
|
say "error\nUnable to find an image named '#{user_fuzzy_name}'.", :red
|
110
105
|
exit 1
|
111
106
|
end
|
112
107
|
end
|
113
108
|
|
114
|
-
|
115
|
-
say "done#{CLEAR}, #{env[
|
109
|
+
unless did_run_multiple
|
110
|
+
say "done#{CLEAR}, #{env['image_id']} #{env['image_name']}", :green
|
116
111
|
end
|
117
112
|
@app.call(env)
|
118
113
|
end
|
119
114
|
end
|
120
115
|
end
|
121
116
|
end
|
122
|
-
|
@@ -4,19 +4,19 @@ module Tugboat
|
|
4
4
|
def call(env)
|
5
5
|
ocean = env['barge']
|
6
6
|
|
7
|
-
response = if env[
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
response = if env['user_droplet_hard']
|
8
|
+
say "Queuing hard shutdown for #{env['droplet_id']} #{env['droplet_name']}...", nil, false
|
9
|
+
ocean.droplet.power_off env['droplet_id']
|
10
|
+
else
|
11
|
+
say "Queuing shutdown for #{env['droplet_id']} #{env['droplet_name']}...", nil, false
|
12
|
+
ocean.droplet.shutdown env['droplet_id']
|
13
13
|
end
|
14
14
|
|
15
|
-
|
15
|
+
if response.success?
|
16
|
+
say 'Halt successful!', :green
|
17
|
+
else
|
16
18
|
say "Failed to halt on Droplet: #{response.message}", :red
|
17
19
|
exit 1
|
18
|
-
else
|
19
|
-
say "Halt successful!", :green
|
20
20
|
end
|
21
21
|
|
22
22
|
@app.call(env)
|
@@ -24,4 +24,3 @@ module Tugboat
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
27
|
-
|
@@ -4,7 +4,7 @@ module Tugboat
|
|
4
4
|
def call(env)
|
5
5
|
ocean = env['barge']
|
6
6
|
|
7
|
-
response = ocean.droplet.show env[
|
7
|
+
response = ocean.droplet.show env['droplet_id']
|
8
8
|
|
9
9
|
check_response_success('get info for Droplet', response)
|
10
10
|
|
@@ -15,45 +15,45 @@ module Tugboat
|
|
15
15
|
exit 1
|
16
16
|
end
|
17
17
|
|
18
|
-
if droplet.status ==
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
status_color = if droplet.status == 'active'
|
19
|
+
GREEN
|
20
|
+
else
|
21
|
+
RED
|
22
|
+
end
|
23
23
|
|
24
|
-
attribute = env[
|
24
|
+
attribute = env['user_attribute']
|
25
25
|
|
26
|
-
droplet_ip4_public = droplet.networks.v4.
|
27
|
-
droplet_ip6_public = droplet.networks.v6.
|
28
|
-
check_private_ip = droplet.networks.v4.
|
26
|
+
droplet_ip4_public = droplet.networks.v4.find { |address| address.type == 'public' }.ip_address
|
27
|
+
droplet_ip6_public = droplet.networks.v6.find { |address| address.type == 'public' }.ip_address unless droplet.networks.v6.empty?
|
28
|
+
check_private_ip = droplet.networks.v4.find { |address| address.type == 'private' }
|
29
29
|
droplet_private_ip = check_private_ip.ip_address if check_private_ip
|
30
30
|
|
31
31
|
attributes_list = [
|
32
|
-
[
|
33
|
-
[
|
34
|
-
[
|
35
|
-
[
|
36
|
-
[
|
37
|
-
[
|
38
|
-
[
|
39
|
-
[
|
40
|
-
[
|
41
|
-
[
|
32
|
+
['name', droplet.name],
|
33
|
+
['id', droplet.id],
|
34
|
+
['status', droplet.status],
|
35
|
+
['ip4', droplet_ip4_public],
|
36
|
+
['ip6', droplet_ip6_public],
|
37
|
+
['private_ip', droplet_private_ip],
|
38
|
+
['region', droplet.region.slug],
|
39
|
+
['image', droplet.image.id],
|
40
|
+
['size', droplet.size_slug],
|
41
|
+
['backups_active', !droplet.backup_ids.empty?]
|
42
42
|
]
|
43
43
|
attributes = Hash[*attributes_list.flatten(1)]
|
44
44
|
|
45
45
|
if attribute
|
46
|
-
if attributes.
|
46
|
+
if attributes.key? attribute
|
47
47
|
say attributes[attribute]
|
48
48
|
else
|
49
49
|
say "Invalid attribute \"#{attribute}\"", :red
|
50
|
-
say
|
50
|
+
say 'Provide one of the following:', :red
|
51
51
|
attributes_list.each { |a| say " #{a[0]}", :red }
|
52
52
|
exit 1
|
53
53
|
end
|
54
54
|
else
|
55
|
-
if env[
|
56
|
-
attributes_list.select{ |a| a[1]
|
55
|
+
if env['user_porcelain']
|
56
|
+
attributes_list.select { |a| !a[1].nil? }.each { |a| say "#{a[0]} #{a[1]}" }
|
57
57
|
else
|
58
58
|
say
|
59
59
|
say "Name: #{droplet.name}"
|
@@ -62,15 +62,13 @@ module Tugboat
|
|
62
62
|
say "IP4: #{droplet_ip4_public}"
|
63
63
|
say "IP6: #{droplet_ip6_public}" unless droplet.networks.v6.empty?
|
64
64
|
|
65
|
-
if droplet_private_ip
|
66
|
-
say "Private IP: #{droplet_private_ip}"
|
67
|
-
end
|
65
|
+
say "Private IP: #{droplet_private_ip}" if droplet_private_ip
|
68
66
|
|
69
|
-
if droplet.image.slug.nil?
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
67
|
+
image_description = if droplet.image.slug.nil?
|
68
|
+
droplet.image.name
|
69
|
+
else
|
70
|
+
droplet.image.slug
|
71
|
+
end
|
74
72
|
|
75
73
|
say "Region: #{droplet.region.name} - #{droplet.region.slug}"
|
76
74
|
say "Image: #{droplet.image.id} - #{image_description}"
|
@@ -84,4 +82,3 @@ module Tugboat
|
|
84
82
|
end
|
85
83
|
end
|
86
84
|
end
|
87
|
-
|
@@ -5,19 +5,17 @@ module Tugboat
|
|
5
5
|
module Middleware
|
6
6
|
# Inject the digital ocean client into the environment
|
7
7
|
class InjectClient < Base
|
8
|
+
def call(env)
|
9
|
+
# Sets the digital ocean client into the environment for use
|
10
|
+
# later.
|
11
|
+
@access_token = env['config'].access_token
|
8
12
|
|
9
|
-
|
10
|
-
# Sets the digital ocean client into the environment for use
|
11
|
-
# later.
|
12
|
-
@access_token = env["config"].access_token
|
13
|
+
env['barge'] = Barge::Client.new(access_token: @access_token)
|
13
14
|
|
14
|
-
|
15
|
+
env['barge'].faraday.use CustomLogger if ENV['DEBUG']
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
@app.call(env)
|
19
|
-
end
|
17
|
+
@app.call(env)
|
18
|
+
end
|
20
19
|
end
|
21
20
|
end
|
22
21
|
end
|
23
|
-
|
@@ -13,22 +13,22 @@ module Tugboat
|
|
13
13
|
droplet_list.each do |droplet|
|
14
14
|
has_one = true
|
15
15
|
|
16
|
-
private_addr = droplet.networks.v4.
|
16
|
+
private_addr = droplet.networks.v4.find { |address| address.type == 'private' }
|
17
17
|
if private_addr
|
18
18
|
private_ip = ", private_ip: #{private_addr.ip_address}"
|
19
19
|
end
|
20
20
|
|
21
|
-
if droplet.status ==
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
status_color = if droplet.status == 'active'
|
22
|
+
GREEN
|
23
|
+
else
|
24
|
+
RED
|
25
|
+
end
|
26
26
|
|
27
|
-
public_addr = droplet.networks.v4.
|
28
|
-
say "#{droplet.name} (ip: #{public_addr.ip_address}#{private_ip}, status: #{status_color}#{droplet.status}#{CLEAR}, region: #{droplet.region.slug}, id: #{droplet.id}#{env[
|
27
|
+
public_addr = droplet.networks.v4.find { |address| address.type == 'public' }
|
28
|
+
say "#{droplet.name} (ip: #{public_addr.ip_address}#{private_ip}, status: #{status_color}#{droplet.status}#{CLEAR}, region: #{droplet.region.slug}, id: #{droplet.id}#{env['include_urls'] ? droplet_id_to_url(droplet.id) : ''})"
|
29
29
|
end
|
30
30
|
|
31
|
-
|
31
|
+
unless has_one
|
32
32
|
say "You don't appear to have any droplets.", :red
|
33
33
|
say "Try creating one with #{GREEN}\`tugboat create\`#{CLEAR}"
|
34
34
|
end
|
@@ -44,4 +44,3 @@ module Tugboat
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
47
|
-
|
@@ -3,33 +3,33 @@ module Tugboat
|
|
3
3
|
class ListImages < Base
|
4
4
|
def call(env)
|
5
5
|
ocean = env['barge']
|
6
|
-
my_images = ocean.image.all(:
|
6
|
+
my_images = ocean.image.all(private: true)
|
7
7
|
public_images = ocean.image.all.images - my_images.images
|
8
8
|
|
9
9
|
if env['user_show_just_private_images']
|
10
|
-
say
|
11
|
-
say
|
10
|
+
say 'Showing just private images', :green
|
11
|
+
say 'Private Images:', :blue
|
12
12
|
my_images_list = my_images.images
|
13
13
|
if my_images_list.nil? || my_images_list.empty?
|
14
|
-
say
|
14
|
+
say 'No private images found'
|
15
15
|
else
|
16
16
|
my_images_list.each do |image|
|
17
17
|
say "#{image.name} (id: #{image.id}, distro: #{image.distribution})"
|
18
18
|
end
|
19
19
|
end
|
20
20
|
else
|
21
|
-
say
|
22
|
-
say
|
21
|
+
say 'Showing both private and public images'
|
22
|
+
say 'Private Images:', :blue
|
23
23
|
my_images_list = my_images.images
|
24
24
|
if my_images_list.nil? || my_images_list.empty?
|
25
|
-
say
|
25
|
+
say 'No private images found'
|
26
26
|
else
|
27
27
|
my_images_list.each do |image|
|
28
28
|
say "#{image.name} (id: #{image.id}, distro: #{image.distribution})"
|
29
29
|
end
|
30
30
|
end
|
31
31
|
say ''
|
32
|
-
say
|
32
|
+
say 'Public Images:', :blue
|
33
33
|
public_images.each do |image|
|
34
34
|
say "#{image.name} (slug: #{image.slug}, id: #{image.id}, distro: #{image.distribution})"
|
35
35
|
end
|
@@ -39,4 +39,4 @@ module Tugboat
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
42
|
-
end
|
42
|
+
end
|
@@ -2,11 +2,10 @@ module Tugboat
|
|
2
2
|
module Middleware
|
3
3
|
class ListSSHKeys < Base
|
4
4
|
def call(env)
|
5
|
-
|
6
5
|
ocean = env['barge']
|
7
6
|
ssh_keys = ocean.key.all.ssh_keys
|
8
7
|
|
9
|
-
say
|
8
|
+
say 'SSH Keys:'
|
10
9
|
ssh_keys.each do |key|
|
11
10
|
say "Name: #{key.name}, (id: #{key.id}), fingerprint: #{key.fingerprint}"
|
12
11
|
end
|
@@ -16,4 +15,3 @@ module Tugboat
|
|
16
15
|
end
|
17
16
|
end
|
18
17
|
end
|
19
|
-
|
@@ -4,15 +4,15 @@ module Tugboat
|
|
4
4
|
def call(env)
|
5
5
|
ocean = env['barge']
|
6
6
|
|
7
|
-
say "Queuing password reset for #{env[
|
8
|
-
response = ocean.droplet.password_reset env[
|
7
|
+
say "Queuing password reset for #{env['droplet_id']} #{env['droplet_name']}...", nil, false
|
8
|
+
response = ocean.droplet.password_reset env['droplet_id']
|
9
9
|
|
10
|
-
|
10
|
+
if response.success?
|
11
|
+
say 'Password reset successful!', :green
|
12
|
+
say 'Your new root password will be emailed to you', :green
|
13
|
+
else
|
11
14
|
say "Failed to reset password on Droplet: #{response.message}", :red
|
12
15
|
exit 1
|
13
|
-
else
|
14
|
-
say "Password reset successful!", :green
|
15
|
-
say "Your new root password will be emailed to you", :green
|
16
16
|
end
|
17
17
|
|
18
18
|
@app.call(env)
|
@@ -20,4 +20,3 @@ module Tugboat
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
23
|
-
|