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.
Files changed (39) hide show
  1. data/.pryrc +1 -0
  2. data/.rvmrc +1 -0
  3. data/Gemfile +18 -0
  4. data/Gemfile.lock +59 -0
  5. data/README.md +335 -0
  6. data/Rakefile +64 -0
  7. data/VERSION +1 -0
  8. data/bin/collins-shell +36 -0
  9. data/collins_shell.gemspec +95 -0
  10. data/lib/collins_shell.rb +3 -0
  11. data/lib/collins_shell/asset.rb +198 -0
  12. data/lib/collins_shell/cli.rb +185 -0
  13. data/lib/collins_shell/console.rb +129 -0
  14. data/lib/collins_shell/console/asset.rb +127 -0
  15. data/lib/collins_shell/console/cache.rb +17 -0
  16. data/lib/collins_shell/console/command_helpers.rb +131 -0
  17. data/lib/collins_shell/console/commands.rb +28 -0
  18. data/lib/collins_shell/console/commands/cat.rb +123 -0
  19. data/lib/collins_shell/console/commands/cd.rb +61 -0
  20. data/lib/collins_shell/console/commands/io.rb +26 -0
  21. data/lib/collins_shell/console/commands/iterators.rb +190 -0
  22. data/lib/collins_shell/console/commands/tail.rb +178 -0
  23. data/lib/collins_shell/console/commands/versions.rb +42 -0
  24. data/lib/collins_shell/console/filesystem.rb +121 -0
  25. data/lib/collins_shell/console/options_helpers.rb +8 -0
  26. data/lib/collins_shell/errors.rb +7 -0
  27. data/lib/collins_shell/ip_address.rb +144 -0
  28. data/lib/collins_shell/ipmi.rb +67 -0
  29. data/lib/collins_shell/monkeypatch.rb +60 -0
  30. data/lib/collins_shell/provision.rb +152 -0
  31. data/lib/collins_shell/state.rb +98 -0
  32. data/lib/collins_shell/tag.rb +41 -0
  33. data/lib/collins_shell/thor.rb +209 -0
  34. data/lib/collins_shell/util.rb +120 -0
  35. data/lib/collins_shell/util/asset_printer.rb +265 -0
  36. data/lib/collins_shell/util/asset_stache.rb +32 -0
  37. data/lib/collins_shell/util/log_printer.rb +187 -0
  38. data/lib/collins_shell/util/printer_util.rb +28 -0
  39. 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,8 @@
1
+ module CollinsShell; module Console; module OptionsHelpers
2
+
3
+ module_function
4
+ def pager_options opt
5
+ opt.on :f, :flood, "Do not use a pager to view text longer than one screen"
6
+ end
7
+
8
+ end; end; end
@@ -0,0 +1,7 @@
1
+ module CollinsShell
2
+
3
+ class CollinsShellError < StandardError; end
4
+ class ConfigurationError < CollinsShellError; end
5
+ class RequirementFailedError < CollinsShellError; end
6
+
7
+ 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