collins_shell 0.2.14

Sign up to get free protection for your applications and to get access to all the features.
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