Class: Stackadmin
- Inherits:
-
Object
- Object
- Stackadmin
- Defined in:
- lib/stackadmin/base.rb,
lib/stackadmin/log.rb,
lib/stackadmin/yaml.rb,
lib/stackadmin/audit.rb,
lib/stackadmin/patch.rb,
lib/stackadmin/version.rb,
lib/stackadmin/exceptions.rb
Overview
Core class of the Stackadmin gem
Defined Under Namespace
Classes: Exception, InvalidCommand, InvalidFlags, InvalidPatchStatus, YAMLTargetNotFound
Constant Summary collapse
- VERSION =
Gem version
'1.0.0'
Instance Attribute Summary collapse
-
#fresh ⇒ Boolean
readonly
Whether the available node data is from a fresh audit.
-
#id ⇒ String
readonly
The hostname/FQDN/IP address of the core Stackato node.
-
#license ⇒ Hash
readonly
The details of the Stackato license installed on the node.
-
#nodes ⇒ Hash
readonly
The details of each node in the Stackato cluster.
-
#version ⇒ String
readonly
The version of Stackato installed on the node.
Class Method Summary collapse
-
.find_instances(ssh_config = '~/.ssh/config', filter = []) ⇒ Array<String>
Parse through an SSH config to find possible Stackato hostnames.
Instance Method Summary collapse
-
#initialize(target, port = 22, debug = false, yml_file = nil) ⇒ Stackadmin
constructor
Initializes a new Stackadmin object.
-
#install!(patches = [], node = nil, local = false, restart = true, force_update = false, manifest_file = nil) ⇒ Hash
Installs patch(es) to the targeted Stackato cluster.
-
#manifest(uri = nil) ⇒ Hash
Retrieves patch manifest.
-
#mark!(patches = [], mark_installed = false, node = nil, local = false) ⇒ Hash
Marks patch(es) as installed or uninstalled on the targeted Stackato cluster Returns hash: { node1: [patch1, patch2], etc }.
-
#refresh(target = nil) ⇒ Object
Refresh object data with a fresh audit.
-
#reinstall!(patches = [], node = nil, local = false, restart = true, force_update = false, manifest_file = nil) ⇒ Hash
Reinstalls patch(es) to the targeted Stackato cluster.
-
#report(*args) ⇒ String
Retrieve a report from the targeted Stackato.
-
#reset!(node = nil, local = false) ⇒ Boolean
Marks all of the targeted Stackato cluster’s patch updates as uninstalled.
-
#revert!(patches = [], node = nil, local = false, restart = true, force_update = false, manifest_file = nil) ⇒ Hash
Revert patch(es) on the targeted Stackato cluster.
-
#to_yaml ⇒ String
YAML-formatted target Stackato cluster info.
-
#update!(node = nil, local = false, manifest_file = nil) ⇒ Boolean
Updates the patch manifest for the targeted Stackato cluster.
Constructor Details
#initialize(target, port = 22, debug = false, yml_file = nil) ⇒ Stackadmin
All paramaters, -target, should be in an opt[] hash
Initializes a new Stackadmin object
44 45 46 47 48 |
# File 'lib/stackadmin/base.rb', line 44 def initialize(target, port = 22, debug = false, yml_file = nil) @port = port @debug = debug yml_file ? parse_yaml(target, yml_file) : audit(target) end |
Instance Attribute Details
#fresh ⇒ Boolean (readonly)
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/stackadmin/base.rb', line 34 class Stackadmin attr_reader :id, :version, :license, :nodes, :fresh # Initializes a new Stackadmin object # @param target [String] hostname/FQDN/IP address of the target node # @param port [Fixnum] port used to SSH into the target node # @param debug [Boolean] toggles display of debug information # @param yml_file [String, nil] pre-populated YAML file to pull node information from # @return [Stackadmin] new, populated object # @todo All paramaters, -target, should be in an opt[] hash def initialize(target, port = 22, debug = false, yml_file = nil) @port = port @debug = debug yml_file ? parse_yaml(target, yml_file) : audit(target) end # Refresh object data with a fresh audit # @param target [String, nil] optional hostname/FQDN/IP address of the target node # @todo Probably unneccessary? Deprecate? def refresh(target = nil) @id ||= target audit end # Parse through an SSH config to find possible Stackato hostnames # @param ssh_config [String] path to the SSH config file # @param filter [Array<String>] list of regex strings to filter out of found hostnames # @return [Array<String>] (optionally filtered) list of Stackato hostnames found def self.find_instances(ssh_config = '~/.ssh/config', filter = []) instances = IO.read(File.(ssh_config)) .scan(/^\s*Host (.*stackato.*)/) .flatten filter.each { |f| instances.delete_if { |host| host =~ /#{f}/ } } instances end # Retrieves patch manifest # @param uri [String, nil] path to the manifest.json # @return [Hash] the patch manifest def manifest(uri = nil) unless @manifest uri ||= "https://get.stackato.com/kato-patch/#{@version}/manifest.json" log "Retrieving latest manifest from: #{uri}" end @manifest ||= JSON.load(open(uri)) rescue nil end private # Outputs formatted debug messages to stderr # @param msg [String] debug message to output # @return [String] formatted debug message def log(msg) $stderr.puts ">> #{msg}" if @debug end end |
#id ⇒ String (readonly)
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/stackadmin/base.rb', line 34 class Stackadmin attr_reader :id, :version, :license, :nodes, :fresh # Initializes a new Stackadmin object # @param target [String] hostname/FQDN/IP address of the target node # @param port [Fixnum] port used to SSH into the target node # @param debug [Boolean] toggles display of debug information # @param yml_file [String, nil] pre-populated YAML file to pull node information from # @return [Stackadmin] new, populated object # @todo All paramaters, -target, should be in an opt[] hash def initialize(target, port = 22, debug = false, yml_file = nil) @port = port @debug = debug yml_file ? parse_yaml(target, yml_file) : audit(target) end # Refresh object data with a fresh audit # @param target [String, nil] optional hostname/FQDN/IP address of the target node # @todo Probably unneccessary? Deprecate? def refresh(target = nil) @id ||= target audit end # Parse through an SSH config to find possible Stackato hostnames # @param ssh_config [String] path to the SSH config file # @param filter [Array<String>] list of regex strings to filter out of found hostnames # @return [Array<String>] (optionally filtered) list of Stackato hostnames found def self.find_instances(ssh_config = '~/.ssh/config', filter = []) instances = IO.read(File.(ssh_config)) .scan(/^\s*Host (.*stackato.*)/) .flatten filter.each { |f| instances.delete_if { |host| host =~ /#{f}/ } } instances end # Retrieves patch manifest # @param uri [String, nil] path to the manifest.json # @return [Hash] the patch manifest def manifest(uri = nil) unless @manifest uri ||= "https://get.stackato.com/kato-patch/#{@version}/manifest.json" log "Retrieving latest manifest from: #{uri}" end @manifest ||= JSON.load(open(uri)) rescue nil end private # Outputs formatted debug messages to stderr # @param msg [String] debug message to output # @return [String] formatted debug message def log(msg) $stderr.puts ">> #{msg}" if @debug end end |
#license ⇒ Hash (readonly)
Returns the details of the Stackato license installed on the node.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/stackadmin/base.rb', line 34 class Stackadmin attr_reader :id, :version, :license, :nodes, :fresh # Initializes a new Stackadmin object # @param target [String] hostname/FQDN/IP address of the target node # @param port [Fixnum] port used to SSH into the target node # @param debug [Boolean] toggles display of debug information # @param yml_file [String, nil] pre-populated YAML file to pull node information from # @return [Stackadmin] new, populated object # @todo All paramaters, -target, should be in an opt[] hash def initialize(target, port = 22, debug = false, yml_file = nil) @port = port @debug = debug yml_file ? parse_yaml(target, yml_file) : audit(target) end # Refresh object data with a fresh audit # @param target [String, nil] optional hostname/FQDN/IP address of the target node # @todo Probably unneccessary? Deprecate? def refresh(target = nil) @id ||= target audit end # Parse through an SSH config to find possible Stackato hostnames # @param ssh_config [String] path to the SSH config file # @param filter [Array<String>] list of regex strings to filter out of found hostnames # @return [Array<String>] (optionally filtered) list of Stackato hostnames found def self.find_instances(ssh_config = '~/.ssh/config', filter = []) instances = IO.read(File.(ssh_config)) .scan(/^\s*Host (.*stackato.*)/) .flatten filter.each { |f| instances.delete_if { |host| host =~ /#{f}/ } } instances end # Retrieves patch manifest # @param uri [String, nil] path to the manifest.json # @return [Hash] the patch manifest def manifest(uri = nil) unless @manifest uri ||= "https://get.stackato.com/kato-patch/#{@version}/manifest.json" log "Retrieving latest manifest from: #{uri}" end @manifest ||= JSON.load(open(uri)) rescue nil end private # Outputs formatted debug messages to stderr # @param msg [String] debug message to output # @return [String] formatted debug message def log(msg) $stderr.puts ">> #{msg}" if @debug end end |
#nodes ⇒ Hash (readonly)
Returns the details of each node in the Stackato cluster.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/stackadmin/base.rb', line 34 class Stackadmin attr_reader :id, :version, :license, :nodes, :fresh # Initializes a new Stackadmin object # @param target [String] hostname/FQDN/IP address of the target node # @param port [Fixnum] port used to SSH into the target node # @param debug [Boolean] toggles display of debug information # @param yml_file [String, nil] pre-populated YAML file to pull node information from # @return [Stackadmin] new, populated object # @todo All paramaters, -target, should be in an opt[] hash def initialize(target, port = 22, debug = false, yml_file = nil) @port = port @debug = debug yml_file ? parse_yaml(target, yml_file) : audit(target) end # Refresh object data with a fresh audit # @param target [String, nil] optional hostname/FQDN/IP address of the target node # @todo Probably unneccessary? Deprecate? def refresh(target = nil) @id ||= target audit end # Parse through an SSH config to find possible Stackato hostnames # @param ssh_config [String] path to the SSH config file # @param filter [Array<String>] list of regex strings to filter out of found hostnames # @return [Array<String>] (optionally filtered) list of Stackato hostnames found def self.find_instances(ssh_config = '~/.ssh/config', filter = []) instances = IO.read(File.(ssh_config)) .scan(/^\s*Host (.*stackato.*)/) .flatten filter.each { |f| instances.delete_if { |host| host =~ /#{f}/ } } instances end # Retrieves patch manifest # @param uri [String, nil] path to the manifest.json # @return [Hash] the patch manifest def manifest(uri = nil) unless @manifest uri ||= "https://get.stackato.com/kato-patch/#{@version}/manifest.json" log "Retrieving latest manifest from: #{uri}" end @manifest ||= JSON.load(open(uri)) rescue nil end private # Outputs formatted debug messages to stderr # @param msg [String] debug message to output # @return [String] formatted debug message def log(msg) $stderr.puts ">> #{msg}" if @debug end end |
#version ⇒ String (readonly)
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/stackadmin/base.rb', line 34 class Stackadmin attr_reader :id, :version, :license, :nodes, :fresh # Initializes a new Stackadmin object # @param target [String] hostname/FQDN/IP address of the target node # @param port [Fixnum] port used to SSH into the target node # @param debug [Boolean] toggles display of debug information # @param yml_file [String, nil] pre-populated YAML file to pull node information from # @return [Stackadmin] new, populated object # @todo All paramaters, -target, should be in an opt[] hash def initialize(target, port = 22, debug = false, yml_file = nil) @port = port @debug = debug yml_file ? parse_yaml(target, yml_file) : audit(target) end # Refresh object data with a fresh audit # @param target [String, nil] optional hostname/FQDN/IP address of the target node # @todo Probably unneccessary? Deprecate? def refresh(target = nil) @id ||= target audit end # Parse through an SSH config to find possible Stackato hostnames # @param ssh_config [String] path to the SSH config file # @param filter [Array<String>] list of regex strings to filter out of found hostnames # @return [Array<String>] (optionally filtered) list of Stackato hostnames found def self.find_instances(ssh_config = '~/.ssh/config', filter = []) instances = IO.read(File.(ssh_config)) .scan(/^\s*Host (.*stackato.*)/) .flatten filter.each { |f| instances.delete_if { |host| host =~ /#{f}/ } } instances end # Retrieves patch manifest # @param uri [String, nil] path to the manifest.json # @return [Hash] the patch manifest def manifest(uri = nil) unless @manifest uri ||= "https://get.stackato.com/kato-patch/#{@version}/manifest.json" log "Retrieving latest manifest from: #{uri}" end @manifest ||= JSON.load(open(uri)) rescue nil end private # Outputs formatted debug messages to stderr # @param msg [String] debug message to output # @return [String] formatted debug message def log(msg) $stderr.puts ">> #{msg}" if @debug end end |
Class Method Details
.find_instances(ssh_config = '~/.ssh/config', filter = []) ⇒ Array<String>
Parse through an SSH config to find possible Stackato hostnames
62 63 64 65 66 67 68 |
# File 'lib/stackadmin/base.rb', line 62 def self.find_instances(ssh_config = '~/.ssh/config', filter = []) instances = IO.read(File.(ssh_config)) .scan(/^\s*Host (.*stackato.*)/) .flatten filter.each { |f| instances.delete_if { |host| host =~ /#{f}/ } } instances end |
Instance Method Details
#install!(patches = [], node = nil, local = false, restart = true, force_update = false, manifest_file = nil) ⇒ Hash
DRY this with ::mark! & ::reinstall! & ::revert!
collapse args into opt{}
Installs patch(es) to the targeted Stackato cluster
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/stackadmin/patch.rb', line 30 def install!(patches = [], node = nil, local = false, restart = true, force_update = false, manifest_file = nil) status = Hash.new output = patch('install', patches, node: node, local: local, no_restart: !restart, force_update: force_update, manifest: manifest_file) output.each do |p| p = p[:stdout] log "Job output:\n#{p}" p.gsub!(/\e\[\d+m/, '') # Strip ASCII color p.scan(/^Failed installing update (.+?) on (.+?)\.$/).each do |fp| status[fp[1]] = { installed: [], not_installed: [] } unless status.has_key?(fp[1]) status[fp[1]][:not_installed] << fp[0] end p.scan(/^Successfully installed update (.+?) on (.+?)\.$/).each do |sp| status[sp[1]] = { installed: [], not_installed: [] } unless status.has_key?(sp[1]) status[sp[1]][:installed] << sp[0] end end status end |
#manifest(uri = nil) ⇒ Hash
Retrieves patch manifest
73 74 75 76 77 78 79 80 |
# File 'lib/stackadmin/base.rb', line 73 def manifest(uri = nil) unless @manifest uri ||= "https://get.stackato.com/kato-patch/#{@version}/manifest.json" log "Retrieving latest manifest from: #{uri}" end @manifest ||= JSON.load(open(uri)) rescue nil end |
#mark!(patches = [], mark_installed = false, node = nil, local = false) ⇒ Hash
DRY this with ::install! & ::reinstall! & ::revert!
collapse args into opt{}
Marks patch(es) as installed or uninstalled on the targeted Stackato cluster Returns hash: { node1: [patch1, patch2], etc }
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/stackadmin/patch.rb', line 99 def mark!(patches = [], mark_installed = false, node = nil, local = false) status = Hash.new output = v3_action_check('mark') do patch('mark', patches, node: node, local: local, mark_installed: mark_installed) end output.each do |p| p = p[:stdout] log "Job output:\n#{p}" p.gsub!(/\e\[\d+m/, '') # Strip ASCII color p.scan(/^Successfully marked patch (.+?) as #{'not ' unless mark_installed}installed on (.+?)\.$/).each do |sp| # sp = Array of successfully marked patches # e.g. [["patch1-name", "node1-ip"], ["patch2-name", "node2-ip"]] status[sp[1]] = Array.new unless status.has_key?(sp[1]) status[sp[1]] << sp[0] end end status end |
#refresh(target = nil) ⇒ Object
Probably unneccessary? Deprecate?
Refresh object data with a fresh audit
53 54 55 56 |
# File 'lib/stackadmin/base.rb', line 53 def refresh(target = nil) @id ||= target audit end |
#reinstall!(patches = [], node = nil, local = false, restart = true, force_update = false, manifest_file = nil) ⇒ Hash
DRY this with ::install! & ::mark! & ::revert!
collapse args into opt{}
Reinstalls patch(es) to the targeted Stackato cluster
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/stackadmin/patch.rb', line 127 def reinstall!(patches = [], node = nil, local = false, restart = true, force_update = false, manifest_file = nil) if patches.empty? raise InvalidCommand, "kato patch reinstall requires a specific patchname!" else status = Hash.new output = patch('reinstall', patches, node: node, local: local, no_restart: !restart, force_update: force_update, manifest: manifest_file) output.each do |p| p = p[:stdout] log "Job output:\n#{p}" p.gsub!(/\e\[\d+m/, '') # Strip ASCII color p.scan(/^Failed installing update (.+?) on (.+?)\.$/).each do |fp| # fp = Array of failed patches # e.g. [["patch1-name", "node1-ip"], ["patch2-name", "node2-ip"]] status[fp[1]] = { installed: [], not_installed: [] } unless status.has_key?(fp[1]) status[fp[1]][:not_installed] << fp[0] end p.scan(/^Successfully installed update (.+?) on (.+?)\.$/).each do |sp| # sp = Array of successful patches. See fp example above status[sp[1]] = { installed: [], not_installed: [] } unless status.has_key?(sp[1]) status[sp[1]][:installed] << sp[0] end end status end end |
#report(*args) ⇒ String
Retrieve a report from the targeted Stackato
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/stackadmin/log.rb', line 18 def report(*args) opts = (args.last.class == Hash) ? args.pop : Hash.new opts[:destination] = '.' unless opts.has_key?(:destination) cmd = 'kato report' query = /^Report generated at (.+)\. / output = nil if args.include?(:cluster) cmd += ' --cluster' query = /^Your cluster 'kato report' is available at (.+)\.$/ end log "Generating #{'cluster ' if args.include?(:cluster)}report at #{@id}" ssh = Net::SSH.start(@id, 'stackato', port: @port) location = ssh.exec_sc!(cmd)[:stdout].match(query)[1] log "Report located at: #{@id}:#{location}" if args.include?(:tarball) filename = location.split('/').last output = File.(File.join(opts[:destination], filename)) log "Downloading tarball to: #{output}" ssh.scp.download!(location, opts[:destination]) else log 'Downloading report' tarball = StringIO.new(ssh.scp.download!(location)) log "Decompressing report to: #{opts[:destination]}" decompress_report(tarball, opts[:destination]) output = File.(opts[:destination]) output = File.join(output, 'stackato-report') unless args.include?(:cluster) end ssh.close output end |
#reset!(node = nil, local = false) ⇒ Boolean
collapse args into opt{}
Marks all of the targeted Stackato cluster’s patch updates as uninstalled
66 67 68 69 |
# File 'lib/stackadmin/patch.rb', line 66 def reset!(node = nil, local = false) output = patch('reset', [], node: node, local: local) output[0][:stdout] =~ /^Updates state reset.$/ ? true : false end |
#revert!(patches = [], node = nil, local = false, restart = true, force_update = false, manifest_file = nil) ⇒ Hash
DRY this with ::install! & ::mark!
collapse args into opt{}
Revert patch(es) on the targeted Stackato cluster
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/stackadmin/patch.rb', line 183 def revert!(patches = [], node = nil, local = false, restart = true, force_update = false, manifest_file = nil) status = Hash.new output = v3_action_check('revert') do patch('revert', patches, node: node, local: local, no_restart: !restart, force_update: force_update, manifest: manifest_file) end output.each do |p| p = p[:stdout] log "Job output:\n#{p}" p.gsub!(/\e\[\d+m/, '') # Strip ASCII color p.scan(/^Failed reverting update (.+?) on (.+?)\.$/).each do |fp| # fp = Array of failed patches # e.g. [["patch1-name", "node1-ip"], ["patch2-name", "node2-ip"]] status[fp[1]] = { reverted: [], not_reverted: [], unable_to_revert: [] } unless status.has_key?(fp[1]) status[fp[1]][:not_installed] << fp[0] end p.scan(/^Successfully reverted update (.+?) on (.+?)\.$/).each do |sp| # sp = Array of successful patches. See fp example above status[sp[1]] = { reverted: [], not_reverted: [], unable_to_revert: [] } unless status.has_key?(sp[1]) status[sp[1]][:installed] << sp[0] end end status end |
#to_yaml ⇒ String
8 9 10 11 12 13 |
# File 'lib/stackadmin/yaml.rb', line 8 def to_yaml { 'id' => @id, 'version' => @version, 'license' => @license, 'nodes' => @nodes }.to_yaml end |
#update!(node = nil, local = false, manifest_file = nil) ⇒ Boolean
collapse args into opt{}
Updates the patch manifest for the targeted Stackato cluster
77 78 79 80 81 82 83 |
# File 'lib/stackadmin/patch.rb', line 77 def update!(node = nil, local = false, manifest_file = nil) output = v3_action_check('update') do patch('update', [], node: node, local: local, manifest: manifest_file) end output[0][:stdout] =~ /^done!$/ ? true : false end |