Module: Train::Platforms::Detect::Helpers::OSCommon

Includes:
Linux, Windows
Included in:
Scanner, UUID
Defined in:
lib/train/platforms/detect/helpers/os_common.rb

Instance Method Summary collapse

Methods included from Windows

#check_cmd, #check_powershell, #detect_windows, #local_windows?, #read_wmic, #read_wmic_cpu, #windows_uuid, #windows_uuid_from_chef, #windows_uuid_from_machine_file, #windows_uuid_from_registry, #windows_uuid_from_wmic

Methods included from Linux

#linux_os_release, #lsb_config, #lsb_release, #parse_os_release_info, #read_linux_lsb, #redhatish, #redhatish_platform, #redhatish_version

Instance Method Details

#backend_nameObject



18
19
20
# File 'lib/train/platforms/detect/helpers/os_common.rb', line 18

def backend_name
  @backend.class.name
end

#brocade_versionObject



75
76
77
78
79
80
81
82
83
# File 'lib/train/platforms/detect/helpers/os_common.rb', line 75

def brocade_version
  return @cache[:brocade] if @cache.key?(:brocade)

  res = command_output("version")

  m = res.match(/^Fabric OS:\s+v(\S+)$/)

  @cache[:brocade] = m && { version: m[1], type: "fos" }
end

#cisco_show_versionObject



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/train/platforms/detect/helpers/os_common.rb', line 85

def cisco_show_version
  return @cache[:cisco] if @cache.key?(:cisco)

  res = command_output("show version")

  m = res.match(/Cisco IOS Software, [^,]+? \(([^,]+?)\), Version (\d+\.\d+)/)
  unless m.nil?
    return @cache[:cisco] = { version: m[2], model: m[1], type: "ios" }
  end

  m = res.match(/Cisco IOS Software, IOS-XE Software, [^,]+? \(([^,]+?)\), Version (\d+\.\d+\.\d+[A-Z]*)/)
  unless m.nil?
    return @cache[:cisco] = { version: m[2], model: m[1], type: "ios-xe" }
  end

  # CSR 1000V (for example) does not specify model
  m = res.match(/Cisco IOS XE Software, Version (\d+\.\d+\.\d+[A-Z]*)/)
  unless m.nil?
    return @cache[:cisco] = { version: m[1], type: "ios-xe" }
  end

  m = res.match(/Cisco Nexus Operating System \(NX-OS\) Software/)
  unless m.nil?
    v = res[/^\s*system:\s+version (\d+\.\d+)/, 1]
    v ||= res[/NXOS: version (\d+\.\d+)/, 1]
    return @cache[:cisco] = { version: v, type: "nexus" }
  end

  @cache[:cisco] = nil
end

#command_output(cmd) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/train/platforms/detect/helpers/os_common.rb', line 36

def command_output(cmd)
  res = @backend.run_command(cmd)
  stdout = res.stdout
  stderr = res.stderr
  # When you try to execute command using ssh connection as root user and you have provided ssh user identity file
  # it gives standard output to login as authorized user other than root. To show this standard output as an error
  # to user we are matching the string of stdout and raising the error here so that user gets exact information.
  if @backend.class.to_s == "Train::Transports::SSH::Connection"
    if stdout =~ /Please login as the user/
      raise Train::UserError, "SSH failed: #{stdout}"
    end

    if stderr =~ /WARNING: Your password has expired/
      raise Train::UserError, "SSH failed: #{stderr}"
    end
  end

  stdout.strip! unless stdout.nil?
  stdout
end

#json_cmd(cmd) ⇒ Object



171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/train/platforms/detect/helpers/os_common.rb', line 171

def json_cmd(cmd)
  cmd = @backend.run_command(cmd)
  if cmd.exit_status == 0 && !cmd.stdout.empty?
    require "json" unless defined?(JSON)
    eos_ver = JSON.parse(cmd.stdout)
    @platform[:release] = eos_ver["version"]
    @platform[:arch] = eos_ver["architecture"]
    true
  end
rescue JSON::ParserError
  nil
end

#ruby_host_os(regex) ⇒ Object



10
11
12
# File 'lib/train/platforms/detect/helpers/os_common.rb', line 10

def ruby_host_os(regex)
  ::RbConfig::CONFIG["host_os"] =~ regex
end

#set_from_unameObject



184
185
186
187
188
# File 'lib/train/platforms/detect/helpers/os_common.rb', line 184

