train 3.2.14 → 3.2.20

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 (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