collins_shell 0.2.14
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/.pryrc +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +59 -0
- data/README.md +335 -0
- data/Rakefile +64 -0
- data/VERSION +1 -0
- data/bin/collins-shell +36 -0
- data/collins_shell.gemspec +95 -0
- data/lib/collins_shell.rb +3 -0
- data/lib/collins_shell/asset.rb +198 -0
- data/lib/collins_shell/cli.rb +185 -0
- data/lib/collins_shell/console.rb +129 -0
- data/lib/collins_shell/console/asset.rb +127 -0
- data/lib/collins_shell/console/cache.rb +17 -0
- data/lib/collins_shell/console/command_helpers.rb +131 -0
- data/lib/collins_shell/console/commands.rb +28 -0
- data/lib/collins_shell/console/commands/cat.rb +123 -0
- data/lib/collins_shell/console/commands/cd.rb +61 -0
- data/lib/collins_shell/console/commands/io.rb +26 -0
- data/lib/collins_shell/console/commands/iterators.rb +190 -0
- data/lib/collins_shell/console/commands/tail.rb +178 -0
- data/lib/collins_shell/console/commands/versions.rb +42 -0
- data/lib/collins_shell/console/filesystem.rb +121 -0
- data/lib/collins_shell/console/options_helpers.rb +8 -0
- data/lib/collins_shell/errors.rb +7 -0
- data/lib/collins_shell/ip_address.rb +144 -0
- data/lib/collins_shell/ipmi.rb +67 -0
- data/lib/collins_shell/monkeypatch.rb +60 -0
- data/lib/collins_shell/provision.rb +152 -0
- data/lib/collins_shell/state.rb +98 -0
- data/lib/collins_shell/tag.rb +41 -0
- data/lib/collins_shell/thor.rb +209 -0
- data/lib/collins_shell/util.rb +120 -0
- data/lib/collins_shell/util/asset_printer.rb +265 -0
- data/lib/collins_shell/util/asset_stache.rb +32 -0
- data/lib/collins_shell/util/log_printer.rb +187 -0
- data/lib/collins_shell/util/printer_util.rb +28 -0
- metadata +200 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'pry'
|
2
|
+
|
3
|
+
module CollinsShell; module Console; module Commands
|
4
|
+
Versions = Pry::CommandSet.new do
|
5
|
+
create_command "latest", "Latest version of collins shell" do
|
6
|
+
group "Software"
|
7
|
+
|
8
|
+
def options(opt)
|
9
|
+
opt.banner <<-BANNER
|
10
|
+
Usage: latest
|
11
|
+
|
12
|
+
Display the latest version of collins shell
|
13
|
+
BANNER
|
14
|
+
end
|
15
|
+
|
16
|
+
def process
|
17
|
+
o = CollinsShell::Console.options
|
18
|
+
render_output CollinsShell::Cli.new([], o).get_latest_version
|
19
|
+
end
|
20
|
+
|
21
|
+
end # create_command
|
22
|
+
|
23
|
+
create_command "version", "Current version of collins shell" do
|
24
|
+
group "Software"
|
25
|
+
|
26
|
+
def options(opt)
|
27
|
+
opt.banner <<-BANNER
|
28
|
+
Usage: version
|
29
|
+
|
30
|
+
Display the current version of collins shell
|
31
|
+
BANNER
|
32
|
+
end
|
33
|
+
|
34
|
+
def process
|
35
|
+
o = CollinsShell::Console.options
|
36
|
+
render_output CollinsShell::Cli.new([], o).get_version
|
37
|
+
end
|
38
|
+
|
39
|
+
end # create_command
|
40
|
+
|
41
|
+
end # CommandSet
|
42
|
+
end; end; end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'collins_shell/console/asset'
|
2
|
+
|
3
|
+
module CollinsShell; module Console
|
4
|
+
class Filesystem
|
5
|
+
include CollinsShell::Console::CommandHelpers
|
6
|
+
|
7
|
+
attr_accessor :console_asset, :stack # Using console_asset, don't want to steal asset
|
8
|
+
|
9
|
+
def initialize optns = {}
|
10
|
+
options = Collins::Util.symbolize_hash(optns)
|
11
|
+
@console_asset = options.fetch(:console_asset, nil)
|
12
|
+
@options = options
|
13
|
+
@stack = options.fetch(:stack, [])
|
14
|
+
end
|
15
|
+
|
16
|
+
def root?
|
17
|
+
@stack.size == 0
|
18
|
+
end
|
19
|
+
|
20
|
+
def asset?
|
21
|
+
!console_asset.nil?
|
22
|
+
end
|
23
|
+
|
24
|
+
def path
|
25
|
+
'/' + @stack.join('/')
|
26
|
+
end
|
27
|
+
|
28
|
+
def pop
|
29
|
+
stk = @stack.dup
|
30
|
+
stk.pop
|
31
|
+
stk = [] if stk.nil?
|
32
|
+
asset = resolve_location(stk) if stk.size > 0
|
33
|
+
opts = @options.merge(:stack => stk, :console_asset => asset)
|
34
|
+
CollinsShell::Console::Filesystem.new(opts)
|
35
|
+
end
|
36
|
+
|
37
|
+
def push ctxt
|
38
|
+
stk = @stack.dup
|
39
|
+
stk << ctxt
|
40
|
+
asset = resolve_location stk
|
41
|
+
if asset? and asset then
|
42
|
+
raise StandardError.new("Can not nest assets in assets")
|
43
|
+
end
|
44
|
+
opts = @options.merge(:stack => stk, :console_asset => asset)
|
45
|
+
CollinsShell::Console::Filesystem.new(opts)
|
46
|
+
end
|
47
|
+
|
48
|
+
def available_commands
|
49
|
+
includes = ['clear_cache'] + pry_commands
|
50
|
+
if asset? then
|
51
|
+
excludes = ['respond_to?','to_s','cput'].map{|s|s.to_sym}
|
52
|
+
cmds1 = CollinsShell::Console::Asset.public_instance_methods(false).reject{|i| excludes.include?(i.to_sym)}
|
53
|
+
cmds2 = Collins::Asset.public_instance_methods(false).reject{|i| excludes.include?(i.to_sym)}.map{|s| "asset.#{s}"}
|
54
|
+
cmds1 + cmds2 + includes
|
55
|
+
else
|
56
|
+
includes
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_s
|
61
|
+
"#{self.class}(path = '#{path}', asset? = '#{asset?}')"
|
62
|
+
end
|
63
|
+
|
64
|
+
protected
|
65
|
+
def method_missing meth, *args, &block
|
66
|
+
if asset? then
|
67
|
+
a = @console_asset
|
68
|
+
if a.respond_to?(meth) then
|
69
|
+
a.send(meth, *args, &block)
|
70
|
+
else
|
71
|
+
Pry.output.puts("Command not found: #{meth}")
|
72
|
+
cmds = available_commands.join(', ')
|
73
|
+
Pry.output.puts("Available commands: #{cmds}")
|
74
|
+
end
|
75
|
+
elsif pry_commands.include?(meth) then
|
76
|
+
arg = args.unshift(meth).join(' ')
|
77
|
+
runner = CollinsShell::Console
|
78
|
+
runner.run_pry_command(arg, :context => self, :binding_stack => [Pry.binding_for(self)])
|
79
|
+
else
|
80
|
+
Pry.output.puts("command not found: #{meth}")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def pry_commands
|
85
|
+
@pry_commands ||= Pry.commands.list_commands.select{|c| c.respond_to?(:to_sym)}.map{|c| c.to_sym}
|
86
|
+
end
|
87
|
+
|
88
|
+
# @return [Collins::Asset,NilClass] asset if context is one, nil otherwise
|
89
|
+
# @raise [ExpectationFailedException] if invalid nesting is attempted
|
90
|
+
def resolve_location stack
|
91
|
+
context = stack.last
|
92
|
+
path = "/#{stack.join('/')}"
|
93
|
+
|
94
|
+
if get_all_tags.include?(context) then
|
95
|
+
Pry.output.puts("Found tag: '#{context}'")
|
96
|
+
nil
|
97
|
+
elsif asset_exists?(context) then
|
98
|
+
Pry.output.puts("Found asset: '#{context}'")
|
99
|
+
CollinsShell::Console::Asset.new(context)
|
100
|
+
elsif stack.size % 2 == 0 then # should be key/value, we know it's not root
|
101
|
+
begin
|
102
|
+
assets = find_assets(stack, false)
|
103
|
+
if assets.size == 0 then
|
104
|
+
raise StandardError.new("No assets in path #{path}")
|
105
|
+
elsif assets.size == 1 then
|
106
|
+
Pry.output.puts("Found asset #{assets[0]} in #{path}")
|
107
|
+
CollinsShell::Console::Asset.new(assets[0])
|
108
|
+
else
|
109
|
+
Pry.output.puts("#{assets.size} assets in path #{path}")
|
110
|
+
nil
|
111
|
+
end
|
112
|
+
rescue Exception => e
|
113
|
+
raise StandardError.new("Invalid path #{path} - #{e}")
|
114
|
+
end
|
115
|
+
else
|
116
|
+
raise StandardError.new("Path #{path} is invalid")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end; end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'collins_shell/thor'
|
2
|
+
require 'collins_shell/util'
|
3
|
+
require 'thor'
|
4
|
+
require 'thor/group'
|
5
|
+
|
6
|
+
module CollinsShell
|
7
|
+
|
8
|
+
class IpAddress < Thor
|
9
|
+
|
10
|
+
include ThorHelper
|
11
|
+
include CollinsShell::Util
|
12
|
+
namespace :ip_address
|
13
|
+
def self.banner task, namespace = true, subcommand = false
|
14
|
+
"#{basename} #{task.formatted_usage(self, true, subcommand).gsub(':',' ')}"
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'allocate POOL', 'allocate addresses for an asset in the specified pool'
|
18
|
+
use_collins_options
|
19
|
+
use_tag_option(true)
|
20
|
+
method_option :count, :type => :numeric, :default => 1, :desc => 'Number of addresses to allocate'
|
21
|
+
def allocate pool
|
22
|
+
call_collins get_collins_client, "ip_address allocate" do |client|
|
23
|
+
addresses = client.ipaddress_allocate! options.tag, pool, options["count"]
|
24
|
+
header = [["Gateway","Netmask","Address","Pool"]]
|
25
|
+
tags = header + addresses.map do |address|
|
26
|
+
[address.gateway, address.netmask, address.address, address.pool]
|
27
|
+
end
|
28
|
+
print_table tags
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'delete POOL', 'delete addresses for an asset in the specified pool'
|
33
|
+
use_collins_options
|
34
|
+
use_tag_option(true)
|
35
|
+
def delete pool
|
36
|
+
call_collins get_collins_client, "ip_address delete" do |client|
|
37
|
+
delete_count = client.ipaddress_delete! options.tag, pool
|
38
|
+
say_success "Deleted #{delete_count} addresses"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
desc 'delete_all', 'delete all addresses for an asset'
|
43
|
+
use_collins_options
|
44
|
+
use_tag_option(true)
|
45
|
+
def delete_all
|
46
|
+
call_collins get_collins_client, "ip_address delete_all" do |client|
|
47
|
+
delete_count = client.ipaddress_delete! options.tag
|
48
|
+
say_success "Deleted #{delete_count} addresses"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
desc 'find ADDRESS', 'find asset using specified IP address'
|
53
|
+
use_collins_options
|
54
|
+
def find address
|
55
|
+
call_collins get_collins_client, "ip_address find" do |client|
|
56
|
+
asset = client.asset_at_address address
|
57
|
+
if asset then
|
58
|
+
say_success "Asset #{asset.tag} is using address #{address}"
|
59
|
+
else
|
60
|
+
say_error "No asset using address #{address}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
desc 'assets POOL', 'find all assets in a pool'
|
66
|
+
use_collins_options
|
67
|
+
method_option :details, :type => :boolean, :default => false, :desc => 'Retrieve details for each asset. SLOW'
|
68
|
+
def assets pool
|
69
|
+
call_collins get_collins_client, "ip_address assets" do |client|
|
70
|
+
header = true
|
71
|
+
client.assets_in_pool(pool).each do |asset|
|
72
|
+
if options.details then
|
73
|
+
asset = client.get asset
|
74
|
+
print_find_results asset, [:tag,:status,:type,:hostname,:addresses], :header => header
|
75
|
+
header = false
|
76
|
+
else
|
77
|
+
puts(asset.tag)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
desc 'pools', 'find all pools that are in use'
|
84
|
+
use_collins_options
|
85
|
+
method_option :used, :type => :boolean, :default => false, :desc => 'Only pools that are in use'
|
86
|
+
def pools
|
87
|
+
call_collins get_collins_client, "ip_address pools" do |client|
|
88
|
+
# NAME, NETWORK, START_ADDRESS, SPECIFIED_GATEWAY, GATEWAY, BROADCAST, POSSIBLE_ADDRESSES
|
89
|
+
header = [["Pool","Network","Gateway","Broadcast","Possible Addresses","Start Address","Specified Gateway"]]
|
90
|
+
rows = client.ipaddress_pools(!options.used).map do |pool|
|
91
|
+
[pool["NAME"], pool["NETWORK"], pool["GATEWAY"], pool["BROADCAST"], pool["POSSIBLE_ADDRESSES"],
|
92
|
+
pool["START_ADDRESS"], pool["SPECIFIED_GATEWAY"]]
|
93
|
+
end
|
94
|
+
print_table header + rows
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
desc 'create', 'create a new IP address (Use allocate, not create)'
|
99
|
+
use_collins_options
|
100
|
+
use_tag_option(true)
|
101
|
+
method_option :address, :required => true, :type => :string, :desc => 'IP address'
|
102
|
+
method_option :gateway, :required => true, :type => :string, :desc => 'IP gateway'
|
103
|
+
method_option :netmask, :required => true, :type => :string, :desc => 'IP netmask'
|
104
|
+
method_option :pool, :type => :string, :desc => 'Name of pool'
|
105
|
+
def create
|
106
|
+
call_collins get_collins_client, "create address" do |client|
|
107
|
+
address = client.ipaddress_update! options.tag, nil,
|
108
|
+
:address => options.address,
|
109
|
+
:gateway => options.gateway,
|
110
|
+
:netmask => options.netmask,
|
111
|
+
:pool => options.pool
|
112
|
+
if address then
|
113
|
+
say_success "Address for #{options.tag} created"
|
114
|
+
else
|
115
|
+
say_error "Address for #{options.tag} not created"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
desc 'update OLD_ADDRESS', 'update the IP info for an asset'
|
121
|
+
use_collins_options
|
122
|
+
use_tag_option(true)
|
123
|
+
method_option :address, :type => :string, :desc => 'New IP address'
|
124
|
+
method_option :gateway, :type => :string, :desc => 'New IP gateway'
|
125
|
+
method_option :netmask, :type => :string, :desc => 'New IP netmask'
|
126
|
+
method_option :pool, :type => :string, :desc => 'New pool'
|
127
|
+
def update old_address
|
128
|
+
call_collins get_collins_client, "update address" do |client|
|
129
|
+
address = client.ipaddress_update! options.tag, old_address,
|
130
|
+
:address => options.address,
|
131
|
+
:gateway => options.gateway,
|
132
|
+
:netmask => options.netmask,
|
133
|
+
:pool => options.pool
|
134
|
+
if address then
|
135
|
+
say_success "Address for #{options.tag} updated"
|
136
|
+
else
|
137
|
+
say_error "Address for #{options.tag} not updated"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'collins_shell/thor'
|
2
|
+
require 'collins_shell/util'
|
3
|
+
require 'thor'
|
4
|
+
require 'thor/group'
|
5
|
+
|
6
|
+
module CollinsShell
|
7
|
+
|
8
|
+
class Ipmi < Thor
|
9
|
+
include ThorHelper
|
10
|
+
include CollinsShell::Util
|
11
|
+
namespace :ipmi
|
12
|
+
def self.banner task, namespace = true, subcommand = false
|
13
|
+
"#{basename} #{task.formatted_usage(self, true, subcommand).gsub(':',' ')}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.ipmi_options required = false
|
17
|
+
method_option :ipmi_username, :type => :string, :required => required, :desc => 'IPMI username'
|
18
|
+
method_option :ipmi_password, :type => :string, :required => required, :desc => 'IPMI password'
|
19
|
+
method_option :address, :type => :string, :required => required, :desc => 'IPMI address'
|
20
|
+
method_option :gateway, :type => :string, :required => required, :desc => 'IPMI gateway'
|
21
|
+
method_option :netmask, :type => :string, :required => required, :desc => 'IPMI netmask'
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.print_ipmi ipmi
|
25
|
+
puts("address,gateway,netmask,username,password")
|
26
|
+
puts([ipmi.address,ipmi.gateway,ipmi.netmask,ipmi.username,ipmi.password].join(','))
|
27
|
+
end
|
28
|
+
|
29
|
+
desc 'create', 'create a new IPMI address for the specified asset'
|
30
|
+
use_collins_options
|
31
|
+
use_tag_option(true)
|
32
|
+
ipmi_options(true)
|
33
|
+
def create
|
34
|
+
call_collins get_collins_client, "create ipmi" do |client|
|
35
|
+
ipmi = client.ipmi_create options.tag, options.ipmi_username, options.ipmi_password, options.address, options.gateway, options.netmask
|
36
|
+
if ipmi then
|
37
|
+
asset = client.get options.tag
|
38
|
+
CollinsShell::Ipmi.print_ipmi asset.ipmi
|
39
|
+
else
|
40
|
+
say_error "create IPMI address"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
desc 'update', 'update IPMI settings for an asset'
|
46
|
+
use_collins_options
|
47
|
+
use_tag_option(true)
|
48
|
+
ipmi_options(false)
|
49
|
+
def update
|
50
|
+
call_collins get_collins_client, "update ipmi" do |client|
|
51
|
+
ipmi = client.ipmi_update options.tag, :username => options.ipmi_username,
|
52
|
+
:password => options.ipmi_password,
|
53
|
+
:address => options.address,
|
54
|
+
:gateway => options.gateway,
|
55
|
+
:netmask => options.netmask
|
56
|
+
if ipmi then
|
57
|
+
asset = client.get options.tag
|
58
|
+
CollinsShell::Ipmi.print_ipmi asset.ipmi
|
59
|
+
else
|
60
|
+
say_error "update IPMI address"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class Numeric
|
2
|
+
SIZE_ARRAY = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB']
|
3
|
+
end
|
4
|
+
|
5
|
+
class Float
|
6
|
+
def to_human_size
|
7
|
+
return "0 Bytes" if (self == 0)
|
8
|
+
i = (Math.log(self) / Math.log(1024)).floor.to_i
|
9
|
+
small = self / (1024 ** i)
|
10
|
+
if i == 0 then
|
11
|
+
"#{self} #{SIZE_ARRAY[i]}"
|
12
|
+
else
|
13
|
+
sprintf("%.14f %s", small, SIZE_ARRAY[i])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Fixnum
|
19
|
+
|
20
|
+
def to_human_size
|
21
|
+
return "0 Bytes" if (self == 0)
|
22
|
+
i = (Math.log(self) / Math.log(1024)).floor.to_i
|
23
|
+
small = self / (1024 ** i)
|
24
|
+
if i == 0 then
|
25
|
+
"#{self} #{SIZE_ARRAY[i]}"
|
26
|
+
else
|
27
|
+
sprintf("%.2f %s", small, SIZE_ARRAY[i])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
class String
|
34
|
+
|
35
|
+
def is_disk_size?
|
36
|
+
s = self.downcase
|
37
|
+
s.include?("gb") or s.include?("mb") or s.include?("tb")
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_bytes
|
41
|
+
s = self.downcase
|
42
|
+
size_h = ""
|
43
|
+
multiplier = 0
|
44
|
+
if s.include?("mb") then
|
45
|
+
multiplier = (1024 ** 2)
|
46
|
+
size_h = s.split('mb')[0]
|
47
|
+
elsif s.include?("gb") then
|
48
|
+
multiplier = (1024 ** 3)
|
49
|
+
size_h = s.split('gb')[0]
|
50
|
+
elsif s.include?("tb") then
|
51
|
+
multiplier = (1024 ** 4)
|
52
|
+
size_h = s.split('tb')[0]
|
53
|
+
else
|
54
|
+
raise Exception.new("Unknown size: #{s}")
|
55
|
+
end
|
56
|
+
(multiplier * size_h.to_f).floor.to_i
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
end
|