train 3.2.14 → 3.2.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. metadata +29 -149
  3. data/LICENSE +0 -201
  4. data/lib/train.rb +0 -193
  5. data/lib/train/errors.rb +0 -44
  6. data/lib/train/extras.rb +0 -11
  7. data/lib/train/extras/command_wrapper.rb +0 -201
  8. data/lib/train/extras/stat.rb +0 -136
  9. data/lib/train/file.rb +0 -212
  10. data/lib/train/file/local.rb +0 -82
  11. data/lib/train/file/local/unix.rb +0 -96
  12. data/lib/train/file/local/windows.rb +0 -68
  13. data/lib/train/file/remote.rb +0 -40
  14. data/lib/train/file/remote/aix.rb +0 -29
  15. data/lib/train/file/remote/linux.rb +0 -21
  16. data/lib/train/file/remote/qnx.rb +0 -41
  17. data/lib/train/file/remote/unix.rb +0 -110
  18. data/lib/train/file/remote/windows.rb +0 -110
  19. data/lib/train/globals.rb +0 -5
  20. data/lib/train/options.rb +0 -81
  21. data/lib/train/platforms.rb +0 -102
  22. data/lib/train/platforms/common.rb +0 -34
  23. data/lib/train/platforms/detect.rb +0 -12
  24. data/lib/train/platforms/detect/helpers/os_common.rb +0 -160
  25. data/lib/train/platforms/detect/helpers/os_linux.rb +0 -80
  26. data/lib/train/platforms/detect/helpers/os_windows.rb +0 -142
  27. data/lib/train/platforms/detect/scanner.rb +0 -85
  28. data/lib/train/platforms/detect/specifications/api.rb +0 -20
  29. data/lib/train/platforms/detect/specifications/os.rb +0 -629
  30. data/lib/train/platforms/detect/uuid.rb +0 -32
  31. data/lib/train/platforms/family.rb +0 -31
  32. data/lib/train/platforms/platform.rb +0 -109
  33. data/lib/train/plugin_test_helper.rb +0 -51
  34. data/lib/train/plugins.rb +0 -40
  35. data/lib/train/plugins/base_connection.rb +0 -198
  36. data/lib/train/plugins/transport.rb +0 -49
  37. data/lib/train/transports/cisco_ios_connection.rb +0 -133
  38. data/lib/train/transports/local.rb +0 -240
  39. data/lib/train/transports/mock.rb +0 -183
  40. data/lib/train/transports/ssh.rb +0 -271
  41. data/lib/train/transports/ssh_connection.rb +0 -342
  42. data/lib/train/version.rb +0 -7
