train 0.12.1

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 (87) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +71 -0
  3. data/CHANGELOG.md +308 -0
  4. data/Gemfile +30 -0
  5. data/LICENSE +201 -0
  6. data/README.md +156 -0
  7. data/Rakefile +148 -0
  8. data/lib/train.rb +117 -0
  9. data/lib/train/errors.rb +23 -0
  10. data/lib/train/extras.rb +17 -0
  11. data/lib/train/extras/command_wrapper.rb +148 -0
  12. data/lib/train/extras/file_aix.rb +20 -0
  13. data/lib/train/extras/file_common.rb +161 -0
  14. data/lib/train/extras/file_linux.rb +16 -0
  15. data/lib/train/extras/file_unix.rb +79 -0
  16. data/lib/train/extras/file_windows.rb +91 -0
  17. data/lib/train/extras/linux_lsb.rb +60 -0
  18. data/lib/train/extras/os_common.rb +136 -0
  19. data/lib/train/extras/os_detect_darwin.rb +32 -0
  20. data/lib/train/extras/os_detect_linux.rb +148 -0
  21. data/lib/train/extras/os_detect_unix.rb +99 -0
  22. data/lib/train/extras/os_detect_windows.rb +57 -0
  23. data/lib/train/extras/stat.rb +133 -0
  24. data/lib/train/options.rb +80 -0
  25. data/lib/train/plugins.rb +40 -0
  26. data/lib/train/plugins/base_connection.rb +86 -0
  27. data/lib/train/plugins/transport.rb +49 -0
  28. data/lib/train/transports/docker.rb +103 -0
  29. data/lib/train/transports/local.rb +52 -0
  30. data/lib/train/transports/local_file.rb +90 -0
  31. data/lib/train/transports/local_os.rb +51 -0
  32. data/lib/train/transports/mock.rb +147 -0
  33. data/lib/train/transports/ssh.rb +163 -0
  34. data/lib/train/transports/ssh_connection.rb +225 -0
  35. data/lib/train/transports/winrm.rb +184 -0
  36. data/lib/train/transports/winrm_connection.rb +194 -0
  37. data/lib/train/version.rb +7 -0
  38. data/test/integration/.kitchen.yml +43 -0
  39. data/test/integration/Berksfile +3 -0
  40. data/test/integration/bootstrap.sh +17 -0
  41. data/test/integration/chefignore +1 -0
  42. data/test/integration/cookbooks/test/metadata.rb +1 -0
  43. data/test/integration/cookbooks/test/recipes/default.rb +100 -0
  44. data/test/integration/cookbooks/test/recipes/prep_files.rb +47 -0
  45. data/test/integration/docker_run.rb +153 -0
  46. data/test/integration/docker_test.rb +24 -0
  47. data/test/integration/docker_test_container.rb +24 -0
  48. data/test/integration/helper.rb +61 -0
  49. data/test/integration/sudo/customcommand.rb +15 -0
  50. data/test/integration/sudo/nopasswd.rb +16 -0
  51. data/test/integration/sudo/passwd.rb +21 -0
  52. data/test/integration/sudo/reqtty.rb +17 -0
  53. data/test/integration/sudo/run_as.rb +12 -0
  54. data/test/integration/test-travis-1.yaml +13 -0
  55. data/test/integration/test-travis-2.yaml +13 -0
  56. data/test/integration/test_local.rb +19 -0
  57. data/test/integration/test_ssh.rb +39 -0
  58. data/test/integration/tests/path_block_device_test.rb +74 -0
  59. data/test/integration/tests/path_character_device_test.rb +74 -0
  60. data/test/integration/tests/path_file_test.rb +79 -0
  61. data/test/integration/tests/path_folder_test.rb +90 -0
  62. data/test/integration/tests/path_missing_test.rb +77 -0
  63. data/test/integration/tests/path_pipe_test.rb +78 -0
  64. data/test/integration/tests/path_symlink_test.rb +95 -0
  65. data/test/integration/tests/run_command_test.rb +28 -0
  66. data/test/unit/extras/command_wrapper_test.rb +78 -0
  67. data/test/unit/extras/file_common_test.rb +180 -0
  68. data/test/unit/extras/linux_file_test.rb +167 -0
  69. data/test/unit/extras/os_common_test.rb +269 -0
  70. data/test/unit/extras/os_detect_linux_test.rb +189 -0
  71. data/test/unit/extras/os_detect_windows_test.rb +99 -0
  72. data/test/unit/extras/stat_test.rb +148 -0
  73. data/test/unit/extras/windows_file_test.rb +44 -0
  74. data/test/unit/helper.rb +7 -0
  75. data/test/unit/plugins/connection_test.rb +44 -0
  76. data/test/unit/plugins/transport_test.rb +111 -0
  77. data/test/unit/plugins_test.rb +22 -0
  78. data/test/unit/train_test.rb +156 -0
  79. data/test/unit/transports/local_file_test.rb +184 -0
  80. data/test/unit/transports/local_test.rb +87 -0
  81. data/test/unit/transports/mock_test.rb +87 -0
  82. data/test/unit/transports/ssh_test.rb +109 -0
  83. data/test/unit/version_test.rb +8 -0
  84. data/test/windows/local_test.rb +46 -0
  85. data/test/windows/winrm_test.rb +52 -0
  86. data/train.gemspec +38 -0
  87. metadata +295 -0
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+ # author: Jeremy Miller
3
+
4
+ require_relative 'run_as'
5
+
6
+ describe 'run custom sudo command' do
7
+ it 'is running as non-root without sudo' do
8
+ run_as('whoami').stdout.wont_match(/root/i)
9
+ end
10
+
11
+ it 'is running nopasswd custom sudo command' do
12
+ run_as('whoami', { sudo: true, sudo_command: 'allyourbase' })
13
+ .stdout.must_match(/root/i)
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+ # author: Dominik Richter
3
+ # author: Christoph Hartmann
4
+
5
+ require_relative 'run_as'
6
+
7
+ describe 'run_command' do
8
+ it 'is running as non-root without sudo' do
9
+ run_as('whoami').stdout.wont_match /root/i
10
+ end
11
+
12
+ it 'is running nopasswd sudo' do
13
+ run_as('whoami', { sudo: true })
14
+ .stdout.must_match /root/i
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+ # author: Dominik Richter
3
+ # author: Christoph Hartmann
4
+
5
+ require_relative 'run_as'
6
+
7
+ describe 'run_command' do
8
+ it 'is running as non-root without sudo' do
9
+ run_as('whoami').stdout.wont_match /root/i
10
+ end
11
+
12
+ it 'is not running sudo without password' do
13
+ err = ->{Train.create('local', { sudo: true }).connection}.must_raise Train::UserError
14
+ err.message.must_match /Sudo requires a password/
15
+ end
16
+
17
+ it 'is running passwd sudo' do
18
+ run_as('whoami', { sudo: true, sudo_password: 'password' })
19
+ .stdout.must_match /root/i
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+ # author: Dominik Richter
3
+ # author: Christoph Hartmann
4
+ # author: Stephan Renatus
5
+
6
+ require_relative 'run_as'
7
+
8
+ describe 'run_command' do
9
+ it 'is running as non-root without sudo' do
10
+ run_as('whoami').stdout.wont_match /root/i
11
+ end
12
+
13
+ it 'is throwing an error trying to use sudo' do
14
+ err = ->{ run_as('whoami', { sudo: true }) }.must_raise Train::UserError
15
+ err.message.must_match /Sudo failed: Sudo requires a TTY. Please see the README/i
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+ # author: Dominik Richter
3
+ # author: Christoph Hartmann
4
+
5
+ require_relative '../helper'
6
+ require 'train'
7
+
8
+ def run_as(cmd, opts = {})
9
+ Train.create('local', opts)
10
+ .connection
11
+ .run_command(cmd)
12
+ end
@@ -0,0 +1,13 @@
1
+ images:
2
+ - centos:6.6
3
+ - centos:6.7
4
+ - centos:7.1.1503
5
+ - debian:7.9
6
+ - debian:8.2
7
+ - fedora:21
8
+ - fedora:22
9
+ - ubuntu:12.04
10
+ - ubuntu:14.04
11
+ - ubuntu:15.04
12
+ provision:
13
+ - script: bootstrap.sh
@@ -0,0 +1,13 @@
1
+ images:
2
+ - centos:5.11
3
+ - centos:7.0.1406
4
+ - debian:6.0.10
5
+ - fedora:20
6
+ - oraclelinux:5.11
7
+ - oraclelinux:6.7
8
+ - oraclelinux:7.1
9
+ - ubuntu:10.04
10
+ - ubuntu:13.04
11
+ - ubuntu:15.10
12
+ provision:
13
+ - script: bootstrap.sh
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+ # author: Dominik Richter
3
+
4
+ require_relative 'helper'
5
+ require 'train'
6
+
7
+ backends = {}
8
+
9
+ backends[:local] = proc { |*opts|
10
+ Train.create('local', {}).connection(opts[0])
11
+ }
12
+
13
+ tests = ARGV
14
+
15
+ backends.each do |type, get_backend|
16
+ tests.each do |test|
17
+ instance_eval(File.read(test), test, 1)
18
+ end
19
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+ # author: Dominik Richter
3
+
4
+ require_relative 'helper'
5
+ require 'train'
6
+ require 'logger'
7
+
8
+ backends = {}
9
+ backend_conf = {
10
+ 'target' => ENV['target'] || 'vagrant@localhost',
11
+ 'key_files' => ENV['key_files'] || '/root/.ssh/id_rsa',
12
+ 'logger' => Logger.new(STDOUT),
13
+ }
14
+
15
+ backend_conf['target'] = 'ssh://' + backend_conf['target']
16
+ backend_conf['logger'].level = \
17
+ if ENV.key?('debug')
18
+ case ENV['debug'].to_s
19
+ when /^false$/i, /^0$/i
20
+ Logger::INFO
21
+ else
22
+ Logger::DEBUG
23
+ end
24
+ else
25
+ Logger::INFO
26
+ end
27
+
28
+ backends[:ssh] = proc { |*args|
29
+ conf = Train.target_config(backend_conf)
30
+ Train.create('ssh', conf).connection(args[0])
31
+ }
32
+
33
+ tests = ARGV
34
+
35
+ backends.each do |type, get_backend|
36
+ tests.each do |test|
37
+ instance_eval(File.read(test), test, 1)
38
+ end
39
+ end
@@ -0,0 +1,74 @@
1
+ # encoding: utf-8
2
+
3
+ describe 'file interface' do
4
+ let(:backend) { get_backend.call }
5
+
6
+ describe 'block device' do
7
+ let(:file) { backend.file('/tmp/block_device') }
8
+
9
+ it 'exists' do
10
+ file.exist?.must_equal(true)
11
+ end
12
+
13
+ it 'is a block device' do
14
+ file.block_device?.must_equal(true)
15
+ end
16
+
17
+ it 'has type :block_device' do
18
+ file.type.must_equal(:block_device)
19
+ end
20
+
21
+ it 'has no content' do
22
+ file.content.must_equal('')
23
+ end
24
+
25
+ it 'has owner name root' do
26
+ file.owner.must_equal('root')
27
+ end
28
+
29
+ it 'has group name' do
30
+ file.group.must_equal(Test.root_group(backend.os))
31
+ end
32
+
33
+ it 'has mode 0666' do
34
+ file.mode.must_equal(00666)
35
+ end
36
+
37
+ it 'checks mode? 0666' do
38
+ file.mode?(00666).must_equal(true)
39
+ end
40
+
41
+ it 'has no link_path' do
42
+ file.link_path.must_be_nil
43
+ end
44
+
45
+ it 'has no md5sum' do
46
+ file.md5sum.must_equal('d41d8cd98f00b204e9800998ecf8427e')
47
+ end
48
+
49
+ it 'has no sha256sum' do
50
+ file.sha256sum.must_equal('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
51
+ end
52
+
53
+ it 'has a modified time' do
54
+ file.mtime.must_be_close_to(Time.now.to_i - Test.mtime/2, Test.mtime)
55
+ end
56
+
57
+ it 'has inode size of 0' do
58
+ file.size.must_equal(0)
59
+ end
60
+
61
+ it 'has selinux label handling' do
62
+ res = Test.selinux_label(backend, file.path)
63
+ file.selinux_label.must_equal(res)
64
+ end
65
+
66
+ it 'has no product_version' do
67
+ file.product_version.must_equal(nil)
68
+ end
69
+
70
+ it 'has no file_version' do
71
+ file.file_version.must_equal(nil)
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,74 @@
1
+ # encoding: utf-8
2
+
3
+ describe 'file interface' do
4
+ let(:backend) { get_backend.call }
5
+
6
+ describe 'character device' do
7
+ let(:file) { backend.file('/dev/null') }
8
+
9
+ it 'exists' do
10
+ file.exist?.must_equal(true)
11
+ end
12
+
13
+ it 'is a character device' do
14
+ file.character_device?.must_equal(true)
15
+ end
16
+
17
+ it 'has type :character_device' do
18
+ file.type.must_equal(:character_device)
19
+ end
20
+
21
+ it 'has empty content' do
22
+ file.content.must_equal('')
23
+ end
24
+
25
+ it 'has owner name root' do
26
+ file.owner.must_equal('root')
27
+ end
28
+
29
+ it 'has group name' do
30
+ file.group.must_equal(Test.root_group(backend.os))
31
+ end
32
+
33
+ it 'has mode 0666' do
34
+ file.mode.must_equal(00666)
35
+ end
36
+
37
+ it 'checks mode? 0666' do
38
+ file.mode?(00666).must_equal(true)
39
+ end
40
+
41
+ it 'has no link_path' do
42
+ file.link_path.must_be_nil
43
+ end
44
+
45
+ it 'has an md5sum' do
46
+ file.md5sum.must_equal('d41d8cd98f00b204e9800998ecf8427e')
47
+ end
48
+
49
+ it 'has an sha256sum' do
50
+ file.sha256sum.must_equal('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855')
51
+ end
52
+
53
+ it 'has a modified time' do
54
+ file.mtime.must_be_close_to(Time.now.to_i - Test.mtime/2, Test.mtime)
55
+ end
56
+
57
+ it 'has inode size of 0' do
58
+ file.size.must_equal(0)
59
+ end
60
+
61
+ it 'has selinux label handling' do
62
+ res = Test.selinux_label(backend, file.path)
63
+ file.selinux_label.must_equal(res)
64
+ end
65
+
66
+ it 'has no product_version' do
67
+ file.product_version.must_equal(nil)
68
+ end
69
+
70
+ it 'has no file_version' do
71
+ file.file_version.must_equal(nil)
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,79 @@
1
+ # encoding: utf-8
2
+
3
+ describe 'file interface' do
4
+ let(:backend) { get_backend.call }
5
+
6
+ describe 'regular file' do
7
+ let(:file) { backend.file('/tmp/file') }
8
+
9
+ it 'exists' do
10
+ file.exist?.must_equal(true)
11
+ end
12
+
13
+ it 'is a file' do
14
+ file.file?.must_equal(true)
15
+ end
16
+
17
+ it 'has type :file' do
18
+ file.type.must_equal(:file)
19
+ end
20
+
21
+ it 'has content' do
22
+ file.content.must_equal('hello world')
23
+ end
24
+
25
+ it 'has owner name root' do
26
+ file.owner.must_equal('root')
27
+ end
28
+
29
+ it 'has group name' do
30
+ file.group.must_equal(Test.root_group(backend.os))
31
+ end
32
+
33
+ it 'has mode 0765' do
34
+ file.mode.must_equal(00765)
35
+ end
36
+
37
+ it 'checks mode? 0765' do
38
+ file.mode?(00765).must_equal(true)
39
+ end
40
+
41
+ it 'doesnt check mode? 0764' do
42
+ file.mode?(00764).must_equal(false)
43
+ end
44
+
45
+ it 'has no link_path' do
46
+ file.link_path.must_be_nil
47
+ end
48
+
49
+ it 'has an md5sum' do
50
+ file.md5sum.must_equal('5eb63bbbe01eeed093cb22bb8f5acdc3')
51
+ end
52
+
53
+ it 'has an sha256sum' do
54
+ file.sha256sum.must_equal('b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9')
55
+ end
56
+
57
+ it 'has a modified time' do
58
+ file.mtime.must_be_close_to(Time.now.to_i - Test.mtime/2, Test.mtime)
59
+ end
60
+
61
+ it 'has size' do
62
+ # Must be around 11 Bytes, +- 4
63
+ file.size.must_be_close_to(11, 4)
64
+ end
65
+
66
+ it 'has selinux label handling' do
67
+ res = Test.selinux_label(backend, file.path)
68
+ file.selinux_label.must_equal(res)
69
+ end
70
+
71
+ it 'has no product_version' do
72
+ file.product_version.must_equal(nil)
73
+ end
74
+
75
+ it 'has no file_version' do
76
+ file.file_version.must_equal(nil)
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,90 @@
1
+ # encoding: utf-8
2
+
3
+ describe 'file interface' do
4
+ let(:backend) { get_backend.call }
5
+
6
+ describe 'a folder' do
7
+ let(:file) { backend.file('/tmp/folder') }
8
+
9
+ it 'exists' do
10
+ file.exist?.must_equal(true)
11
+ end
12
+
13
+ it 'is a directory' do
14
+ file.directory?.must_equal(true)
15
+ end
16
+
17
+ it 'has type :directory' do
18
+ file.type.must_equal(:directory)
19
+ end
20
+
21
+ case get_backend.call.os[:family]
22
+ when 'freebsd'
23
+ it 'has freebsd folder content behavior' do
24
+ file.content.must_equal("\u0003\u0000")
25
+ end
26
+
27
+ it 'has an md5sum' do
28
+ file.md5sum.must_equal('598f4fe64aefab8f00bcbea4c9239abf')
29
+ end
30
+
31
+ it 'has an sha256sum' do
32
+ file.sha256sum.must_equal('9b4fb24edd6d1d8830e272398263cdbf026b97392cc35387b991dc0248a628f9')
33
+ end
34
+
35
+ else
36
+ it 'has no content' do
37
+ file.content.must_equal(nil)
38
+ end
39
+
40
+ it 'has an md5sum' do
41
+ file.md5sum.must_equal(nil)
42
+ end
43
+
44
+ it 'has an sha256sum' do
45
+ file.sha256sum.must_equal(nil)
46
+ end
47
+ end
48
+
49
+ it 'has owner name root' do
50
+ file.owner.must_equal('root')
51
+ end
52
+
53
+ it 'has group name' do
54
+ file.group.must_equal(Test.root_group(backend.os))
55
+ end
56
+
57
+ it 'has mode 0567' do
58
+ file.mode.must_equal(00567)
59
+ end
60
+
61
+ it 'checks mode? 0567' do
62
+ file.mode?(00567).must_equal(true)
63
+ end
64
+
65
+ it 'has no link_path' do
66
+ file.link_path.must_be_nil
67
+ end
68
+
69
+ it 'has a modified time' do
70
+ file.mtime.must_be_close_to(Time.now.to_i - Test.mtime/2, Test.mtime)
71
+ end
72
+
73
+ it 'has inode size' do
74
+ file.size.must_be_close_to(4096, 4096)
75
+ end
76
+
77
+ it 'has selinux label handling' do
78
+ res = Test.selinux_label(backend, file.path)
79
+ file.selinux_label.must_equal(res)
80
+ end
81
+
82
+ it 'has no product_version' do
83
+ file.product_version.must_equal(nil)
84
+ end
85
+
86
+ it 'has no file_version' do
87
+ file.file_version.must_equal(nil)
88
+ end
89
+ end
90
+ end