kanrisuru 0.1.0 → 0.2.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 (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