@@ -1,136 +0,0 @@
1
- # encoding: utf-8
2
- # author: Dominik Richter
3
- # author: Christoph Hartmann
4
- module Train::Extras
5
- class Stat
6
- TYPES = {
7
- socket: 00140000,
8
- symlink: 00120000,
9
- file: 00100000,
10
- block_device: 00060000,
11
- directory: 00040000,
12
- character_device: 00020000,
13
- pipe: 00010000,
14
- }.freeze
15
-
16
- def self.find_type(mode)
17
- res = TYPES.find { |_, mask| mask & mode == mask }
18
- res.nil? ? :unknown : res[0]
19
- end
20
-
21
- def self.stat(shell_escaped_path, backend, follow_symlink)
22
- # use perl scripts for aix, solaris 10 and hpux
23
- if backend.os.aix? || (backend.os.solaris? && backend.os[:release].to_i < 11) || backend.os.hpux?
24
- return aix_stat(shell_escaped_path, backend, follow_symlink)
25
- end
26
- return bsd_stat(shell_escaped_path, backend, follow_symlink) if backend.os.bsd?
27
- # linux,solaris 11 and esx will use standard linux stats
28
- return linux_stat(shell_escaped_path, backend, follow_symlink) if backend.os.unix? || backend.os.esx?
29
-
30
- # all other cases we don't handle
31
- # TODO: print an error if we get here, as it shouldn't be invoked
32
- # on non-unix
33
- {}
34
- end
35
-
36
- def self.linux_stat(shell_escaped_path, backend, follow_symlink)
37
- lstat = follow_symlink ? " -L" : ""
38
- format = (backend.os.esx? || backend.os[:name] == "alpine" || backend.os[:name] == "yocto") ? "-c" : "--printf"
39
- res = backend.run_command("stat#{lstat} #{shell_escaped_path} 2>/dev/null #{format} '%s\n%f\n%U\n%u\n%G\n%g\n%X\n%Y\n%C'")
40
- # ignore the exit_code: it is != 0 if selinux labels are not supported
41
- # on the system.
42
-
43
- fields = res.stdout.split("\n")
44
- return {} if fields.length != 9
45
-
46
- tmask = fields[1].to_i(16)
47
- selinux = fields[8]
48
- ## selinux security context string not available on esxi
49
- selinux = nil if (selinux == "?") || (selinux == "(null)") || (selinux == "C")
50
- {
51
- type: find_type(tmask),
52
- mode: tmask & 07777,
53
- owner: fields[2],
54
- uid: fields[3].to_i,
55
- group: fields[4],
56
- gid: fields[5].to_i,
57
- mtime: fields[7].to_i,
58
- size: fields[0].to_i,
59
- selinux_label: selinux,
60
- }
61
- end
62
-
63
- def self.bsd_stat(shell_escaped_path, backend, follow_symlink)
64
- # From stat man page on FreeBSD:
65
- # z The size of file in bytes (st_size).
66
- # p File type and permissions (st_mode).
67
- # u, g User ID and group ID of file's owner (st_uid, st_gid).
68
- # a, m, c, B
69
- # The time file was last accessed or modified, or when the
70
- # inode was last changed, or the birth time of the inode
71
- # (st_atime, st_mtime, st_ctime, st_birthtime).
72
- #
73
- # The special output specifier S may be used to indicate that the
74
- # output, if applicable, should be in string format. May be used
75
- # in combination with:
76
- # ...
77
- # gu Display group or user name.
78
- lstat = follow_symlink ? " -L" : ""
79
- res = backend.run_command(
80
- "stat#{lstat} -f '%z\n%p\n%Su\n%u\n%Sg\n%g\n%a\n%m' "\
81
- "#{shell_escaped_path}"
82
- )
83
-
84
- return {} if res.exit_status != 0
85
-
86
- fields = res.stdout.split("\n")
87
- return {} if fields.length != 8
88
-
89
- tmask = fields[1].to_i(8)
90
-
91
- {
92
- type: find_type(tmask),
93
- mode: tmask & 07777,
94
- owner: fields[2],
95
- uid: fields[3].to_i,
96
- group: fields[4],
97
- gid: fields[5].to_i,
98
- mtime: fields[7].to_i,
99
- size: fields[0].to_i,
100
- selinux_label: fields[8],
101
- }
102
- end
103
-
104
- def self.aix_stat(shell_escaped_path, backend, follow_symlink)
105
- # Perl here b/c it is default on AIX
106
- lstat = follow_symlink ? "lstat" : "stat"
107
- stat_cmd = <<-EOP
108
- perl -e '
109
- @a = #{lstat}(shift) or exit 2;
110
- $u = getpwuid($a[4]);
111
- $g = getgrgid($a[5]);
112
- printf("0%o\\n%s\\n%d\\n%s\\n%d\\n%d\\n%d\\n", $a[2], $u, $a[4], $g, $a[5], $a[9], $a[7])
113
- ' #{shell_escaped_path}
114
- EOP
115
-
116
- res = backend.run_command(stat_cmd)
117
- return {} if res.exit_status != 0
118
-
119
- fields = res.stdout.split("\n")
120
- return {} if fields.length != 7
121
-
122
- tmask = fields[0].to_i(8)
123
- {
124
- type: find_type(tmask),
125
- mode: tmask & 07777,
126
- owner: fields[1],
127
- uid: fields[2].to_i,
128
- group: fields[3],
129
- gid: fields[4].to_i,
130
- mtime: fields[5].to_i,
131
- size: fields[6].to_i,
132
- selinux_label: nil,
133
- }
134
- end
135
- end
136
- end
data/lib/train/file.rb DELETED
@@ -1,212 +0,0 @@
1
- # encoding: utf-8
2
- #
3
- # author: Christoph Hartmann
4
- # author: Dominik Richter
5
-
6
- require_relative "file/local"
7
- require_relative "file/remote"
8
- require_relative "extras/stat"
9
-
10
- module Train
11
- class File # rubocop:disable Metrics/ClassLength
12
- def initialize(backend, path, follow_symlink = true)
13
- @backend = backend
14
- @path = path || ""
15
- @follow_symlink = follow_symlink
16
-
17
- sanitize_filename(path)
18
- end
19
-
20
- # This method gets override by particular os class.
21
- def sanitize_filename(_path)
22
- nil
23
- end
24
-
25
- # interface methods: these fields should be implemented by every
26
- # backend File
27
- DATA_FIELDS = %w{
28
- exist? mode owner group uid gid content mtime size selinux_label path
29
- }.freeze
30
-
31
- DATA_FIELDS.each do |m|
32
- next if m == "path"
33
-
34
- define_method m do
35
- raise NotImplementedError, "File must implement the #{m}() method."
36
- end
37
- end
38
-
39
- def to_json
40
- res = Hash[DATA_FIELDS.map { |x| [x, method(x).call] }]
41
- # additional fields provided as input
42
- res["type"] = type
43
- res["follow_symlink"] = @follow_symlink
44
- res
45
- end
46
-
47
- def type
48
- :unknown
49
- end
50
-
51
- def source
52
- if @follow_symlink
53
- self.class.new(@backend, @path, false)
54
- else
55
- self
56
- end
57
- end
58
-
59
- def source_path
60
- @path
61
- end
62
-
63
- # product_version is primarily used by Windows operating systems only and will be overwritten
64
- # in Windows-related classes. Since this field is returned for all file objects, the acceptable
65
- # default value is nil
66
- def product_version
67
- nil
68
- end
69
-
70
- # file_version is primarily used by Windows operating systems only and will be overwritten
71
- # in Windows-related classes. Since this field is returned for all file objects, the acceptable
72
- # default value is nil
73
- def file_version
74
- nil
75
- end
76
-
77
- def version?(version)
78
- (product_version == version) ||
79
- (file_version == version)
80
- end
81
-
82
- def block_device?
83
- type.to_s == "block_device"
84
- end
85
-
86
- def character_device?
87
- type.to_s == "character_device"
88
- end
89
-
90
- def pipe?
91
- type.to_s == "pipe"
92
- end
93
-
94
- def file?
95
- type.to_s == "file"
96
- end
97
-
98
- def socket?
99
- type.to_s == "socket"
100
- end
101
-
102
- def directory?
103
- type.to_s == "directory"
104
- end
105
-
106
- def symlink?
107
- source.type.to_s == "symlink"
108
- end
109
-
110
- def owned_by?(sth)
111
- owner == sth
112
- end
113
-
114
- def path
115
- if symlink? && @follow_symlink
116
- link_path
117
- else
118
- @path
119
- end
120
- end
121
-
122
- # if the OS-specific file class supports inquirying as to whether the
123
- # file/device is mounted, the #mounted method should return a command
124
- # object whose stdout will not be nil if indeed the device is mounted.
125
- #
126
- # if the OS-specific file class does not support checking for mount
127
- # status, the method should not be implemented and this method will
128
- # return false.
129
- def mounted?
130
- return false unless respond_to?(:mounted)
131
-
132
- !mounted.nil? && !mounted.stdout.nil? && !mounted.stdout.empty?
133
- end
134
-
135
- def md5sum
136
- # Skip processing rest of method if fallback method is selected
137
- return perform_checksum_ruby(:md5) if defined?(@ruby_checksum_fallback)
138
-
139
- checksum = if @backend.os.family == "windows"
140
- perform_checksum_windows(:md5)
141
- else
142
- @md5_command ||= case @backend.os.family
143
- when "darwin"
144
- "md5 -r"
145
- when "solaris"
146
- "digest -a md5"
147
- else
148
- "md5sum"
149
- end
150
-
151
- perform_checksum_unix(@md5_command)
152
- end
153
-
154
- checksum || perform_checksum_ruby(:md5)
155
- end
156
-
157
- def sha256sum
158
- # Skip processing rest of method if fallback method is selected
159
- return perform_checksum_ruby(:sha256) if defined?(@ruby_checksum_fallback)
160
-
161
- checksum = if @backend.os.family == "windows"
162
- perform_checksum_windows(:sha256)
163
- else
164
- @sha256_command ||= case @backend.os.family
165
- when "darwin", "hpux", "qnx"
166
- "shasum -a 256"
167
- when "solaris"
168
- "digest -a sha256"
169
- else
170
- "sha256sum"
171
- end
172
-
173
- perform_checksum_unix(@sha256_command)
174
- end
175
-
176
- checksum || perform_checksum_ruby(:sha256)
177
- end
178
-
179
- private
180
-
181
- def perform_checksum_unix(cmd)
182
- res = @backend.run_command("#{cmd} #{@path}")
183
- res.stdout.split(" ").first if res.exit_status == 0
184
- end
185
-
186
- def perform_checksum_windows(method)
187
- cmd = "CertUtil -hashfile #{@path} #{method.to_s.upcase}"
188
- res = @backend.run_command(cmd)
189
- res.stdout.split("\r\n")[1].tr(" ", "") if res.exit_status == 0
190
- end
191
-
192
- # This pulls the content of the file to the machine running Train and uses
193
- # Digest to perform the checksum. This is less efficient than using remote
194
- # system binaries and can lead to incorrect results due to encoding.
195
- def perform_checksum_ruby(method)
196
- # This is used to skip attempting other checksum methods. If this is set
197
- # then we know all other methods have failed.
198
- @ruby_checksum_fallback = true
199
- case method
200
- when :md5
201
- res = Digest::MD5.new
202
- when :sha256
203
- res = Digest::SHA256.new
204
- end
205
-
206
- res.update(content)
207
- res.hexdigest
208
- rescue TypeError => _
209
- nil
210
- end
211
- end
212
- end
@@ -1,82 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Train
4
- class File
5
- class Local < Train::File
6
- %w{
7
- exist? file? socket? directory? symlink? pipe? size basename
8
- }.each do |m|
9
- define_method m.to_sym do
10
- ::File.method(m.to_sym).call(@path)
11
- end
12
- end
13
-
14
- def content
15
- @content ||= ::File.read(@path, encoding: "UTF-8")
16
- rescue StandardError => _
17
- nil
18
- end
19
-
20
- def link_path
21
- return nil unless symlink?
22
-
23
- begin
24
- @link_path ||= ::File.realpath(@path)
25
- rescue Errno::ELOOP => _
26
- # Leave it blank on symbolic loop, same as readlink
27
- @link_path = ""
28
- end
29
- end
30
-
31
- def shallow_link_path
32
- return nil unless symlink?
33
-
34
- @link_path ||= ::File.readlink(@path)
35
- end
36
-
37
- def block_device?
38
- ::File.blockdev?(@path)
39
- end
40
-
41
- def character_device?
42
- ::File.chardev?(@path)
43
- end
44
-
45
- def type
46
- case ::File.ftype(@path)
47
- when "blockSpecial"
48
- :block_device
49
- when "characterSpecial"
50
- :character_device
51
- when "link"
52
- :symlink
53
- when "fifo"
54
- :pipe
55
- else
56
- ::File.ftype(@path).to_sym
57
- end
58
- end
59
-
60
- %w{
61
- mode owner group uid gid mtime selinux_label
62
- }.each do |field|
63
- define_method field.to_sym do
64
- stat[field.to_sym]
65
- end
66
- end
67
-
68
- def mode?(sth)
69
- mode == sth
70
- end
71
-
72
- def linked_to?(dst)
73
- link_path == dst
74
- end
75
- end
76
- end
77
- end
78
-
79
- # subclass requires are loaded after Train::File::Local is defined
80
- # to avoid superclass mismatch errors
81
- require_relative "local/unix"
82
- require_relative "local/windows"
@@ -1,96 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require "shellwords"
4
- require_relative "../../extras/stat"
5
-
6
- module Train
7
- class File
8
- class Local
9
- class Unix < Train::File::Local
10
- def sanitize_filename(path)
11
- @spath = Shellwords.escape(path) || @path
12
- end
13
-
14
- def stat
15
- return @stat if defined?(@stat)
16
-
17
- begin
18
- file_stat =
19
- if @follow_symlink
20
- ::File.stat(@path)
21
- else
22
- ::File.lstat(@path)
23
- end
24
- rescue StandardError => _err
25
- return @stat = {}
26
- end
27
-
28
- @stat = {
29
- type: Train::Extras::Stat.find_type(file_stat.mode),
30
- mode: file_stat.mode & 07777,
31
- mtime: file_stat.mtime.to_i,
32
- size: file_stat.size,
33
- owner: pw_username(file_stat.uid),
34
- uid: file_stat.uid,
35
- group: pw_groupname(file_stat.gid),
36
- gid: file_stat.gid,
37
- }
38
-
39
- lstat = @follow_symlink ? " -L" : ""
40
- res = @backend.run_command("stat#{lstat} #{@spath} 2>/dev/null --printf '%C'")
41
- if res.exit_status == 0 && !res.stdout.empty? && res.stdout != "?"
42
- @stat[:selinux_label] = res.stdout.strip
43
- end
44
-
45
- @stat
46
- end
47
-
48
- def mounted
49
- @mounted ||=
50
- @backend.run_command("mount | grep -- ' on #{@path} '")
51
- end
52
-
53
- def grouped_into?(sth)
54
- group == sth
55
- end
56
-
57
- def unix_mode_mask(owner, type)
58
- o = UNIX_MODE_OWNERS[owner.to_sym]
59
- return nil if o.nil?
60
-
61
- t = UNIX_MODE_TYPES[type.to_sym]
62
- return nil if t.nil?
63
-
64
- t & o
65
- end
66
-
67
- private
68
-
69
- def pw_username(uid)
70
- Etc.getpwuid(uid).name
71
- rescue ArgumentError => _
72
- nil
73
- end
74
-
75
- def pw_groupname(gid)
76
- Etc.getgrgid(gid).name
77
- rescue ArgumentError => _
78
- nil
79
- end
80
-
81
- UNIX_MODE_OWNERS = {
82
- all: 00777,
83
- owner: 00700,
84
- group: 00070,
85
- other: 00007,
86
- }.freeze
87
-
88
- UNIX_MODE_TYPES = {
89
- r: 00444,
90
- w: 00222,
91
- x: 00111,
92
- }.freeze
93
- end
94
- end
95
- end
96
- end