def set_from_uname
  @platform[:name]    = unix_uname_s.lines.first.chomp
  @platform[:release] = unix_uname_r.lines.first.chomp
  true
end

#unix_file_contents(path) ⇒ Object



22
23
24
25
26
27
28
29
30
# File 'lib/train/platforms/detect/helpers/os_common.rb', line 22

def unix_file_contents(path)
  # keep a log of files incase multiple checks call the same one
  return @files[path] if @files.key?(path)

  res = @backend.run_command("test -f #{path} && cat #{path}")
  # ignore files that can't be read
  @files[path] = res.exit_status == 0 ? res.stdout : nil
  @files[path]
end

#unix_file_exist?(path) ⇒ Boolean

Returns:

  • (Boolean)


32
33
34
# File 'lib/train/platforms/detect/helpers/os_common.rb', line 32

def unix_file_exist?(path)
  @backend.run_command("test -f #{path}").exit_status == 0
end

#unix_uname_mObject



69
70
71
72
73
# File 'lib/train/platforms/detect/helpers/os_common.rb', line 69

def unix_uname_m
  return @uname[:m] if @uname.key?(:m)

  @uname[:m] = command_output("uname -m")
end

#unix_uname_rObject



63
64
65
66
67
# File 'lib/train/platforms/detect/helpers/os_common.rb', line 63

def unix_uname_r
  return @uname[:r] if @uname.key?(:r)

  @uname[:r] = command_output("uname -r")
end

#unix_uname_sObject



57
58
59
60
61
# File 'lib/train/platforms/detect/helpers/os_common.rb', line 57

def unix_uname_s
  return @uname[:s] if @uname.key?(:s)

  @uname[:s] = command_output("uname -s")
end

#unix_uuidObject



116
117
118
119
120
121
# File 'lib/train/platforms/detect/helpers/os_common.rb', line 116

def unix_uuid
  (unix_uuid_from_chef         ||
   unix_uuid_from_machine_file ||
   uuid_from_command           ||
   raise(Train::TransportError, "Cannot find a UUID for your node."))
end

#unix_uuid_from_chefObject



123
124
125
126
127
128
129
# File 'lib/train/platforms/detect/helpers/os_common.rb', line 123

def unix_uuid_from_chef
  file = @backend.file("/var/chef/cache/data_collector_metadata.json")
  if file.exist? && file.size != 0
    json = ::JSON.parse(file.content)
    return json["node_uuid"] if json["node_uuid"]
  end
end

#unix_uuid_from_machine_fileObject



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/train/platforms/detect/helpers/os_common.rb', line 131

def unix_uuid_from_machine_file
  %W{
    /etc/chef/chef_guid
    #{ENV["HOME"]}/.chef/chef_guid
    /etc/machine-id
    /var/lib/dbus/machine-id
    /var/db/dbus/machine-id
  }.each do |path|
    file = @backend.file(path)
    next unless file.exist? && file.size != 0
    return file.content.chomp if path =~ /guid/

    return uuid_from_string(file.content.chomp)
  end
  nil
end

#uuid_from_commandObject

This takes a command from the platform detect block to run. We expect the command to return a unique identifier which we turn into a UUID.



151
152
153
154
155
156
# File 'lib/train/platforms/detect/helpers/os_common.rb', line 151

def uuid_from_command
  return unless @platform[:uuid_command]

  result = @backend.run_command(@platform[:uuid_command])
  uuid_from_string(result.stdout.chomp) if result.exit_status == 0 && !result.stdout.empty?
end

#uuid_from_string(string) ⇒ Object

This hashes the passed string into SHA1. Then it downgrades the 160bit SHA1 to a 128bit then we format it as a valid UUIDv5.



161
162
163
164
165
166
167
168
169
# File 'lib/train/platforms/detect/helpers/os_common.rb', line 161

def uuid_from_string(string)
  hash = Digest::SHA1.new
  hash.update(string)
  ary = hash.digest.unpack("NnnnnN")
  ary[2] = (ary[2] & 0x0FFF) | (5 << 12)
  ary[3] = (ary[3] & 0x3FFF) | 0x8000
  # rubocop:disable Style/FormatString
  "%08x-%04x-%04x-%04x-%04x%08x" % ary
end

#winrm?Boolean

Returns:

  • (Boolean)


14
15
16
# File 'lib/train/platforms/detect/helpers/os_common.rb', line 14

def winrm?
  backend_name == "TrainPlugins::WinRM::Connection"
end