vmfloaty 0.8.1 → 0.10.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.
- checksums.yaml +5 -5
- data/README.md +96 -55
- data/bin/floaty +2 -1
- data/lib/vmfloaty.rb +60 -53
- data/lib/vmfloaty/abs.rb +318 -0
- data/lib/vmfloaty/auth.rb +14 -22
- data/lib/vmfloaty/conf.rb +3 -2
- data/lib/vmfloaty/errors.rb +6 -4
- data/lib/vmfloaty/http.rb +14 -25
- data/lib/vmfloaty/nonstandard_pooler.rb +15 -31
- data/lib/vmfloaty/pooler.rb +64 -55
- data/lib/vmfloaty/service.rb +25 -17
- data/lib/vmfloaty/ssh.rb +25 -25
- data/lib/vmfloaty/utils.rb +103 -97
- data/lib/vmfloaty/version.rb +3 -1
- data/spec/spec_helper.rb +13 -0
- data/spec/vmfloaty/abs/auth_spec.rb +84 -0
- data/spec/vmfloaty/abs_spec.rb +126 -0
- data/spec/vmfloaty/auth_spec.rb +39 -43
- data/spec/vmfloaty/nonstandard_pooler_spec.rb +132 -146
- data/spec/vmfloaty/pooler_spec.rb +121 -101
- data/spec/vmfloaty/service_spec.rb +17 -17
- data/spec/vmfloaty/ssh_spec.rb +49 -0
- data/spec/vmfloaty/utils_spec.rb +123 -98
- data/spec/vmfloaty/vmfloaty_services_spec.rb +39 -0
- metadata +38 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e7789275b2b0b2a9a85ccf0c9c3820dd4bffd882b1567d2c8ed739eb937eab32
|
4
|
+
data.tar.gz: cadb2bb55534f79a7fb3c6d06136b2993531958a9ffc269203bfcdeae8ee8361
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ebc7b72f2633318c51f29fefc26cd234d7666b731907ba27491c8592a3a068e3f0e25df2ce4c9cdbf05f404a6110ac6f4112250526473a25f771ed464b08a87
|
7
|
+
data.tar.gz: 6a12342fde08a069f75ed3fa9fb6918a1f295622129f5685405b941196515c08b07c6125b1736904271ee791342412a28cd63ac5189e11611969f5dd192fbebb
|
data/README.md
CHANGED
@@ -1,40 +1,64 @@
|
|
1
|
-
vmfloaty
|
2
|
-
|
3
|
-
|
4
|
-
[](https://badge.fury.io/rb/vmfloaty)
|
4
|
+
[](https://travis-ci.com/puppetlabs/vmfloaty)
|
5
|
+
[](https://coveralls.io/github/puppetlabs/vmfloaty?branch=master)
|
6
|
+
[](https://dependabot.com)
|
7
|
+
|
8
|
+
A CLI helper tool for [Puppet's vmpooler](https://github.com/puppetlabs/vmpooler) to help you stay afloat.
|
9
|
+
|
10
|
+

|
11
|
+
|
12
|
+
- [Install](#install)
|
13
|
+
- [Usage](#usage)
|
14
|
+
- [Example workflow](#example-workflow)
|
15
|
+
- [vmfloaty dotfile](#vmfloaty-dotfile)
|
16
|
+
- [Basic configuration](#basic-configuration)
|
17
|
+
- [Default to Puppet's ABS instead of vmpooler](#default-to-puppets-abs-instead-of-vmpooler)
|
18
|
+
- [Configuring multiple services](#configuring-multiple-services)
|
19
|
+
- [Using a Nonstandard Pooler service](#using-a-nonstandard-pooler-service)
|
20
|
+
- [Valid config keys](#valid-config-keys)
|
21
|
+
- [Tab Completion](#tab-completion)
|
22
|
+
- [vmpooler API](#vmpooler-api)
|
23
|
+
- [Using the Pooler class](#using-the-pooler-class)
|
24
|
+
- [Example Projects](#example-projects)
|
25
|
+
- [Special thanks](#special-thanks)
|
11
26
|
|
12
27
|
## Install
|
13
28
|
|
14
29
|
Grab the latest from ruby gems...
|
15
30
|
|
16
|
-
```
|
17
|
-
|
18
|
-
...
|
19
|
-
...
|
20
|
-
$ floaty --help
|
31
|
+
```bash
|
32
|
+
gem install vmfloaty
|
21
33
|
```
|
22
34
|
|
23
35
|
## Usage
|
24
36
|
|
25
|
-
```
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
37
|
+
```plain
|
38
|
+
$ floaty --help
|
39
|
+
NAME:
|
40
|
+
|
41
|
+
floaty
|
42
|
+
|
43
|
+
DESCRIPTION:
|
44
|
+
|
45
|
+
A CLI helper tool for Puppet's vmpooler to help you stay afloat
|
46
|
+
|
47
|
+
COMMANDS:
|
48
|
+
|
49
|
+
completion Outputs path to completion script
|
50
|
+
delete Schedules the deletion of a host or hosts
|
51
|
+
get Gets a vm or vms based on the os argument
|
52
|
+
help Display global or [command] help documentation
|
53
|
+
list Shows a list of available vms from the pooler or vms obtained with a token
|
54
|
+
modify Modify a VM's tags, time to live, disk space, or reservation reason
|
55
|
+
query Get information about a given vm
|
56
|
+
revert Reverts a vm to a specified snapshot
|
57
|
+
snapshot Takes a snapshot of a given vm
|
58
|
+
ssh Grabs a single vm and sshs into it
|
59
|
+
status Prints the status of pools in the pooler service
|
60
|
+
summary Prints a summary of a pooler service
|
61
|
+
token Retrieves or deletes a token or checks token status
|
38
62
|
|
39
63
|
GLOBAL OPTIONS:
|
40
64
|
|
@@ -52,33 +76,43 @@ $ floaty --help
|
|
52
76
|
|
53
77
|
Grabbing a token for authenticated pooler requests:
|
54
78
|
|
55
|
-
```
|
56
|
-
floaty token get --user username --url https://vmpooler.
|
79
|
+
```bash
|
80
|
+
floaty token get --user username --url https://vmpooler.example.net/api/v1
|
57
81
|
```
|
58
82
|
|
59
83
|
This command will then ask you to log in. If successful, it will return a token that you can save either in a dotfile or use with other cli commands.
|
60
84
|
|
61
85
|
Grabbing vms:
|
62
86
|
|
63
|
-
```
|
64
|
-
floaty get centos-7-x86_64=2 debian-7-x86_64 windows-10=3 --token mytokenstring --url https://vmpooler.
|
87
|
+
```bash
|
88
|
+
floaty get centos-7-x86_64=2 debian-7-x86_64 windows-10=3 --token mytokenstring --url https://vmpooler.example.net/api/v1
|
65
89
|
```
|
66
90
|
|
67
91
|
### vmfloaty dotfile
|
68
92
|
|
69
|
-
If you do not wish to
|
93
|
+
If you do not wish to continually specify various config options with the cli, you can have a dotfile in your home directory for some defaults. For example:
|
70
94
|
|
71
95
|
#### Basic configuration
|
72
96
|
|
73
97
|
```yaml
|
74
|
-
# file at
|
75
|
-
url: 'https://vmpooler.
|
98
|
+
# file at ~/.vmfloaty.yml
|
99
|
+
url: 'https://vmpooler.example.net/api/v1'
|
76
100
|
user: 'brian'
|
77
101
|
token: 'tokenstring'
|
78
102
|
```
|
79
103
|
|
80
104
|
Now vmfloaty will use those config files if no flag was specified.
|
81
105
|
|
106
|
+
#### Default to Puppet's ABS instead of vmpooler
|
107
|
+
|
108
|
+
```yaml
|
109
|
+
# file at ~/.vmfloaty.yml
|
110
|
+
url: 'https://abs.example.net'
|
111
|
+
user: 'brian'
|
112
|
+
token: 'tokenstring'
|
113
|
+
type: 'abs'
|
114
|
+
```
|
115
|
+
|
82
116
|
#### Configuring multiple services
|
83
117
|
|
84
118
|
Most commands allow you to specify a `--service <servicename>` option to allow the use of multiple vmpooler instances. This can be useful when you'd rather not specify a `--url` or `--token` by hand for alternate services.
|
@@ -90,10 +124,10 @@ To configure multiple services, you can set up your `~/.vmfloaty.yml` config fil
|
|
90
124
|
user: 'brian'
|
91
125
|
services:
|
92
126
|
main:
|
93
|
-
url: 'https://vmpooler.
|
127
|
+
url: 'https://vmpooler.example.net/api/v1'
|
94
128
|
token: 'tokenstring'
|
95
129
|
alternate:
|
96
|
-
url: 'https://vmpooler.
|
130
|
+
url: 'https://vmpooler.example.com/api/v1'
|
97
131
|
token: 'alternate-tokenstring'
|
98
132
|
```
|
99
133
|
|
@@ -105,14 +139,16 @@ services:
|
|
105
139
|
Examples using the above configuration:
|
106
140
|
|
107
141
|
List available vm types from our main vmpooler instance:
|
108
|
-
|
142
|
+
|
143
|
+
```bash
|
109
144
|
floaty list --service main
|
110
145
|
# or, since the first configured service is used by default:
|
111
146
|
floaty list
|
112
147
|
```
|
113
148
|
|
114
149
|
List available vm types from our alternate vmpooler instance:
|
115
|
-
|
150
|
+
|
151
|
+
```bash
|
116
152
|
floaty list --service alternate
|
117
153
|
```
|
118
154
|
|
@@ -125,17 +161,22 @@ vmfloaty is capable of working with Puppet's [nonstandard pooler](https://github
|
|
125
161
|
user: 'brian'
|
126
162
|
services:
|
127
163
|
vm:
|
128
|
-
url: 'https://vmpooler.
|
164
|
+
url: 'https://vmpooler.example.net/api/v1'
|
129
165
|
token: 'tokenstring'
|
130
166
|
ns:
|
131
|
-
url: 'https://nspooler.
|
167
|
+
url: 'https://nspooler.example.net/api/v1'
|
132
168
|
token: 'nspooler-tokenstring'
|
133
169
|
type: 'nonstandard' # <-- 'type' is necessary for any non-vmpooler service
|
170
|
+
abs:
|
171
|
+
url: 'https://abs.example.net/'
|
172
|
+
token: 'abs-tokenstring'
|
173
|
+
type: 'abs' # <-- 'type' is necessary for any non-vmpooler service
|
174
|
+
|
134
175
|
```
|
135
176
|
|
136
177
|
With this configuration, you could list available OS types from nspooler like this:
|
137
178
|
|
138
|
-
```
|
179
|
+
```bash
|
139
180
|
floaty list --service ns
|
140
181
|
```
|
141
182
|
|
@@ -143,20 +184,16 @@ floaty list --service ns
|
|
143
184
|
|
144
185
|
Here are the keys that vmfloaty currently supports:
|
145
186
|
|
146
|
-
- verbose
|
147
|
-
|
148
|
-
-
|
149
|
-
|
150
|
-
-
|
151
|
-
|
152
|
-
- url
|
153
|
-
+ String
|
154
|
-
- services
|
155
|
-
+ Map
|
187
|
+
- verbose (Boolean)
|
188
|
+
- token (String)
|
189
|
+
- user (String)
|
190
|
+
- url (String)
|
191
|
+
- services (String)
|
192
|
+
- type (String)
|
156
193
|
|
157
194
|
### Tab Completion
|
158
195
|
|
159
|
-
There is a basic completion script for Bash (and possibly other shells) included with the gem in the [extras/completions](https://github.com/
|
196
|
+
There is a basic completion script for Bash (and possibly other shells) included with the gem in the [extras/completions](https://github.com/puppetlabs/vmfloaty/blob/master/extras/completions) folder. To activate, that file simply needs to be sourced somehow in your shell profile.
|
160
197
|
|
161
198
|
For convenience, the path to the completion script for the currently active version of the gem can be found with the `floaty completion` subcommand. This makes it easy to add the completion script to your profile like so:
|
162
199
|
|
@@ -181,6 +218,10 @@ vmfloaty providers a `Pooler` class that gives users the ability to make request
|
|
181
218
|
### Example Projects
|
182
219
|
|
183
220
|
- [John McCabe: vmpooler-bitbar](https://github.com/johnmccabe/vmpooler-bitbar/)
|
184
|
-
|
221
|
+
- vmpooler status and management in your menubar with bitbar
|
185
222
|
- [Brian Cain: vagrant-vmpooler](https://github.com/briancain/vagrant-vmpooler)
|
186
|
-
|
223
|
+
- Use Vagrant to manage your vmpooler instances
|
224
|
+
|
225
|
+
## Special thanks
|
226
|
+
|
227
|
+
Special thanks to [Brian Cain](https://github.com/briancain) as he is the original author of vmfloaty! Vast amounts of this code exist thanks to his efforts.
|
data/bin/floaty
CHANGED
data/lib/vmfloaty.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'commander'
|
@@ -17,9 +17,9 @@ require 'vmfloaty/ssh'
|
|
17
17
|
class Vmfloaty
|
18
18
|
include Commander::Methods
|
19
19
|
|
20
|
-
def run
|
20
|
+
def run # rubocop:disable Metrics/AbcSize
|
21
21
|
program :version, Vmfloaty::VERSION
|
22
|
-
program :description,
|
22
|
+
program :description, "A CLI helper tool for Puppet's vmpooler to help you stay afloat"
|
23
23
|
|
24
24
|
config = Conf.read_config
|
25
25
|
|
@@ -33,8 +33,11 @@ class Vmfloaty
|
|
33
33
|
c.option '--user STRING', String, 'User to authenticate with'
|
34
34
|
c.option '--url STRING', String, 'URL of pooler service'
|
35
35
|
c.option '--token STRING', String, 'Token for pooler service'
|
36
|
+
c.option '--priority STRING', 'Priority for supported backends(ABS) (High(1), Medium(2), Low(3))'
|
36
37
|
c.option '--notoken', 'Makes a request without a token'
|
37
38
|
c.option '--force', 'Forces vmfloaty to get requested vms'
|
39
|
+
c.option '--json', 'Prints retrieved vms in JSON format'
|
40
|
+
c.option '--ondemand', 'Requested vms are provisioned upon receival of the request, tracked by a request ID'
|
38
41
|
c.action do |args, options|
|
39
42
|
verbose = options.verbose || config['verbose']
|
40
43
|
service = Service.new(options, config)
|
@@ -42,27 +45,36 @@ class Vmfloaty
|
|
42
45
|
force = options.force
|
43
46
|
|
44
47
|
if args.empty?
|
45
|
-
STDERR.puts
|
48
|
+
STDERR.puts 'No operating systems provided to obtain. See `floaty get --help` for more information on how to get VMs.'
|
46
49
|
exit 1
|
47
50
|
end
|
48
51
|
|
49
52
|
os_types = Utils.generate_os_hash(args)
|
50
53
|
|
51
54
|
max_pool_request = 5
|
52
|
-
large_pool_requests = os_types.select{|_,v| v > max_pool_request}
|
53
|
-
if !
|
55
|
+
large_pool_requests = os_types.select { |_, v| v > max_pool_request }
|
56
|
+
if !large_pool_requests.empty? && !force
|
54
57
|
STDERR.puts "Requesting vms over #{max_pool_request} requires a --force flag."
|
55
|
-
STDERR.puts
|
58
|
+
STDERR.puts 'Try again with `floaty get --force`'
|
56
59
|
exit 1
|
57
60
|
end
|
58
61
|
|
59
62
|
if os_types.empty?
|
60
|
-
STDERR.puts
|
63
|
+
STDERR.puts 'No operating systems provided to obtain. See `floaty get --help` for more information on how to get VMs.'
|
61
64
|
exit 1
|
62
65
|
end
|
63
66
|
|
64
|
-
response = service.retrieve(verbose, os_types, use_token)
|
65
|
-
|
67
|
+
response = service.retrieve(verbose, os_types, use_token, options.ondemand)
|
68
|
+
request_id = response['request_id'] if options.ondemand
|
69
|
+
response = service.wait_for_request(verbose, request_id) if options.ondemand
|
70
|
+
|
71
|
+
hosts = Utils.standardize_hostnames(response)
|
72
|
+
|
73
|
+
if options.json || options.ondemand
|
74
|
+
puts JSON.pretty_generate(hosts)
|
75
|
+
else
|
76
|
+
puts Utils.format_host_output(hosts)
|
77
|
+
end
|
66
78
|
end
|
67
79
|
end
|
68
80
|
|
@@ -78,6 +90,7 @@ class Vmfloaty
|
|
78
90
|
c.option '--url STRING', String, 'URL of pooler service'
|
79
91
|
c.action do |args, options|
|
80
92
|
verbose = options.verbose || config['verbose']
|
93
|
+
|
81
94
|
service = Service.new(options, config)
|
82
95
|
filter = args[0]
|
83
96
|
|
@@ -137,18 +150,18 @@ class Vmfloaty
|
|
137
150
|
hostname = args[0]
|
138
151
|
modify_all = options.all
|
139
152
|
|
140
|
-
if hostname.nil?
|
141
|
-
STDERR.puts
|
153
|
+
if hostname.nil? && !modify_all
|
154
|
+
STDERR.puts 'ERROR: Provide a hostname or specify --all.'
|
142
155
|
exit 1
|
143
156
|
end
|
144
|
-
running_vms = modify_all ? service.list_active(verbose) : hostname.split(
|
157
|
+
running_vms = modify_all ? service.list_active(verbose) : hostname.split(',')
|
145
158
|
|
146
159
|
tags = options.tags ? JSON.parse(options.tags) : nil
|
147
160
|
modify_hash = {
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
161
|
+
:lifetime => options.lifetime,
|
162
|
+
:disk => options.disk,
|
163
|
+
:tags => tags,
|
164
|
+
:reason => options.reason,
|
152
165
|
}
|
153
166
|
modify_hash.delete_if { |_, value| value.nil? }
|
154
167
|
|
@@ -165,11 +178,11 @@ class Vmfloaty
|
|
165
178
|
end
|
166
179
|
if ok
|
167
180
|
if modify_all
|
168
|
-
puts
|
181
|
+
puts 'Successfully modified all VMs.'
|
169
182
|
else
|
170
183
|
puts "Successfully modified VM #{hostname}."
|
171
184
|
end
|
172
|
-
puts
|
185
|
+
puts 'Use `floaty list --active` to see the results.'
|
173
186
|
end
|
174
187
|
end
|
175
188
|
end
|
@@ -177,9 +190,11 @@ class Vmfloaty
|
|
177
190
|
|
178
191
|
command :delete do |c|
|
179
192
|
c.syntax = 'floaty delete hostname,hostname2 [options]'
|
193
|
+
c.syntax += "\n floaty delete job1,job2 [options] (only supported with ABS)"
|
180
194
|
c.summary = 'Schedules the deletion of a host or hosts'
|
181
|
-
c.description = 'Given a comma separated list of hostnames, or --all for all vms, vmfloaty makes a request to the pooler service to schedule the deletion of those vms.'
|
195
|
+
c.description = 'Given a comma separated list of hostnames, or --all for all vms, vmfloaty makes a request to the pooler service to schedule the deletion of those vms. If you are using the ABS service, you can also pass in JobIDs here. Note that passing in a Job ID will delete *all* of the hosts in the job.' # rubocop:disable Layout/LineLength
|
182
196
|
c.example 'Schedules the deletion of a host or hosts', 'floaty delete myhost1,myhost2 --url http://vmpooler.example.com'
|
197
|
+
c.example 'Schedules the deletion of a JobID or JobIDs', 'floaty delete 1579300120799,1579300120800 --url http://abs.example.com'
|
183
198
|
c.option '--verbose', 'Enables verbose output'
|
184
199
|
c.option '--service STRING', String, 'Configured pooler service name'
|
185
200
|
c.option '--all', 'Deletes all vms acquired by a token'
|
@@ -199,15 +214,13 @@ class Vmfloaty
|
|
199
214
|
if delete_all
|
200
215
|
running_vms = service.list_active(verbose)
|
201
216
|
if running_vms.empty?
|
202
|
-
STDERR.puts
|
217
|
+
STDERR.puts 'You have no running VMs.'
|
203
218
|
else
|
204
219
|
Utils.pretty_print_hosts(verbose, service, running_vms)
|
205
220
|
# Confirm deletion
|
206
221
|
puts
|
207
222
|
confirmed = true
|
208
|
-
unless force
|
209
|
-
confirmed = agree('Delete all these VMs? [y/N]')
|
210
|
-
end
|
223
|
+
confirmed = agree('Delete all these VMs? [y/N]') unless force
|
211
224
|
if confirmed
|
212
225
|
response = service.delete(verbose, running_vms)
|
213
226
|
response.each do |hostname, result|
|
@@ -230,7 +243,7 @@ class Vmfloaty
|
|
230
243
|
end
|
231
244
|
end
|
232
245
|
else
|
233
|
-
STDERR.puts
|
246
|
+
STDERR.puts 'You did not provide any hosts to delete'
|
234
247
|
exit 1
|
235
248
|
end
|
236
249
|
|
@@ -296,9 +309,7 @@ class Vmfloaty
|
|
296
309
|
hostname = args[0]
|
297
310
|
snapshot_sha = args[1] || options.snapshot
|
298
311
|
|
299
|
-
if args[1] && options.snapshot
|
300
|
-
STDERR.puts "Two snapshot arguments were given....using snapshot #{snapshot_sha}"
|
301
|
-
end
|
312
|
+
STDERR.puts "Two snapshot arguments were given....using snapshot #{snapshot_sha}" if args[1] && options.snapshot
|
302
313
|
|
303
314
|
begin
|
304
315
|
revert_req = service.revert(verbose, hostname, snapshot_sha)
|
@@ -366,25 +377,23 @@ class Vmfloaty
|
|
366
377
|
|
367
378
|
begin
|
368
379
|
case action
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
STDERR.puts "Unknown action: #{action}"
|
387
|
-
exit 1
|
380
|
+
when 'get'
|
381
|
+
token = service.get_new_token(verbose)
|
382
|
+
puts token
|
383
|
+
when 'delete'
|
384
|
+
result = service.delete_token(verbose, options.token)
|
385
|
+
puts result
|
386
|
+
when 'status'
|
387
|
+
token_value = options.token
|
388
|
+
token_value = args[1] if token_value.nil?
|
389
|
+
status = service.token_status(verbose, token_value)
|
390
|
+
puts status
|
391
|
+
when nil
|
392
|
+
STDERR.puts 'No action provided'
|
393
|
+
exit 1
|
394
|
+
else
|
395
|
+
STDERR.puts "Unknown action: #{action}"
|
396
|
+
exit 1
|
388
397
|
end
|
389
398
|
rescue TokenError => e
|
390
399
|
STDERR.puts e
|
@@ -411,15 +420,13 @@ class Vmfloaty
|
|
411
420
|
use_token = !options.notoken
|
412
421
|
|
413
422
|
if args.empty?
|
414
|
-
STDERR.puts
|
423
|
+
STDERR.puts 'No operating systems provided to obtain. See `floaty ssh --help` for more information on how to get VMs.'
|
415
424
|
exit 1
|
416
425
|
end
|
417
426
|
|
418
427
|
host_os = args.first
|
419
428
|
|
420
|
-
if args.length > 1
|
421
|
-
STDERR.puts "Can't ssh to multiple hosts; Using #{host_os} only..."
|
422
|
-
end
|
429
|
+
STDERR.puts "Can't ssh to multiple hosts; Using #{host_os} only..." if args.length > 1
|
423
430
|
|
424
431
|
service.ssh(verbose, host_os, use_token)
|
425
432
|
exit 0
|
@@ -429,13 +436,13 @@ class Vmfloaty
|
|
429
436
|
command :completion do |c|
|
430
437
|
c.syntax = 'floaty completion [options]'
|
431
438
|
c.summary = 'Outputs path to completion script'
|
432
|
-
c.description = Utils.strip_heredoc(<<-
|
439
|
+
c.description = Utils.strip_heredoc(<<-DESCRIPTION)
|
433
440
|
Outputs path to a completion script for the specified shell (or 'bash' if not specified). This makes it easy to add the completion script to your profile:
|
434
441
|
|
435
442
|
source $(floaty completion --shell bash)
|
436
443
|
|
437
444
|
This subcommand will exit non-zero with an error message if no completion script is available for the requested shell.
|
438
|
-
|
445
|
+
DESCRIPTION
|
439
446
|
c.example 'Gets path to bash tab completion script', 'floaty completion --shell bash'
|
440
447
|
c.option '--shell STRING', String, 'Shell to request completion script for'
|
441
448
|
c.action do |_, options|
|