kanrisuru 0.1.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +17 -0
  3. data/.rubocop.yml +47 -0
  4. data/.rubocop_todo.yml +0 -0
  5. data/CHANGELOG.md +0 -0
  6. data/Gemfile +2 -5
  7. data/LICENSE.txt +1 -1
  8. data/README.md +143 -7
  9. data/Rakefile +5 -3
  10. data/bin/console +4 -3
  11. data/kanrisuru.gemspec +21 -12
  12. data/lib/kanrisuru.rb +41 -2
  13. data/lib/kanrisuru/command.rb +99 -0
  14. data/lib/kanrisuru/core.rb +53 -0
  15. data/lib/kanrisuru/core/archive.rb +154 -0
  16. data/lib/kanrisuru/core/disk.rb +302 -0
  17. data/lib/kanrisuru/core/file.rb +332 -0
  18. data/lib/kanrisuru/core/find.rb +108 -0
  19. data/lib/kanrisuru/core/group.rb +97 -0
  20. data/lib/kanrisuru/core/ip.rb +1032 -0
  21. data/lib/kanrisuru/core/mount.rb +138 -0
  22. data/lib/kanrisuru/core/path.rb +140 -0
  23. data/lib/kanrisuru/core/socket.rb +168 -0
  24. data/lib/kanrisuru/core/stat.rb +104 -0
  25. data/lib/kanrisuru/core/stream.rb +121 -0
  26. data/lib/kanrisuru/core/system.rb +348 -0
  27. data/lib/kanrisuru/core/transfer.rb +203 -0
  28. data/lib/kanrisuru/core/user.rb +198 -0
  29. data/lib/kanrisuru/logger.rb +8 -0
  30. data/lib/kanrisuru/mode.rb +277 -0
  31. data/lib/kanrisuru/os_package.rb +235 -0
  32. data/lib/kanrisuru/remote.rb +10 -0
  33. data/lib/kanrisuru/remote/cluster.rb +95 -0
  34. data/lib/kanrisuru/remote/cpu.rb +68 -0
  35. data/lib/kanrisuru/remote/env.rb +33 -0
  36. data/lib/kanrisuru/remote/file.rb +354 -0
  37. data/lib/kanrisuru/remote/fstab.rb +412 -0
  38. data/lib/kanrisuru/remote/host.rb +191 -0
  39. data/lib/kanrisuru/remote/memory.rb +19 -0
  40. data/lib/kanrisuru/remote/os.rb +87 -0
  41. data/lib/kanrisuru/result.rb +78 -0
  42. data/lib/kanrisuru/template.rb +32 -0
  43. data/lib/kanrisuru/util.rb +40 -0
  44. data/lib/kanrisuru/util/bits.rb +203 -0
  45. data/lib/kanrisuru/util/fs_mount_opts.rb +655 -0
  46. data/lib/kanrisuru/util/os_family.rb +213 -0
  47. data/lib/kanrisuru/util/signal.rb +161 -0
  48. data/lib/kanrisuru/version.rb +3 -1
  49. data/spec/functional/core/archive_spec.rb +228 -0
  50. data/spec/functional/core/disk_spec.rb +80 -0
  51. data/spec/functional/core/file_spec.rb +341 -0
  52. data/spec/functional/core/find_spec.rb +52 -0
  53. data/spec/functional/core/group_spec.rb +65 -0
  54. data/spec/functional/core/ip_spec.rb +71 -0
  55. data/spec/functional/core/path_spec.rb +93 -0
  56. data/spec/functional/core/socket_spec.rb +31 -0
  57. data/spec/functional/core/stat_spec.rb +98 -0
  58. data/spec/functional/core/stream_spec.rb +99 -0
  59. data/spec/functional/core/system_spec.rb +96 -0
  60. data/spec/functional/core/transfer_spec.rb +108 -0
  61. data/spec/functional/core/user_spec.rb +76 -0
  62. data/spec/functional/os_package_spec.rb +75 -0
  63. data/spec/functional/remote/cluster_spec.rb +45 -0
  64. data/spec/functional/remote/cpu_spec.rb +41 -0
  65. data/spec/functional/remote/env_spec.rb +36 -0
  66. data/spec/functional/remote/fstab_spec.rb +76 -0
  67. data/spec/functional/remote/host_spec.rb +68 -0
  68. data/spec/functional/remote/memory_spec.rb +29 -0
  69. data/spec/functional/remote/os_spec.rb +63 -0
  70. data/spec/functional/remote/remote_file_spec.rb +180 -0
  71. data/spec/helper/test_hosts.rb +68 -0
  72. data/spec/hosts.json +92 -0
  73. data/spec/spec_helper.rb +11 -3
  74. data/spec/unit/fstab_spec.rb +22 -0
  75. data/spec/unit/kanrisuru_spec.rb +9 -0
  76. data/spec/unit/mode_spec.rb +183 -0
  77. data/spec/unit/template_spec.rb +13 -0
  78. data/spec/unit/util_spec.rb +177 -0
  79. data/spec/zz_reboot_spec.rb +46 -0
  80. metadata +136 -13
  81. data/spec/kanrisuru_spec.rb +0 -9
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Kanrisuru::Remote::Env do
6
+ TestHosts.each_os do |os_name|
7
+ context "with #{os_name}" do
8
+ let(:host_json) { TestHosts.host(os_name) }
9
+ let(:host) do
10
+ Kanrisuru::Remote::Host.new(
11
+ host: host_json['hostname'],
12
+ username: host_json['username'],
13
+ keys: [host_json['ssh_key']]
14
+ )
15
+ end
16
+
17
+ after do
18
+ host.disconnect
19
+ end
20
+
21
+ it 'sets env var' do
22
+ host.env['HELLO'] = 'world'
23
+ host.env['KANRISURU'] = 'manage'
24
+
25
+ expect(host.env['KANRISURU']).to eq('manage')
26
+ expect(host.env.to_s).to eq('export HELLO=world; export KANRISURU=manage;')
27
+ expect(host.env.to_h).to eq({ 'HELLO' => 'world', 'KANRISURU' => 'manage' })
28
+
29
+ command = Kanrisuru::Command.new('echo $KANRISURU $HELLO')
30
+ host.execute_shell(command)
31
+
32
+ expect(command.to_s).to eq('manage world')
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Kanrisuru::Remote::Fstab do
4
+ TestHosts.each_os do |os_name|
5
+ context "with #{os_name}" do
6
+ let(:host_json) { TestHosts.host(os_name) }
7
+ let(:host) do
8
+ Kanrisuru::Remote::Host.new(
9
+ host: host_json['hostname'],
10
+ username: host_json['username'],
11
+ keys: [host_json['ssh_key']]
12
+ )
13
+ end
14
+
15
+ after do
16
+ host.disconnect
17
+ end
18
+
19
+ it 'parses fstab' do
20
+ host.su('root')
21
+ fstab = host.fstab
22
+
23
+ entry =
24
+ case os_name
25
+ when 'opensuse'
26
+ fstab['/dev/vda3']
27
+ when 'sles'
28
+ fstab['/dev/xvda1']
29
+ else
30
+ fstab['/dev/vda1']
31
+ end
32
+
33
+ expect(fstab.get_entry(entry.uuid)).to eq(entry)
34
+ expect(fstab.get_entry(entry.label)).to eq(entry)
35
+
36
+ fstab << Kanrisuru::Remote::Fstab::Entry.new(
37
+ device: '/dev/vda14',
38
+ mount_point: '/mnt/test',
39
+ type: 'ext4',
40
+ opts: { defaults: true },
41
+ freq: '0',
42
+ passno: '0'
43
+ )
44
+
45
+ entry = fstab['/dev/vda14']
46
+ expect(entry.to_s).to eq('/dev/vda14 /mnt/test ext4 defaults 0 0')
47
+ expect(entry.device).to eq('/dev/vda14')
48
+ expect(entry.mount_point).to eq('/mnt/test')
49
+ expect(entry.type).to eq('ext4')
50
+ expect(entry.opts.to_s).to eq('defaults')
51
+ expect(entry.freq).to eq('0')
52
+ expect(entry.passno).to eq('0')
53
+
54
+ entry.opts['defaults'] = false
55
+ entry.opts['user'] = true
56
+ entry.opts['exec'] = true
57
+ entry.opts['rw'] = true
58
+ entry.opts['auto'] = true
59
+ entry.opts['relatime'] = true
60
+ entry.opts['async'] = true
61
+ entry.opts[:nodev] = true
62
+ entry.opts[:nosuid] = true
63
+ entry.opts[:owner] = true
64
+ entry.opts[:group] = true
65
+
66
+ entry.mount_point = '/mnt/test3'
67
+
68
+ expect(fstab['/dev/vda14'].to_s).to eq '/dev/vda14 /mnt/test3 ext4 ' \
69
+ 'user,exec,rw,auto,relatime,async,nodev,nosuid,owner,group 0 0'
70
+
71
+ fstab << '/dev/vda16 /mnt/test2 fat defaults,user,uid=1000,gid=1000 0 0'
72
+ expect(fstab['/dev/vda16'].to_s).to eq('/dev/vda16 /mnt/test2 fat defaults,user,uid=1000,gid=1000 0 0')
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Kanrisuru::Remote::Host do
6
+ TestHosts.each_os do |os_name|
7
+ context "with #{os_name}" do
8
+ let(:host_json) { TestHosts.host(os_name) }
9
+ let(:host) do
10
+ described_class.new(
11
+ host: host_json['hostname'],
12
+ username: host_json['username'],
13
+ keys: [host_json['ssh_key']]
14
+ )
15
+ end
16
+
17
+ after do
18
+ host.disconnect
19
+ end
20
+
21
+ it 'can ping localhost' do
22
+ expect(host.ping?).to eq(true)
23
+ end
24
+
25
+ it 'gets hostname' do
26
+ expect(host.hostname).to eq(host_json['hostname'])
27
+ end
28
+
29
+ it 'changes directories' do
30
+ expect(host.pwd.path).to eq(host_json['home'])
31
+
32
+ host.cd('../')
33
+ expect(host.pwd.path).to eq('/home')
34
+
35
+ host.cd('../')
36
+ expect(host.pwd.path).to eq('/')
37
+
38
+ host.cd('~')
39
+
40
+ expect(host.pwd.path).to eq(host_json['home'])
41
+
42
+ host.su('root')
43
+ host.cd('/root/../etc')
44
+
45
+ result = host.ls
46
+ paths = result.map(&:path)
47
+
48
+ expect(paths).to include('hosts')
49
+ expect(paths).to include('shadow')
50
+ expect(paths).to include('ssh')
51
+
52
+ host.cd('default')
53
+ expect(host.pwd.path).to eq('/etc/default')
54
+
55
+ host.su(host_json['username'])
56
+
57
+ host.cd('.')
58
+ expect(host.pwd.path).to eq('/etc/default')
59
+
60
+ result = host.ls(path: '/home')
61
+ expect(result[0].path).to eq(host_json['username'])
62
+
63
+ host.cd('/bin')
64
+ expect(host.pwd.path).to eq('/bin')
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Kanrisuru::Remote::Memory do
6
+ TestHosts.each_os do |os_name|
7
+ context "with #{os_name}" do
8
+ let(:host_json) { TestHosts.host(os_name) }
9
+ let(:host) do
10
+ Kanrisuru::Remote::Host.new(
11
+ host: host_json['hostname'],
12
+ username: host_json['username'],
13
+ keys: [host_json['ssh_key']]
14
+ )
15
+ end
16
+
17
+ after do
18
+ host.disconnect
19
+ end
20
+
21
+ it 'gets memory details' do
22
+ expect(host.memory.total(:gb)).to be >= 0.5
23
+ expect(host.memory.free(:mb)).to be >= 10.0
24
+ expect(host.memory.swap).to be_instance_of(Integer)
25
+ expect(host.memory.swap_free).to be_instance_of(Integer)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Kanrisuru::Remote::Os do
6
+ TestHosts.each_os do |os_name|
7
+ context "with #{os_name}" do
8
+ let(:host_json) { TestHosts.host(os_name) }
9
+ let(:host) do
10
+ Kanrisuru::Remote::Host.new(
11
+ host: host_json['hostname'],
12
+ username: host_json['username'],
13
+ keys: [host_json['ssh_key']]
14
+ )
15
+ end
16
+
17
+ after do
18
+ host.disconnect
19
+ end
20
+
21
+ it 'detects os specs' do
22
+ expect(host.os.kernel).to eq(host_json['kernel'])
23
+ expect(host.os.processor).to eq('x86_64')
24
+
25
+ case os_name
26
+ when 'opensuse'
27
+ expect(host.os.release).to eq('opensuse-leap')
28
+ else
29
+ expect(host.os.release).to eq(os_name)
30
+ end
31
+
32
+ expect(host.os.version).to be > 0.00
33
+
34
+ case os_name
35
+ when 'debian'
36
+ expect(host.os.version).to eq(10)
37
+ when 'ubuntu'
38
+ expect(host.os.version).to eq(18.04)
39
+ when 'fedora'
40
+ expect(host.os.version).to eq(32)
41
+ when 'centos'
42
+ expect(host.os.version).to eq(7)
43
+ when 'opensuse'
44
+ expect(host.os.version).to eq(15.2)
45
+ when 'rhel'
46
+ expect(host.os.version).to eq(7.9)
47
+ end
48
+ end
49
+
50
+ it 'gets uname' do
51
+ expect(host.os.uname).to eq(host_json['kernel'])
52
+ end
53
+
54
+ it 'gets uname details' do
55
+ host.os.uname(
56
+ kernel_name: true,
57
+ hardware_platform: true,
58
+ operating_system: true
59
+ )
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,180 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Kanrisuru::Remote::File do
4
+ module Kanrisuru
5
+ module Remote
6
+ Class.new(File) do
7
+ READ_FILE_SIZE = 25_000
8
+ end
9
+ end
10
+ end
11
+
12
+ TestHosts.each_os do |os_name|
13
+ context "with #{os_name}" do
14
+ before(:all) do
15
+ host_json = TestHosts.host(os_name)
16
+ host = Kanrisuru::Remote::Host.new(
17
+ host: host_json['hostname'],
18
+ username: host_json['username'],
19
+ keys: [host_json['ssh_key']]
20
+ )
21
+
22
+ host.mkdir("#{host_json['home']}/.kanrisuru_spec_files", silent: true)
23
+ host.disconnect
24
+ end
25
+
26
+ let(:host_json) { TestHosts.host(os_name) }
27
+ let(:host) do
28
+ Kanrisuru::Remote::Host.new(
29
+ host: host_json['hostname'],
30
+ username: host_json['username'],
31
+ keys: [host_json['ssh_key']]
32
+ )
33
+ end
34
+
35
+ let(:spec_dir) { "#{host_json['home']}/.kanrisuru_spec_files" }
36
+
37
+ after do
38
+ host.disconnect
39
+ end
40
+
41
+ after(:all) do
42
+ host_json = TestHosts.host(os_name)
43
+ host = Kanrisuru::Remote::Host.new(
44
+ host: host_json['hostname'],
45
+ username: host_json['username'],
46
+ keys: [host_json['ssh_key']]
47
+ )
48
+
49
+ host.rmdir("#{host_json['home']}/.kanrisuru_spec_files")
50
+ host.rmdir("#{host_json['home']}/extract-tar-files") if host.dir?("#{host_json['home']}/extract-tar-files")
51
+ host.disconnect
52
+ end
53
+
54
+ it 'loads a remote file to edit' do
55
+ file = host.file("#{spec_dir}/remote-file.txt")
56
+
57
+ expect(file).to be_instance_of(described_class)
58
+ expect(file.exists?).to eq(false)
59
+ expect(file.expand_path).to eq('')
60
+
61
+ file.touch
62
+
63
+ expect(file.exists?).to eq(true)
64
+ expect(file.zero?).to eq(true)
65
+ expect(file.user).to eq(host_json['username'])
66
+
67
+ case os_name
68
+ when 'opensuse', 'sles'
69
+ expect(file.group).to eq('users')
70
+ else
71
+ expect(file.group).to eq(host_json['username'])
72
+ end
73
+
74
+ expect(file.expand_path).to eq("#{spec_dir}/remote-file.txt")
75
+
76
+ file.append do |f|
77
+ f << 'Hello world'
78
+ f << 'this is a test!'
79
+ end
80
+
81
+ lines = file.map { |line| line }
82
+ expect(lines).to eq(['Hello world', 'this is a test!'])
83
+ expect(file.zero?).to eq(false)
84
+
85
+ file.prepend do |f|
86
+ f << 'Lines exist'
87
+ f << 'at the beginning...'
88
+ end
89
+
90
+ expect(file[0]).to eq('Lines exist')
91
+ expect(file[3]).to eq('this is a test!')
92
+
93
+ lines = file.map { |line| line }
94
+ expect(lines).to eq(['Lines exist', 'at the beginning...', 'Hello world', 'this is a test!'])
95
+
96
+ expect(file.delete).to eq(true)
97
+ expect(file.exists?).to eq(false)
98
+ end
99
+
100
+ it 'finds and updates file' do
101
+ file = host.file("#{spec_dir}/hosts.conf.test")
102
+
103
+ file.touch
104
+
105
+ file.write do |f|
106
+ f << '127.0.0.1 localhost'
107
+ f << '127.0.1.1 ubuntu'
108
+ f << ''
109
+ f << '# The following lines are desirable for IPv6 capable hosts'
110
+ f << '::1 ip6-localhost ip6-loopback'
111
+ f << 'fe00::0 ip6-localnet'
112
+ f << 'ff00::0 ip6-mcastprefix'
113
+ f << 'ff02::1 ip6-allnodes'
114
+ f << 'ff02::2 ip6-allrouters'
115
+ f << 'ff02::3 ip6-allhosts'
116
+ end
117
+
118
+ expect(file[2]).to eq('')
119
+ file.find_and_append(/^127.0.1.1 ubuntu/, '8.8.8.8 rickroll.com')
120
+ expect(file[2]).to eq('8.8.8.8 rickroll.com')
121
+
122
+ expect(file[1]).to eq('127.0.1.1 ubuntu')
123
+ file.find_and_prepend(/^127.0.1.1 ubuntu/, '1.1.1.1 nevergoingtoletyoudown.io')
124
+ expect(file[1]).to eq('1.1.1.1 nevergoingtoletyoudown.io')
125
+
126
+ file.prepend do |f|
127
+ f << '# Generated by Kanrisuru'
128
+ end
129
+
130
+ file.find_and_replace_line(/#/, '# Rick Astley was here')
131
+ expect(file[0]).to eq('# Rick Astley was here')
132
+ expect(file[6]).to eq('# Rick Astley was here')
133
+
134
+ file.find_and_replace_value(/\slocalhost/, ' nevergoingtogiveyouup.biz')
135
+ expect(file[1]).to eq('127.0.0.1 nevergoingtogiveyouup.biz')
136
+
137
+ file.find_and_remove(/^::/)
138
+ file.find_and_remove(/^ff/)
139
+ file.find_and_remove(/^fe/)
140
+
141
+ expect(file.lines).to eq(7)
142
+ end
143
+
144
+ it 'iterates with chunking' do
145
+ file = host.file("#{spec_dir}/remote-file-large.txt")
146
+
147
+ expect(file.exists?).to eq(false)
148
+
149
+ file.touch
150
+
151
+ file.write do |f|
152
+ (0...50_000).each do |i|
153
+ f << "Line: #{i}"
154
+ end
155
+ end
156
+
157
+ line = file.find do |f|
158
+ f == 'Line: 1111'
159
+ end
160
+
161
+ expect(line).to eq('Line: 1111')
162
+
163
+ expect(file[0]).to eq('Line: 0')
164
+ expect(file[5]).to eq('Line: 5')
165
+ expect(file[28_445]).to eq('Line: 28445')
166
+ expect(file[49_999]).to eq('Line: 49999')
167
+ expect { file[50_000] }.to raise_error(ArgumentError)
168
+
169
+ file.prepend do |f|
170
+ f << 'Hello large file'
171
+ end
172
+
173
+ expect(file[0]).to eq('Hello large file')
174
+ expect(file[1]).to eq('Line: 0')
175
+ expect(file[28_446]).to eq('Line: 28445')
176
+ expect(file[50_000]).to eq('Line: 49999')
177
+ end
178
+ end
179
+ end
180
+ end