scli 0.0.3
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.
- data/MIT-LICENSE.txt +20 -0
- data/README.org +24 -0
- data/bin/scli +9 -0
- data/lib/formatters.rb +146 -0
- data/lib/generic.rb +99 -0
- data/lib/plugins/attach-volume.rb +29 -0
- data/lib/plugins/create-address.rb +22 -0
- data/lib/plugins/create-instance.rb +35 -0
- data/lib/plugins/create-key.rb +21 -0
- data/lib/plugins/create-volume.rb +31 -0
- data/lib/plugins/describe-address-offering.rb +15 -0
- data/lib/plugins/describe-address.rb +15 -0
- data/lib/plugins/describe-image.rb +20 -0
- data/lib/plugins/describe-instance-types.rb +35 -0
- data/lib/plugins/describe-instance.rb +18 -0
- data/lib/plugins/describe-key.rb +11 -0
- data/lib/plugins/describe-location.rb +11 -0
- data/lib/plugins/describe-vlan.rb +18 -0
- data/lib/plugins/describe-volume-offering.rb +14 -0
- data/lib/plugins/describe-volume.rb +18 -0
- data/lib/plugins/detach-volume.rb +29 -0
- data/lib/plugins/get-console-output.rb +20 -0
- data/lib/plugins/reboot.rb +23 -0
- data/lib/plugins/terminate-address.rb +19 -0
- data/lib/plugins/terminate-image.rb +19 -0
- data/lib/plugins/terminate-instance.rb +24 -0
- data/lib/plugins/terminate-key.rb +19 -0
- data/lib/plugins/terminate-volume.rb +24 -0
- data/lib/scli.rb +174 -0
- data/lib/validators.rb +56 -0
- data/scli.gemspec +22 -0
- metadata +143 -0
data/MIT-LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Sonian Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.org
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
* Scli
|
2
|
+
scli is a command line tool used to access and interface with IBM SmartCloud. It currently has support for creating, viewing and deleting instances, volumes, keys and addresses, etc.
|
3
|
+
|
4
|
+
** Documentation
|
5
|
+
Please run `scli help`
|
6
|
+
|
7
|
+
** Contributions
|
8
|
+
Please fork the project, make your commits and do a pull request.
|
9
|
+
|
10
|
+
** Configuration
|
11
|
+
You can either set ENV var's (IBM_SC_USERNAME and IBM_SC_PASSWORD)
|
12
|
+
|
13
|
+
OR
|
14
|
+
|
15
|
+
~/.scli/config.rb should contain:
|
16
|
+
|
17
|
+
ibm_username some@gmail.com
|
18
|
+
ibm_password mypassword
|
19
|
+
|
20
|
+
However if you run the tool without this file present it will prompt you for all the information.
|
21
|
+
|
22
|
+
** License
|
23
|
+
Scli is released under the [[https://github.com/sensu/sensu/blob/master/MIT-LICENSE.txt][MIT license]]. Copyright (c) 2012 Sonian Inc
|
24
|
+
|
data/bin/scli
ADDED
data/lib/formatters.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.word_for_title(string)
|
3
|
+
string.gsub("_"," ").gsub(/\w+/) do |word|
|
4
|
+
word.capitalize
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.format_table_titles(titles)
|
9
|
+
titles.collect do |title|
|
10
|
+
word_for_title(title.to_s).green
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.format_state(state)
|
15
|
+
case state
|
16
|
+
when "Active", "Attached", "Available"
|
17
|
+
state.green
|
18
|
+
when "Requesting", "Provisioning", "New"
|
19
|
+
state.yellow
|
20
|
+
else
|
21
|
+
state.red
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.format_is_default?(default)
|
26
|
+
default ? "True".green : "False".red
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.format_owner(owner)
|
30
|
+
(owner.size > 8) ? "#{owner[0..6]}.." : owner
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.format_name(name)
|
34
|
+
(name.size > 34) ? "#{name[0..32]}.." : name
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.format_description(description)
|
38
|
+
(description.size > 14) ? "#{description[0..12]}.." : description
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.format_capabilities(capable, full = false)
|
42
|
+
capabilities = capable.collect do |cap|
|
43
|
+
"#{cap['id']} => #{cap['entries']}" unless cap['entries'].size == 0 || cap.nil?
|
44
|
+
end
|
45
|
+
cap_print = capabilities.reject{|cap| cap.nil?}.join(",")
|
46
|
+
full ? cap_print : "#{cap_print[0..12]}.."
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.format_ip(ip)
|
50
|
+
return "NA".red if ip.nil? || ip == ""
|
51
|
+
first_octet = ip.split(".").first
|
52
|
+
first_octet == "10" ? ip.cyan : ip.magenta
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.format_instance_id(instance_id)
|
56
|
+
if instance_id.class == String
|
57
|
+
(instance_id.nil? || instance_id.to_s == "0") ? "Detached".red : instance_id.green
|
58
|
+
elsif instance_id.nil?
|
59
|
+
"NA".red
|
60
|
+
else
|
61
|
+
instance_id.join(",")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.format_type(instance_type)
|
66
|
+
instance_type.to_s.split(".").first
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.format_image_instance_types(instance_types, single = false)
|
70
|
+
supported_types = []
|
71
|
+
instance_types.each do |it|
|
72
|
+
supported_types << ((single) ? it.id : format_type(it.id))
|
73
|
+
end
|
74
|
+
(single ? supported_types.join("\n") : supported_types.join(","))
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.format_size(vol_size)
|
78
|
+
if vol_size.to_i > 1024
|
79
|
+
"#{vol_size.to_i / 1024}TB"
|
80
|
+
else
|
81
|
+
"#{vol_size}GB"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.format_location(location)
|
86
|
+
case location.to_i
|
87
|
+
when 41
|
88
|
+
"Raleigh"
|
89
|
+
when 61
|
90
|
+
"Ehningen"
|
91
|
+
when 82
|
92
|
+
"Boulder"
|
93
|
+
when 101
|
94
|
+
"Markham"
|
95
|
+
when 121
|
96
|
+
"Makuhari"
|
97
|
+
when 141
|
98
|
+
"Singapore"
|
99
|
+
else
|
100
|
+
location
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.process_data_to_format(object, data_to_print, single = false)
|
105
|
+
print_array = []
|
106
|
+
data_to_print.each do |data|
|
107
|
+
print_array << case data.to_s
|
108
|
+
when /state/
|
109
|
+
format_state(object.send(data))
|
110
|
+
when /supported_instance_types/
|
111
|
+
single ? format_image_instance_types(object.send(data), true) : format_image_instance_types(object.send(data))
|
112
|
+
when /capabilities/
|
113
|
+
single ? format_capabilities(object.send(data), true) : format_capabilities(object.send(data))
|
114
|
+
when /default/
|
115
|
+
format_is_default?(object.send(data))
|
116
|
+
when /owner/
|
117
|
+
single ? object.send(data) : format_owner(object.send(data))
|
118
|
+
when /name/
|
119
|
+
format_name(object.send(data))
|
120
|
+
when /description/
|
121
|
+
single ? object.send(data) : format_description(object.send(data))
|
122
|
+
when "ip"
|
123
|
+
format_ip(object.send(data))
|
124
|
+
when /volume_ids/
|
125
|
+
object.send(data).join(",")
|
126
|
+
when /instance_id/
|
127
|
+
format_instance_id(object.send(data))
|
128
|
+
when /public_key/
|
129
|
+
format_description(object.send(data))
|
130
|
+
when /type/
|
131
|
+
if object.send(data).class == String
|
132
|
+
format_type(object.send(data))
|
133
|
+
else
|
134
|
+
object.send(data)
|
135
|
+
end
|
136
|
+
when /size/
|
137
|
+
format_size(object.send(data))
|
138
|
+
when /location/
|
139
|
+
format_location(object.send(data))
|
140
|
+
else
|
141
|
+
object.send(data)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
print_array
|
145
|
+
end
|
146
|
+
end
|
data/lib/generic.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
module Scli
|
2
|
+
class Compute
|
3
|
+
def initialize(options={})
|
4
|
+
cli_opts = Scli.options
|
5
|
+
cli_opts.merge!(options)
|
6
|
+
ibm_user = (Scli.env_populated?) ? ENV['IBM_SC_USERNAME'] : cli_opts[:ibm_username]
|
7
|
+
ibm_pass = (Scli.env_populated?) ? ENV['IBM_SC_PASSWORD'] : cli_opts[:ibm_password]
|
8
|
+
@fog_compute = Fog::Compute.new(:ibm_username => ibm_user, :ibm_password => ibm_pass, :provider => 'IBM')
|
9
|
+
end
|
10
|
+
|
11
|
+
def method_missing(method, *args, &block)
|
12
|
+
@fog_compute.send(method, *args, &block)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Storage
|
17
|
+
def initialize(options={})
|
18
|
+
cli_opts = Scli.options
|
19
|
+
cli_opts.merge!(options)
|
20
|
+
ibm_user = (Scli.env_populated?) ? ENV['IBM_SC_USERNAME'] : cli_opts[:ibm_username]
|
21
|
+
ibm_pass = (Scli.env_populated?) ? ENV['IBM_SC_PASSWORD'] : cli_opts[:ibm_password]
|
22
|
+
@fog_storage = Fog::Storage.new(:ibm_username => ibm_user, :ibm_password => ibm_pass, :provider => 'IBM')
|
23
|
+
end
|
24
|
+
|
25
|
+
def method_missing(method, *args, &block)
|
26
|
+
@fog_storage.send(method, *args, &block)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.config_file_exists?(config_file_path)
|
31
|
+
File.exists?(File.expand_path(config_file_path))
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.generate_config_file(config_file_path)
|
35
|
+
puts "Config file #{config_file_path} does not exist, let's create it."
|
36
|
+
puts "What is your IBM SC Username?"
|
37
|
+
ibm_username = $stdin.gets
|
38
|
+
puts "What is your IBM SC Password?"
|
39
|
+
ibm_password = $stdin.gets
|
40
|
+
Dir.mkdir(File.expand_path(File.dirname(config_file_path))) unless File.exists?(File.expand_path(File.dirname(config_file_path)))
|
41
|
+
ibm_config = File.open(File.expand_path(config_file_path), "w")
|
42
|
+
ibm_config.puts "ibm_username #{ibm_username}"
|
43
|
+
ibm_config.puts "ibm_password #{ibm_password}"
|
44
|
+
ibm_config.close
|
45
|
+
puts "Config file written."
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.print_object(title, objects, data_to_print, options = {})
|
49
|
+
table_to_print = []
|
50
|
+
if objects.methods.include?(:each) # Its not a single object
|
51
|
+
title = title + "(#{objects.count})"
|
52
|
+
objects.each do |object|
|
53
|
+
table_to_print << process_data_to_format(object, data_to_print)
|
54
|
+
table_to_print << :separator if options[:separator]
|
55
|
+
end
|
56
|
+
else
|
57
|
+
table_to_print << process_data_to_format(objects, data_to_print, true)
|
58
|
+
end
|
59
|
+
table = Terminal::Table.new :title => title.cyan, :headings => format_table_titles(data_to_print), :rows => table_to_print
|
60
|
+
puts table
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.print_volumes(volumes)
|
64
|
+
print_object("Volumes", volumes, [:id, :name, :size, :instance_id, :owner, :format, :location_id, :offering_id, :created_at, :state])
|
65
|
+
if volumes.class.to_s == "Fog::Storage::IBM::Volumes"
|
66
|
+
total_vol_size = 0
|
67
|
+
volumes.each do |vol|
|
68
|
+
next if vol.size.nil?
|
69
|
+
total_vol_size += vol.size.to_i
|
70
|
+
end
|
71
|
+
puts "Total #{(total_vol_size.to_i / 1024.0).round(2)}Tb of storage"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.print_servers(servers)
|
76
|
+
print_object("Servers", servers, [:id, :name, :ip, :owner, :vlan_id, :volume_ids, :instance_type, :launched_at, :location_id, :state])
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.opt_merge(options, name, data)
|
80
|
+
options.merge!({name => data}) unless data.nil?
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.env_populated?
|
84
|
+
(ENV['IBM_SC_USERNAME'].nil? || ENV['IBM_SC_PASSWORD'].nil?) ? false : (!ENV['IBM_SC_USERNAME'].empty? && !ENV['IBM_SC_PASSWORD'].empty?)
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.read_config(config_file_path)
|
88
|
+
options = {}
|
89
|
+
if File.exists?(config_file_path)
|
90
|
+
config_file = File.open(config_file_path,'r')
|
91
|
+
config_file.each_line do |row|
|
92
|
+
option, data = row.split
|
93
|
+
options[option.to_sym] = data
|
94
|
+
end
|
95
|
+
end
|
96
|
+
options
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.attvol
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
volume_id = cli.config[:volume_id]
|
6
|
+
instance_id = cli.config[:instance_id]
|
7
|
+
if volume_id.nil? || instance_id.nil?
|
8
|
+
puts "Instance and volume id's are required, please retry."
|
9
|
+
else
|
10
|
+
server = Scli::Compute.new.servers.get(instance_id)
|
11
|
+
volume = Scli::Storage.new.volumes.get(volume_id)
|
12
|
+
if server.nil?
|
13
|
+
puts "Could not find server: #{instance_id}"
|
14
|
+
elsif volume.nil?
|
15
|
+
puts "Could not find volume: #{volume_id}"
|
16
|
+
else
|
17
|
+
if server.attach(volume_id.to_i) # Note: attach() takes a string, not an object
|
18
|
+
print_volumes(volume)
|
19
|
+
puts "Is being attached to instance:".red
|
20
|
+
print_servers(server)
|
21
|
+
else
|
22
|
+
puts "Volume could not be attached for some reason..."
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
PLUGINS << ["attvol", "attach-volume", "Volume ID (Req -v), Instance ID (Req -i)", "scli attvol -i 123456 -v 23456"]
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.cadd
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
offering_id = cli.config[:offering_id]
|
6
|
+
location_id = cli.config[:location_id]
|
7
|
+
vlan_id = cli.config[:vlan_id]
|
8
|
+
if offering_id.nil? || location_id.nil?
|
9
|
+
puts "No offering and or location id was found, please retry"
|
10
|
+
else
|
11
|
+
options = vlan_id.nil? ? {} : {:vlan_id => vlan_id}
|
12
|
+
response = Scli::Compute.new.create_address(location_id, offering_id, options)
|
13
|
+
if response.status == 200
|
14
|
+
puts "IP Created successfully: #{response.body.inspect}"
|
15
|
+
else
|
16
|
+
puts "Failed with #{response.status} error of: #{response.body.inspect}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
PLUGINS << ["cadd", "create-address", "Location ID (Req -l), Offering ID (Req -o), Vlan ID (Opt -V)", "scli cadd -o 20025212 -l 41 (-V XX)"]
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.cin
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
name = cli.config[:name]
|
6
|
+
image_id = cli.config[:image_id]
|
7
|
+
instance_type = cli.config[:instance_type]
|
8
|
+
location_id = cli.config[:location_id]
|
9
|
+
#Optional args
|
10
|
+
opts = {}
|
11
|
+
opt_merge(opts, :key_name, cli.config[:key_id])
|
12
|
+
opt_merge(opts, :ip, cli.config[:address_id])
|
13
|
+
opt_merge(opts, :volume_id, cli.config[:volume_id])
|
14
|
+
opt_merge(opts, :vlan_id, cli.config[:vlan_id])
|
15
|
+
opt_merge(opts, :secondary_ip, cli.config[:secondary_address_id])
|
16
|
+
opt_merge(opts, :is_mini_ephemeral, cli.config[:mini_ephemeral])
|
17
|
+
opt_merge(opts, :configuration_data, cli.config[:configuration_data])
|
18
|
+
opt_merge(opts, :anti_collocation_instance, cli.config[:anti_colo])
|
19
|
+
|
20
|
+
if name.nil? || location_id.nil? || image_id.nil? || instance_type.nil?
|
21
|
+
puts "Missing one of the following (name, location_id, image_id OR instance_type)."
|
22
|
+
else
|
23
|
+
response = Scli::Compute.new.create_instance(name, image_id, instance_type, location_id, opts)
|
24
|
+
if response.status == 200
|
25
|
+
puts "Instance Created successfully: #{response.body.inspect}"
|
26
|
+
else
|
27
|
+
puts "Failed with #{response.status} error of: #{response.body.inspect}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
PLUGINS << :separator
|
34
|
+
PLUGINS << ["cin", "create-instance", "Name (Req -n), Image ID (Req -m), Instance Type (Req -t), Location ID (Req -l),\nKey name (Req if linux -k), Addr id eth0 (Opt -a), Addr id eth1 (Opt -A),\nVlan ID (Opt -V), Volume ID (Opt -v), Mini Ephemeral (Opt --mini),\nAnti Colo (Opt --anti-colo), Img Config (Opt --config-data)", "scli cin -n 'new_inst' -i 345678 -t 'COP32.1/2048/60' -l 41"]
|
35
|
+
PLUGINS << :separator
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.ckey
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
name = cli.config[:name]
|
6
|
+
if name.nil?
|
7
|
+
puts "You must provide a name for the key."
|
8
|
+
else
|
9
|
+
response = Scli::Compute.new.create_key(name) #Note: This method can take a pub key too, not supported yet.
|
10
|
+
if response.status == 200
|
11
|
+
puts "Key Created successfully... Copy private key to a safe location."
|
12
|
+
puts "Key name: #{response.body['keyName']}"
|
13
|
+
puts "Key Contents:\n #{response.body['keyMaterial']}"
|
14
|
+
else
|
15
|
+
puts "Failed with #{response.status} error of: #{response.body.inspect}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
PLUGINS << ["ckey", "create-key", "Key Name (Req -n)", "scli ckey -n my_new_keypair"]
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.cvol
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
offering_id = cli.config[:offering_id]
|
6
|
+
location_id = cli.config[:location_id]
|
7
|
+
format = cli.config[:format]
|
8
|
+
size = cli.config[:size]
|
9
|
+
name = cli.config[:name]
|
10
|
+
|
11
|
+
if offering_id.nil?
|
12
|
+
puts "You did not provide an offering id, using a generic id of 20035200."
|
13
|
+
offering_id = 20035200
|
14
|
+
end
|
15
|
+
|
16
|
+
if format.nil? || name.nil? || size.nil? || location_id.nil? || offering_id.nil?
|
17
|
+
puts "Missing offering_id or location_id or format or size or name, please retry."
|
18
|
+
else
|
19
|
+
if volume_format_valid?(format) && volume_size_valid?(size) && volume_offering_valid?(offering_id)
|
20
|
+
response = Scli::Storage.new.create_volume(name, offering_id, format, location_id, size)
|
21
|
+
if response.status == 200
|
22
|
+
puts "Volume Created successfully: #{response.body.inspect}"
|
23
|
+
else
|
24
|
+
puts "Failed with #{response.status} error of: #{response.body.inspect}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
PLUGINS << ["cvol", "create-volume", "Name (Req -n), Offering ID (Req -o), Format (Req -f), Location ID (Req -l), Size (Req -s)", "scli cvol -n 'new_vol' -o 342 -f EXT3 -l 41 -s 1024"]
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.daddoff
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
addresses = Scli::Compute.new.list_address_offerings.body['addresses']
|
6
|
+
table_to_print = addresses.collect do |offering|
|
7
|
+
[offering['id'], offering['ipType'], offering['location'], offering['price']['rate'], offering['price']['countryCode'], offering['price']['currencyCode']]
|
8
|
+
end
|
9
|
+
table = Terminal::Table.new :title => "IP Address Offerings (#{addresses.count})".cyan, :headings => ["id".green, "IpType".green, "location".green, "price rate".green, "price country".green, "price currency".green], :rows => table_to_print
|
10
|
+
puts table
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
PLUGINS << ["daddoff", "describe-address-offerings", "", "scli daddoff, scli describe-address-offerings"]
|
15
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.dadd
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
address_id = cli.config[:address_id] || ARGV[1]
|
6
|
+
if address_id.nil? || is_address_id?(address_id)
|
7
|
+
addresses = (address_id.nil?) ? Scli::Compute.new.addresses : Scli::Compute.new.addresses.get(address_id)
|
8
|
+
print_object("Addresses", addresses, [:id, :location, :ip, :state, :instance_id, :hostname, :mode, :owner])
|
9
|
+
else
|
10
|
+
puts "Got an invalid address id, please retry."
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
PLUGINS << ["dadd", "describe-address, describe-addresses", "Address ID (Opt -a)", "scli dadd -a 345313, scli describe-address 345313"]
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.dim
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
image_id = cli.config[:image_id] || yield_regular_input(ARGV[1])
|
6
|
+
private_imgs = cli.config[:private]
|
7
|
+
if image_id.nil?
|
8
|
+
images = private_imgs ? Scli::Compute.new.images.reject{|img| img.visibility != "PRIVATE"} : Scli::Compute.new.images
|
9
|
+
print_object("Images", images, [:id, :name, :architecture, :platform, :visibility, :supported_instance_types, :description, :location, :owner, :created_at, :state])
|
10
|
+
else
|
11
|
+
if is_image_id?(image_id)
|
12
|
+
print_object("Image", Scli::Compute.new.images.get(image_id), [:id, :name, :architecture, :platform, :visibility, :supported_instance_types, :description, :location, :owner, :created_at, :state])
|
13
|
+
else
|
14
|
+
puts "Image id provided is invalid"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
PLUGINS << ["dim", "describe-image, describe-images", "Image ID (Opt -m), Private Only (Opt -p)", "scli dim -m 34567, scli describe-image 34567"]
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.dint
|
3
|
+
instance_types = []
|
4
|
+
|
5
|
+
instance_types << "COP32.1/2048/60"
|
6
|
+
instance_types << "BRZ32.1/2048/60*175"
|
7
|
+
instance_types << "SLV32.2/4096/60*350"
|
8
|
+
instance_types << "GLD32.4/4096/60*350"
|
9
|
+
|
10
|
+
instance_types << "COP64.2/4096/60"
|
11
|
+
instance_types << "BRZ64.2/4096/60*500*350"
|
12
|
+
instance_types << "SLV64.4/8192/60*500*500"
|
13
|
+
instance_types << "GLD64.8/16384/60*500*500"
|
14
|
+
instance_types << "PLT64.16/16384/60*500*500*500*500"
|
15
|
+
|
16
|
+
table_to_print = []
|
17
|
+
|
18
|
+
instance_types.each do |inst_type|
|
19
|
+
name, ram, disks = inst_type.split("/")
|
20
|
+
color = name.slice!(0..2)
|
21
|
+
bits, cpus = name.split(".")
|
22
|
+
disk = disks.split("*")
|
23
|
+
total_ephemeral_size = disk.inject{|sum,x| sum.to_i + x.to_i }
|
24
|
+
total_ephemeral_non_root = (disk.count > 1) ? (disk.drop(1).inject{|sum,x| sum.to_i + x.to_i }) : 0
|
25
|
+
total_ephemeral_devices = (disk.count > 1) ? (disk.drop(1).count) : 0
|
26
|
+
table_to_print << [inst_type, color, bits, cpus, ram, total_ephemeral_size, total_ephemeral_non_root, total_ephemeral_devices]
|
27
|
+
end
|
28
|
+
|
29
|
+
table = Terminal::Table.new :title => "Instance Types".cyan, :headings => ["id".green, "color".green, "bits".green, "CPU(s)".green, "RAM".green, "Total Ephemeral".green, "Total Ephemeral (Non-Root)".green, "Ephemeral devices (Non-Root)".green], :rows => table_to_print
|
30
|
+
puts table
|
31
|
+
puts "Note: This table is not from an API, its simply a helper for the non-rememberable naming IBM gives their instances - List may update/change."
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
PLUGINS << ["dint", "describe-instance-types", "", "scli dint"]
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.din
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
instance_id = cli.config[:instance_id] || ARGV[1]
|
6
|
+
if instance_id.nil?
|
7
|
+
print_servers(Scli::Compute.new.servers)
|
8
|
+
else
|
9
|
+
if is_instance_id?(instance_id)
|
10
|
+
print_servers(Scli::Compute.new.servers.get(instance_id))
|
11
|
+
else
|
12
|
+
puts "Instance id provided is invalid"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
PLUGINS << ["din", "describe-instances, describe-instance", "Instance ID (Opt -i)", "scli din, scli din 123456"]
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.dkey
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
key_id = cli.config[:key_id] || ARGV[1]
|
6
|
+
keys = key_id.nil? ? Scli::Compute.new.keys : Scli::Compute.new.keys.get(key_id)
|
7
|
+
print_object("Keys", keys, [:name, :default, :public_key, :instance_ids, :modified_at])
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
PLUGINS << ["dkey", "describe-key, describe-keys", "Key ID (Opt -k)", "scli dkey -k 345678, scli describe-key 345678"]
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.dloc
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
location_id = cli.config[:location_id] || ARGV[1]
|
6
|
+
locations = location_id.nil? ? Scli::Compute.new.locations : Scli::Compute.new.locations.get(location_id)
|
7
|
+
print_object("Locations", locations, [:id, :name, :location, :capabilities, :description])
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
PLUGINS << ["dloc", "describe-location, describe-locations", "Location ID (Opt -l)", "scli dloc -l 345, scli describe-location 345"]
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.dvlan
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
vlan_id = cli.config[:vlan_id] || ARGV[1]
|
6
|
+
if vlan_id.nil?
|
7
|
+
print_object("VLANs", Scli::Compute.new.vlans, [:id, :name, :location])
|
8
|
+
else
|
9
|
+
if is_vlan_id?(vlan_id)
|
10
|
+
print_object("VLANs", Scli::Compute.new.vlans.get(vlan_id), [:id, :name, :location])
|
11
|
+
else
|
12
|
+
puts "Got an invalid VLAN id, please retry."
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
PLUGINS << ["dvlan", "describe-vlan, describe-vlans", "Vlan ID (Opt -V)", "scli dvlan -V 345, scli describe-vlan 345"]
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.dvoloff
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
offerings = Scli::Storage.new.list_offerings.body['volumes']
|
6
|
+
table_to_print = offerings.collect do |offering|
|
7
|
+
[offering['id'], offering['name'], format_location(offering['location']), offering['price']['rate'], offering['price']['currencyCode'], offering['price']['unitOfMeasure'], offering['formats'].collect{|format| format['id']}.join(","), offering['capacity']]
|
8
|
+
end
|
9
|
+
table = Terminal::Table.new :title => "Volume Offerings (#{offerings.count})".cyan, :headings => ["id".green, "Name".green, "location".green, "price rate".green, "price currency".green, "Price Measure".green, "Formats".green, "Capacity".green], :rows => table_to_print
|
10
|
+
puts table
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
PLUGINS << ["dvoloff", "describe-volume-offerings", "", "scli dvoloff"]
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.dvol
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
volume_id = cli.config[:volume_id] || ARGV[1]
|
6
|
+
if volume_id.nil?
|
7
|
+
print_volumes(Scli::Storage.new.volumes)
|
8
|
+
else
|
9
|
+
if is_volume_id?(volume_id)
|
10
|
+
print_volumes(Scli::Storage.new.volumes.get(volume_id))
|
11
|
+
else
|
12
|
+
puts "Volume id provided is invalid"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
PLUGINS << ["dvol", "describe-volume, describe-volumes", "Volume ID (Opt -v)", "scli dvol 23456"]
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.detvol
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
volume_id = cli.config[:volume_id]
|
6
|
+
instance_id = cli.config[:instance_id]
|
7
|
+
if volume_id.nil? || instance_id.nil?
|
8
|
+
puts "Instance and volume id's are required, please retry."
|
9
|
+
else
|
10
|
+
server = Scli::Compute.new.servers.get(instance_id)
|
11
|
+
volume = Scli::Storage.new.volumes.get(volume_id)
|
12
|
+
if server.nil?
|
13
|
+
puts "Could not find server: #{instance_id}"
|
14
|
+
elsif volume.nil?
|
15
|
+
puts "Could not find volume: #{volume_id}"
|
16
|
+
else
|
17
|
+
if server.detach(volume_id) # Note: detach() takes a string, not an object
|
18
|
+
print_volumes(volume)
|
19
|
+
puts "Is being detached from instance:".red
|
20
|
+
print_servers(server)
|
21
|
+
else
|
22
|
+
puts "Volume could not be detached for some reason..."
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
PLUGINS << ["detvol", "detach-volume", "Volume ID (Req -v), Instance ID (Req -i)", "scli detvol -i 123456 -v 23456"]
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.gco
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
instance_id = cli.config[:instance_id] || yield_regular_input(ARGV[1])
|
6
|
+
if instance_id.nil? || !is_instance_id?(instance_id)
|
7
|
+
puts "An invalid instance id was provided."
|
8
|
+
else
|
9
|
+
response = Scli::Compute.new.get_instance_logs(instance_id)
|
10
|
+
if response.status == 200
|
11
|
+
puts "Console log output:"
|
12
|
+
puts "#{response.body['logs'].join("\n")}"
|
13
|
+
else
|
14
|
+
puts "Failed with #{response.status} error of: #{response.body.inspect}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
PLUGINS << ["gco", "get-console-output", "Instance ID (Req -i)", "scli gco 123456"]
|
20
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.reboot
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
instance_id = cli.config[:instance_id] || ARGV[1]
|
6
|
+
if instance_id.nil? || !is_instance_id?(instance_id)
|
7
|
+
puts "Instance id provided is invalid"
|
8
|
+
else
|
9
|
+
server = Scli::Compute.new.servers.get(instance_id)
|
10
|
+
if server.nil?
|
11
|
+
puts "Server could not be found, check instance_id and state to ensure it can be rebooted..."
|
12
|
+
else
|
13
|
+
if server.reboot
|
14
|
+
puts "Reboot successful..."
|
15
|
+
else
|
16
|
+
puts "Reboot failed, check instance_id and state to ensure it can be rebooted..."
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
PLUGINS << ["reboot", "", "Instance ID (Req -i)", "scli reboot 123456"]
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.tad
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
address_id = cli.config[:address_id] || ARGV[1]
|
6
|
+
if address_id.nil? || !is_address_id?(address_id)
|
7
|
+
puts "Address id provided is invalid"
|
8
|
+
else
|
9
|
+
response = Scli::Compute.new.delete_address(address_id)
|
10
|
+
if response.status == 200
|
11
|
+
puts "Address successfully terminated: #{response.body.inspect}"
|
12
|
+
else
|
13
|
+
puts "Address terminated failed #{response.status} with #{response.body.inspect}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
PLUGINS << ["tad", "terminate-address", "Address ID (Req -a)", "scli tad 200001"]
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.tim
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
image_id = cli.config[:image_id] || ARGV[1]
|
6
|
+
if image_id.nil? || !is_image_id?(image_id)
|
7
|
+
puts "Image id provided is invalid"
|
8
|
+
else
|
9
|
+
response = Scli::Compute.new.delete_image(image_id)
|
10
|
+
if response.status == 200
|
11
|
+
puts "Image successfully terminated: #{response.body.inspect}"
|
12
|
+
else
|
13
|
+
puts "Image terminated failed #{response.status} with #{response.body.inspect}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
PLUGINS << ["tim", "terminate-image", "Image ID (Req -m)", "scli tim 200001"]
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.tin
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
instance_id = cli.config[:instance_id] || ARGV[1]
|
6
|
+
if instance_id.nil? || !is_instance_id?(instance_id)
|
7
|
+
puts "Instance id provided is invalid"
|
8
|
+
else
|
9
|
+
server = Scli::Compute.new.servers.get(instance_id)
|
10
|
+
if server.nil?
|
11
|
+
puts "Could not find server #{instance_id}, please check instance_id and state and retry."
|
12
|
+
else
|
13
|
+
if server.destroy
|
14
|
+
print_server(server)
|
15
|
+
puts "Is being destroyed...".red
|
16
|
+
else
|
17
|
+
puts "Could not destroy server #{instance_id}, please check instance_id and state and retry."
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
PLUGINS << ["tin", "terminate-instance", "Instance ID (Req -i)", "scli tin 123456"]
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.tkey
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
name = cli.config[:name] || yield_regular_input(ARGV[1])
|
6
|
+
if name.nil?
|
7
|
+
puts "Key name not provided"
|
8
|
+
else
|
9
|
+
response = Scli::Compute.new.delete_key(name)
|
10
|
+
if response.status == 200
|
11
|
+
puts "Key successfully terminated: #{response.body.inspect}"
|
12
|
+
else
|
13
|
+
puts "Key termination failed #{response.status} with #{response.body.inspect}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
PLUGINS << ["tkey", "terminate-key", "Name (Req -n)", "scli tkey 200001"]
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.delvol
|
3
|
+
cli = MyCLI.new
|
4
|
+
cli.parse_options
|
5
|
+
volume_id = cli.config[:volume_id] || ARGV[1]
|
6
|
+
if volume_id.nil? || !is_volume_id?(volume_id)
|
7
|
+
puts "Volume ID is either missing or invalid, please retry."
|
8
|
+
else
|
9
|
+
volume = Scli::Storage.new.volumes.get(volume_id)
|
10
|
+
if volume.nil?
|
11
|
+
puts "Could not find volume: #{volume_id}"
|
12
|
+
else
|
13
|
+
if volume.destroy
|
14
|
+
print_volume(volume)
|
15
|
+
puts "Is being destroyed...".red
|
16
|
+
else
|
17
|
+
puts "Volume could not be destroyed for some reason..."
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
PLUGINS << ["delvol", "delete-volume,terminate-volume", "Volume ID (Req -v)", "scli delvol -v 23456, scli delvol 23456"]
|
data/lib/scli.rb
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'mixlib/cli'
|
3
|
+
require 'fog'
|
4
|
+
require 'colored'
|
5
|
+
require 'terminal-table'
|
6
|
+
require 'validators'
|
7
|
+
require 'formatters'
|
8
|
+
require 'generic'
|
9
|
+
|
10
|
+
PLUGINS = []
|
11
|
+
|
12
|
+
class MyCLI
|
13
|
+
include Mixlib::CLI
|
14
|
+
|
15
|
+
option :config_file,
|
16
|
+
:short => "-C CONFIG",
|
17
|
+
:long => "--config CONFIG",
|
18
|
+
:default => '~/.scli/config.rb',
|
19
|
+
:description => "The configuration file to use"
|
20
|
+
|
21
|
+
option :address_id,
|
22
|
+
:short => "-a ADDRESS",
|
23
|
+
:long => "--address-id ADDRESS",
|
24
|
+
:description => "IP Address ID to use"
|
25
|
+
|
26
|
+
option :instance_id,
|
27
|
+
:short => "-i INSTANCE",
|
28
|
+
:long => "--instance-id INSTANCE",
|
29
|
+
:description => "Instance ID to use"
|
30
|
+
|
31
|
+
option :volume_id,
|
32
|
+
:short => "-v VOLUME",
|
33
|
+
:long => "--volume-id VOLUME",
|
34
|
+
:description => "Volume ID to use"
|
35
|
+
|
36
|
+
option :instance_type,
|
37
|
+
:short => "-t TYPE",
|
38
|
+
:long => "--instance-type TYPE",
|
39
|
+
:description => "Instance Type (e.g. COP32.1/2048/60)"
|
40
|
+
|
41
|
+
option :image_id,
|
42
|
+
:short => "-m IMAGE",
|
43
|
+
:long => "--image-id IMAGE",
|
44
|
+
:description => "Image ID to use"
|
45
|
+
|
46
|
+
option :key_id,
|
47
|
+
:short => "-k IMAGE",
|
48
|
+
:long => "--key-id KEY",
|
49
|
+
:description => "Key ID to use"
|
50
|
+
|
51
|
+
option :offering_id,
|
52
|
+
:short => "-o OFFERING",
|
53
|
+
:long => "--offering-id OFFERING",
|
54
|
+
:description => "Offering ID to use"
|
55
|
+
|
56
|
+
option :vlan_id,
|
57
|
+
:short => "-V VLAN",
|
58
|
+
:long => "--vlan-id VLAN",
|
59
|
+
:description => "Vlan ID to use"
|
60
|
+
|
61
|
+
option :location_id,
|
62
|
+
:short => "-l LOCATION",
|
63
|
+
:long => "--location-id LOCATION",
|
64
|
+
:description => "Location ID to use"
|
65
|
+
|
66
|
+
option :name,
|
67
|
+
:short => "-n NAME",
|
68
|
+
:long => "--name NAME",
|
69
|
+
:description => "Name to use"
|
70
|
+
|
71
|
+
option :size,
|
72
|
+
:short => "-s SIZE",
|
73
|
+
:long => "--size SIZE",
|
74
|
+
:description => "Size to use"
|
75
|
+
|
76
|
+
option :format,
|
77
|
+
:short => "-f FORMAT",
|
78
|
+
:long => "--format FORMAT",
|
79
|
+
:description => "Format to use (ext3, raw)"
|
80
|
+
|
81
|
+
option :private,
|
82
|
+
:short => "-p",
|
83
|
+
:long => "--private",
|
84
|
+
:boolean => true,
|
85
|
+
:description => "Only show private images, etc"
|
86
|
+
|
87
|
+
option :mini_ephemeral,
|
88
|
+
:long => "--mini",
|
89
|
+
:boolean => true,
|
90
|
+
:description => "(Create instance only) Set mini ephemeral)"
|
91
|
+
|
92
|
+
option :configuration_data,
|
93
|
+
:long => "--config-data DATA",
|
94
|
+
:description => "(Create instance only) Extra config data required by image"
|
95
|
+
|
96
|
+
option :anti_colo,
|
97
|
+
:long => "--anti-colo INST_ID",
|
98
|
+
:description => "(Create instance only) Instance ID to anti-colo against"
|
99
|
+
|
100
|
+
option :secondary_address_id,
|
101
|
+
:short => "-A SADDRESS",
|
102
|
+
:long => "--secondary-address-id SADDRESS",
|
103
|
+
:description => "(Create instance only) IP To use for eth1"
|
104
|
+
|
105
|
+
option :help,
|
106
|
+
:short => "-h",
|
107
|
+
:long => "--help",
|
108
|
+
:description => "SCLI Help",
|
109
|
+
:on => :tail,
|
110
|
+
:boolean => true,
|
111
|
+
:show_options => true,
|
112
|
+
:exit => 0
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
module Scli
|
117
|
+
def self.options
|
118
|
+
cli = MyCLI.new
|
119
|
+
cli.parse_options
|
120
|
+
cli.config.merge!(read_config(File.expand_path(cli.config[:config_file])) || {})
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
module Scli
|
125
|
+
class Main
|
126
|
+
def self.run
|
127
|
+
cli = MyCLI.new
|
128
|
+
cli.parse_options
|
129
|
+
|
130
|
+
Scli.generate_config_file(cli.config[:config_file]) unless Scli.config_file_exists?(cli.config[:config_file]) || Scli.env_populated?
|
131
|
+
|
132
|
+
Dir.glob("#{File.dirname(__FILE__)}/plugins/*").each do |plugin|
|
133
|
+
require plugin
|
134
|
+
end
|
135
|
+
|
136
|
+
help_table = Terminal::Table.new :title => "Help", :headings => ["Command", "Aliases", "Arguments", "Examples"], :rows => PLUGINS
|
137
|
+
|
138
|
+
#
|
139
|
+
# every array in plugins contains the main command [0], comma seperated command aliases [1], options [2] and examples [3]. So we match on [0] or [1] below.
|
140
|
+
#
|
141
|
+
begin
|
142
|
+
plugin_executed = false
|
143
|
+
PLUGINS.each do |plugin|
|
144
|
+
commands = [plugin[0]] + plugin[1].split(",")
|
145
|
+
if commands.include?(ARGV[0])
|
146
|
+
Scli.send(plugin[0])
|
147
|
+
plugin_executed = true
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
unless plugin_executed || !ARGV[0] == "help"
|
152
|
+
puts help_table
|
153
|
+
puts "\n Run scli -h to get CLI Args"
|
154
|
+
end
|
155
|
+
|
156
|
+
rescue Excon::Errors::InternalServerError => e
|
157
|
+
puts "Got an internal server error while trying to talk to IBM: #{e.response.body}"
|
158
|
+
rescue Excon::Errors::PreconditionFailed => e
|
159
|
+
puts "A precondition failed while trying to do our API Request: #{e.response.body}"
|
160
|
+
rescue Excon::Errors::SocketError => e
|
161
|
+
puts "Could not connect to IBM: #{e}"
|
162
|
+
rescue Excon::Errors::Unauthorized => e
|
163
|
+
puts "You were not authorized to access a resource, Are you sure its owned by the account in your config file? -- #{e.response.body}"
|
164
|
+
rescue Exception => e
|
165
|
+
if e.methods.include?(:response)
|
166
|
+
puts "Fog API Took an exception while speaking to IBM: #{e.response.body}"
|
167
|
+
else
|
168
|
+
puts "Took an exception, You probably put an invalid instance, volume or address id in as a command line argument, Check to make sure it really exists and retry."
|
169
|
+
puts "#{e.backtrace.join("\n")} -- #{e.message}"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
data/lib/validators.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module Scli
|
2
|
+
def self.yield_regular_input(argument)
|
3
|
+
return nil if argument.nil?
|
4
|
+
(argument[0] == "-") ? nil : argument
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.is_address_id?(address_id)
|
8
|
+
address_id.to_i.to_s.size >= 6
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.is_volume_id?(volume_id)
|
12
|
+
volume_id.to_i.to_s.size >= 5
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.is_vlan_id?(vlan_id)
|
16
|
+
vlan_id.to_i.to_s.size == 3
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.is_image_id?(image_id)
|
20
|
+
image_id.to_i.to_s.size >= 8
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.is_instance_id?(instance_id)
|
24
|
+
instance_id.to_i.to_s.size >= 6
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.volume_format_valid?(format)
|
28
|
+
valid_formats = ["EXT3", "RAW"]
|
29
|
+
if valid_formats.include?(format)
|
30
|
+
true
|
31
|
+
else
|
32
|
+
puts "The format you provided is invalid, it must be one of #{valid_formats.join(",")}"
|
33
|
+
false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.volume_size_valid?(size)
|
38
|
+
valid_sizes = [60, 256, 512, 1024, 2048, 4112, 8224, 10240]
|
39
|
+
if valid_sizes.include?(size.to_i)
|
40
|
+
true
|
41
|
+
else
|
42
|
+
puts "The size you provided is invalid, it must be one of #{valid_sizes.join(",")}"
|
43
|
+
false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.volume_offering_valid?(offering_id)
|
48
|
+
unless offering_id.to_s == "20035200"
|
49
|
+
puts "=" * 60
|
50
|
+
puts "WARN: IBM has many offering ID's for volumes, however most do not support large blocks and they seem to be migrating away from using them."
|
51
|
+
puts "WARN: Every volume created in the WebUI uses a offering id of 20035200, so you probably want to use that."
|
52
|
+
puts "=" * 60
|
53
|
+
end
|
54
|
+
true
|
55
|
+
end
|
56
|
+
end
|
data/scli.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'scli'
|
3
|
+
s.version = '0.0.3'
|
4
|
+
s.date = '2012-06-30'
|
5
|
+
s.platform = Gem::Platform::RUBY
|
6
|
+
s.authors = ['Josh Pasqualetto']
|
7
|
+
s.email = ['josh.pasqualetto@sonian.net']
|
8
|
+
s.homepage = 'https://github.com/sonian/scli'
|
9
|
+
s.summary = 'CLI Interface to IBM SmartCloud API'
|
10
|
+
s.description = 'A command line tool to interface with IBM SmartCloud: create, view & delete instances, keys, volumes, addresses, etc'
|
11
|
+
s.license = 'MIT'
|
12
|
+
s.has_rdoc = false
|
13
|
+
|
14
|
+
s.add_dependency('fog', '~> 1.3.1')
|
15
|
+
s.add_dependency('mixlib-cli', '~> 1.2.2')
|
16
|
+
s.add_dependency('terminal-table', '~> 1.4.5')
|
17
|
+
s.add_dependency('colored', '1.2')
|
18
|
+
|
19
|
+
s.files = Dir.glob('{bin,lib}/**/*') + %w[scli.gemspec README.org MIT-LICENSE.txt]
|
20
|
+
s.executables = Dir.glob('bin/**/*').map { |file| File.basename(file) }
|
21
|
+
s.require_paths = ['lib']
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: scli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Josh Pasqualetto
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-30 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: fog
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.3.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.3.1
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: mixlib-cli
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.2.2
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.2.2
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: terminal-table
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.4.5
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.4.5
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: colored
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - '='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1.2'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - '='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '1.2'
|
78
|
+
description: ! 'A command line tool to interface with IBM SmartCloud: create, view
|
79
|
+
& delete instances, keys, volumes, addresses, etc'
|
80
|
+
email:
|
81
|
+
- josh.pasqualetto@sonian.net
|
82
|
+
executables:
|
83
|
+
- scli
|
84
|
+
extensions: []
|
85
|
+
extra_rdoc_files: []
|
86
|
+
files:
|
87
|
+
- bin/scli
|
88
|
+
- lib/formatters.rb
|
89
|
+
- lib/generic.rb
|
90
|
+
- lib/plugins/attach-volume.rb
|
91
|
+
- lib/plugins/create-address.rb
|
92
|
+
- lib/plugins/create-instance.rb
|
93
|
+
- lib/plugins/create-key.rb
|
94
|
+
- lib/plugins/create-volume.rb
|
95
|
+
- lib/plugins/describe-address-offering.rb
|
96
|
+
- lib/plugins/describe-address.rb
|
97
|
+
- lib/plugins/describe-image.rb
|
98
|
+
- lib/plugins/describe-instance-types.rb
|
99
|
+
- lib/plugins/describe-instance.rb
|
100
|
+
- lib/plugins/describe-key.rb
|
101
|
+
- lib/plugins/describe-location.rb
|
102
|
+
- lib/plugins/describe-vlan.rb
|
103
|
+
- lib/plugins/describe-volume-offering.rb
|
104
|
+
- lib/plugins/describe-volume.rb
|
105
|
+
- lib/plugins/detach-volume.rb
|
106
|
+
- lib/plugins/get-console-output.rb
|
107
|
+
- lib/plugins/reboot.rb
|
108
|
+
- lib/plugins/terminate-address.rb
|
109
|
+
- lib/plugins/terminate-image.rb
|
110
|
+
- lib/plugins/terminate-instance.rb
|
111
|
+
- lib/plugins/terminate-key.rb
|
112
|
+
- lib/plugins/terminate-volume.rb
|
113
|
+
- lib/scli.rb
|
114
|
+
- lib/validators.rb
|
115
|
+
- scli.gemspec
|
116
|
+
- README.org
|
117
|
+
- MIT-LICENSE.txt
|
118
|
+
homepage: https://github.com/sonian/scli
|
119
|
+
licenses:
|
120
|
+
- MIT
|
121
|
+
post_install_message:
|
122
|
+
rdoc_options: []
|
123
|
+
require_paths:
|
124
|
+
- lib
|
125
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
126
|
+
none: false
|
127
|
+
requirements:
|
128
|
+
- - ! '>='
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
|
+
none: false
|
133
|
+
requirements:
|
134
|
+
- - ! '>='
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
137
|
+
requirements: []
|
138
|
+
rubyforge_project:
|
139
|
+
rubygems_version: 1.8.24
|
140
|
+
signing_key:
|
141
|
+
specification_version: 3
|
142
|
+
summary: CLI Interface to IBM SmartCloud API
|
143
|
+
test_files: []
|