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,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kanrisuru
4
+ module Core
5
+ module Mount
6
+ extend OsPackage::Define
7
+
8
+ os_define :linux, :mount
9
+ os_define :linux, :umount
10
+
11
+ def mount(opts = {})
12
+ type = opts[:type]
13
+ all = opts[:all]
14
+ device = opts[:device]
15
+ directory = opts[:directory]
16
+
17
+ bind_old = opts[:bind_old]
18
+ bind_new = opts[:bind_new]
19
+ rbind_old = opts[:rbind_old]
20
+ rbind_new = opts[:rbind_new]
21
+ move_old = opts[:move_old]
22
+ move_new = opts[:move_new]
23
+ fs_opts = opts[:fs_opts]
24
+
25
+ command = Kanrisuru::Command.new('mount')
26
+
27
+ if Kanrisuru::Util.present?(bind_old) && Kanrisuru::Util.present?(bind_new)
28
+ command.append_flag('--bind')
29
+ command << bind_old
30
+ command << bind_new
31
+ elsif Kanrisuru::Util.present?(rbind_old) && Kanrisuru::Util.present?(rbind_new)
32
+ command.append_flag('--rbind')
33
+ command << rbind_old
34
+ command << rbind_new
35
+ elsif Kanrisuru::Util.present?(move_old) && Kanrisuru::Util.present?(move_new)
36
+ command.append_flag('--move')
37
+ command << move_old
38
+ command << move_new
39
+ else
40
+ command.append_arg('-L', opts[:label])
41
+ command.append_arg('-U', opts[:uuid])
42
+ command.append_flag('-n', opts[:no_mtab])
43
+ command.append_flag('-f', opts[:fake])
44
+ command.append_flag('-i', opts[:internal_only])
45
+ command.append_flag('-s', opts[:sloppy])
46
+
47
+ command.append_flag('--no-mtab', opts[:no_mtab])
48
+ command.append_flag('--no-canonicalizeb', opts[:no_canonicalize])
49
+
50
+ fs_options = nil
51
+ if Kanrisuru::Util.present?(type)
52
+ add_type(command, type)
53
+ fs_options = Kanrisuru::Remote::Fstab::Options.new(type, fs_opts) if fs_opts
54
+ elsif fs_opts
55
+ fs_options = Kanrisuru::Remote::Fstab::Options.new('common', fs_opts)
56
+ end
57
+
58
+ if Kanrisuru::Util.present?(all)
59
+ command.append_flag('-a')
60
+ add_test_opts(command, opts[:test_opts], type)
61
+ else
62
+ command.append_arg('-o', fs_options.to_s)
63
+
64
+ command << device if Kanrisuru::Util.present?(device)
65
+ command << directory if Kanrisuru::Util.present?(directory)
66
+ end
67
+ end
68
+
69
+ execute_shell(command)
70
+ Kanrisuru::Result.new(command)
71
+ end
72
+
73
+ def umount(opts = {})
74
+ all = opts[:all]
75
+ type = opts[:type]
76
+ command = Kanrisuru::Command.new('umount')
77
+
78
+ if Kanrisuru::Util.present?(all)
79
+ command.append_flag('-a')
80
+ add_type(command, type)
81
+ add_test_opts(command, opts[:test_opts], type)
82
+ end
83
+
84
+ command.append_flag('--fake', opts[:fake])
85
+ command.append_flag('--no-canonicalize', opts[:no_canonicalize])
86
+ command.append_flag('-n', opts[:no_mtab])
87
+ command.append_flag('-r', opts[:fail_remount_readonly])
88
+ command.append_flag('-d', opts[:free_loopback])
89
+
90
+ command.append_flag('-l', opts[:lazy])
91
+ command.append_flag('-f', opts[:force])
92
+
93
+ execute_shell(command)
94
+
95
+ Kanrisuru::Result.new(command)
96
+ end
97
+
98
+ private
99
+
100
+ def add_type(command, type)
101
+ return unless Kanrisuru::Util.present?(type)
102
+
103
+ test_types = nil
104
+
105
+ if type.include?(',')
106
+ if type.include?('no')
107
+ test_types = type.gsub('no', '')
108
+ test_types = test_types.split(',')
109
+ else
110
+ test_types = type.split(',')
111
+ end
112
+ else
113
+ test_types = [type]
114
+ end
115
+
116
+ test_types.each do |t|
117
+ device_opts = Kanrisuru::Util::FsMountOpts.get_device(t)
118
+ raise ArugmentError, "Invalid fstype: #{t}" unless device_opts
119
+ end
120
+
121
+ command.append_arg('-t', type)
122
+ end
123
+
124
+ def add_test_opts(command, test_opts, type)
125
+ return unless Kanrisuru::Util.present?(test_opts)
126
+
127
+ test_options =
128
+ if Kanrisuru::Util.present?(type)
129
+ Kanrisuru::Remote::Fstab::Options.new(type, test_opts)
130
+ else
131
+ Kanrisuru::Remote::Fstab::Options.new('common', test_opts)
132
+ end
133
+
134
+ command.append_arg('-O', test_options.to_s)
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module Kanrisuru
6
+ module Core
7
+ module Path
8
+ extend OsPackage::Define
9
+
10
+ os_define :linux, :ls
11
+ os_define :linux, :pwd
12
+ os_define :linux, :whoami
13
+ os_define :linux, :which
14
+ os_define :linux, :realpath
15
+ os_define :linux, :readlink
16
+
17
+ FilePath = Struct.new(:path)
18
+ FileInfoId = Struct.new(:inode, :mode, :memory_blocks, :uid, :gid, :fsize, :date, :path, :type)
19
+ FileInfo = Struct.new(:inode, :mode, :memory_blocks, :owner, :group, :fsize, :date, :path, :type)
20
+ UserName = Struct.new(:user)
21
+
22
+ def ls(opts = {})
23
+ path = opts[:path]
24
+ all = opts[:all]
25
+ id = opts[:id]
26
+
27
+ command = Kanrisuru::Command.new('ls')
28
+ command.append_flag('-i')
29
+ command.append_flag('-l')
30
+ command.append_flag('-a', all)
31
+ command.append_flag('-n', id)
32
+
33
+ command << (path || pwd.path)
34
+ execute_shell(command)
35
+
36
+ Kanrisuru::Result.new(command) do |cmd|
37
+ items = []
38
+ rows = cmd.to_a
39
+
40
+ rows.each.with_index do |row, index|
41
+ next if index.zero?
42
+
43
+ values = row.split
44
+ date = DateTime.parse("#{values[6]} #{values[7]} #{values[8]}")
45
+
46
+ type = values[1].include?('d') ? 'directory' : 'file'
47
+
48
+ items <<
49
+ if id
50
+ FileInfoId.new(
51
+ values[0].to_i,
52
+ Kanrisuru::Mode.new(values[1]),
53
+ values[2].to_i,
54
+ values[3].to_i,
55
+ values[4].to_i,
56
+ values[5].to_i,
57
+ date,
58
+ values[9],
59
+ type
60
+ )
61
+ else
62
+ FileInfo.new(
63
+ values[0].to_i,
64
+ Kanrisuru::Mode.new(values[1]),
65
+ values[2].to_i,
66
+ values[3],
67
+ values[4],
68
+ values[5].to_i,
69
+ date,
70
+ values[9],
71
+ type
72
+ )
73
+ end
74
+ end
75
+
76
+ items
77
+ end
78
+ end
79
+
80
+ def whoami
81
+ command = Kanrisuru::Command.new('whoami')
82
+ execute_shell(command)
83
+
84
+ Kanrisuru::Result.new(command) do |cmd|
85
+ UserName.new(cmd.to_s)
86
+ end
87
+ end
88
+
89
+ def pwd
90
+ command = Kanrisuru::Command.new('pwd')
91
+ execute_shell(command)
92
+
93
+ Kanrisuru::Result.new(command) do |cmd|
94
+ FilePath.new(cmd.to_s)
95
+ end
96
+ end
97
+
98
+ def which(program, opts = {})
99
+ command = Kanrisuru::Command.new('which')
100
+ command.append_flag('-a', opts[:all])
101
+ command << program
102
+
103
+ execute_shell(command)
104
+
105
+ Kanrisuru::Result.new(command) do |cmd|
106
+ rows = cmd.to_a
107
+ rows.map do |row|
108
+ FilePath.new(row)
109
+ end
110
+ end
111
+ end
112
+
113
+ def realpath(path, opts = {})
114
+ command = Kanrisuru::Command.new("realpath #{path}")
115
+ command.append_flag('-s', opts[:strip])
116
+
117
+ execute(command)
118
+
119
+ Kanrisuru::Result.new(command) do |cmd|
120
+ FilePath.new(cmd.to_s)
121
+ end
122
+ end
123
+
124
+ def readlink(path, opts = {})
125
+ command = Kanrisuru::Command.new('readlink')
126
+ command.append_flag('-f', opts[:canonicalize])
127
+ command.append_flag('-e', opts[:canonicalize_existing])
128
+ command.append_flag('-m', opts[:canonicalize_missing])
129
+
130
+ command << path
131
+
132
+ execute(command)
133
+
134
+ Kanrisuru::Result.new(command) do |cmd|
135
+ FilePath.new(cmd.to_s)
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,168 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ipaddr'
4
+
5
+ module Kanrisuru
6
+ module Core
7
+ module Socket
8
+ extend OsPackage::Define
9
+
10
+ os_define :linux, :ss
11
+
12
+ SocketStatistics = Struct.new(
13
+ :netid, :state, :receive_queue, :send_queue,
14
+ :local_address, :local_port, :peer_address, :peer_port,
15
+ :memory
16
+ )
17
+
18
+ SocketStatisticsMemory = Struct.new(
19
+ :rmem_alloc, :rcv_buf, :wmem_alloc, :snd_buf,
20
+ :fwd_alloc, :wmem_queued, :ropt_mem, :back_log, :sock_drop
21
+ )
22
+
23
+ TCP_STATES = %w[
24
+ established syn-sent syn-recv
25
+ fin-wait-1 fin-wait-2 time-wait
26
+ closed close-wait last-ack listening closing
27
+ ].freeze
28
+
29
+ OTHER_STATES = %w[
30
+ all connected synchronized bucket syn-recv
31
+ big
32
+ ].freeze
33
+
34
+ TCP_STATE_ABBR = {
35
+ 'ESTAB' => 'established', 'LISTEN' => 'listening', 'UNCONN' => 'unconnected',
36
+ 'SYN-SENT' => 'syn-sent', 'SYN-RECV' => 'syn-recv', 'FIN-WAIT-1' => 'fin-wait-1',
37
+ 'FIN-WAIT-2' => 'fin-wait-2', 'TIME-WAIT' => 'time-wait', 'CLOSE-WAIT' => 'close-wait',
38
+ 'LAST-ACK' => 'last-ack', 'CLOSING' => 'closing'
39
+ }.freeze
40
+
41
+ def ss(opts = {})
42
+ state = opts[:state]
43
+ expression = opts[:expression]
44
+
45
+ command = Kanrisuru::Command.new('ss')
46
+
47
+ command.append_flag('-a')
48
+ command.append_flag('-m')
49
+
50
+ command.append_flag('-n', opts[:numeric])
51
+ command.append_flag('-t', opts[:tcp])
52
+ command.append_flag('-u', opts[:udp])
53
+ command.append_flag('-x', opts[:unix])
54
+ command.append_flag('-w', opts[:raw])
55
+
56
+ command.append_arg('-f', opts[:family])
57
+
58
+ if Kanrisuru::Util.present?(state)
59
+ raise ArgumentError, 'invalid filter state' if !TCP_STATES.include?(state) && !OTHER_STATES.include?(state)
60
+
61
+ command.append_arg('state', state)
62
+ end
63
+
64
+ command << expression if Kanrisuru::Util.present?(expression)
65
+
66
+ execute_shell(command)
67
+
68
+ Kanrisuru::Result.new(command) do |cmd|
69
+ rows = []
70
+
71
+ ## New lines with tabs are from text overflow
72
+ ## on on stdout of SS command.
73
+ ## Replace the newline and tab chars with a space.
74
+ string = cmd.raw_result.join
75
+ string = string.gsub("\n\t", "\s")
76
+ lines = string.lines.map(&:strip)
77
+
78
+ headers = lines.shift
79
+
80
+ lines.each do |line|
81
+ values = line.split
82
+ next if values.length < 5
83
+
84
+ socket_stats = SocketStatistics.new
85
+
86
+ socket_stats.netid = if headers.include?('Netid')
87
+ values.shift
88
+ elsif opts[:tcp]
89
+ 'tcp'
90
+ elsif opts[:udp]
91
+ 'udp'
92
+ elsif opts[:raw]
93
+ 'raw'
94
+ else
95
+ ''
96
+ end
97
+
98
+ socket_stats.state = if headers.include?('State')
99
+ TCP_STATE_ABBR[values.shift]
100
+ else
101
+ state
102
+ end
103
+
104
+ socket_stats.receive_queue = values.shift.to_i
105
+ socket_stats.send_queue = values.shift.to_i
106
+
107
+ address, port = parse_address_port(values)
108
+ socket_stats.local_address = address
109
+ socket_stats.local_port = port
110
+
111
+ address, port = parse_address_port(values)
112
+ socket_stats.peer_address = address
113
+ socket_stats.peer_port = port
114
+
115
+ socket_stats.memory = parse_memory(values.shift)
116
+
117
+ rows << socket_stats
118
+ end
119
+
120
+ rows
121
+ end
122
+ end
123
+
124
+ private
125
+
126
+ def parse_memory(string)
127
+ return if Kanrisuru::Util.blank?(string) ||
128
+ Regexp.new(/skmem:\((\S+)\)/).match(string).nil?
129
+
130
+ _, string = string.split(/skmem:\((\S+)\)/)
131
+ values = string.split(',')
132
+
133
+ memory = SocketStatisticsMemory.new
134
+ memory.rmem_alloc = values[0].split(/(\d+)/)[1].to_i
135
+ memory.rcv_buf = values[1].split(/(\d+)/)[1].to_i
136
+ memory.wmem_alloc = values[2].split(/(\d+)/)[1].to_i
137
+ memory.snd_buf = values[3].split(/(\d+)/)[1].to_i
138
+ memory.fwd_alloc = values[4].split(/(\d+)/)[1].to_i
139
+ memory.wmem_queued = values[5].split(/(\d+)/)[1].to_i
140
+ memory.ropt_mem = values[6].split(/(\d+)/)[1].to_i
141
+ memory.back_log = values[7].split(/(\d+)/)[1].to_i
142
+ memory.sock_drop = values[8].split(/(\d+)/)[1].to_i
143
+
144
+ memory
145
+ end
146
+
147
+ def parse_address_port(values)
148
+ address = values.shift
149
+ port = nil
150
+
151
+ if address == '*' && Regexp.new(/skmem:\((\S+)\)/).match(values[0])
152
+ port = '*'
153
+ elsif Regexp.new(/\[(\S+)\]/).match(address)
154
+ tokens = address.split(/\[(\S+)\]/)
155
+ address = "[#{tokens[1]}]"
156
+ _, port = tokens[2].split(/:(\S+)/)
157
+ elsif Regexp.new(/:\S+/).match(address)
158
+ address, port = address.split(/:(\S+)/)
159
+ else
160
+ port = values.shift
161
+ end
162
+
163
+ port = Kanrisuru::Util.numeric?(port) ? port.to_i : port
164
+ [address, port]
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module Kanrisuru
6
+ module Core
7
+ module Stat
8
+ extend OsPackage::Define
9
+
10
+ os_define :linux, :dir?
11
+ os_define :linux, :file?
12
+ os_define :linux, :block_device?
13
+ os_define :linux, :char_device?
14
+ os_define :linux, :symlink?
15
+ os_define :linux, :file_type?
16
+ os_define :linux, :inode?
17
+ os_define :linux, :stat
18
+
19
+ FileStat = Struct.new(
20
+ :mode, :blocks, :device, :file_type,
21
+ :gid, :group, :links, :inode,
22
+ :path, :fsize, :uid, :user,
23
+ :last_access, :last_modified, :last_changed
24
+ )
25
+
26
+ def dir?(path)
27
+ file_type?(path, 'directory')
28
+ end
29
+
30
+ def file?(path)
31
+ file_type?(path, 'regular file')
32
+ end
33
+
34
+ def empty_file?(path)
35
+ file_type?(path, 'regular empty file')
36
+ end
37
+
38
+ def block_device?(path)
39
+ file_type?(path, 'block special file')
40
+ end
41
+
42
+ def char_device?(path)
43
+ file_type?(path, 'character special file')
44
+ end
45
+
46
+ def symlink?(path)
47
+ file_type?(path, 'symbolic link')
48
+ end
49
+
50
+ def inode?(path)
51
+ command = Kanrisuru::Command.new("stat #{path}")
52
+ command.append_arg('-c', '%i')
53
+
54
+ execute_shell(command)
55
+ command.success?
56
+ end
57
+
58
+ def file_type?(path, type)
59
+ command = Kanrisuru::Command.new("stat #{path}")
60
+ command.append_arg('-c', '%F')
61
+
62
+ execute(command)
63
+
64
+ result = Kanrisuru::Result.new(command, &:to_s)
65
+
66
+ result.success? ? result.data == type : false
67
+ end
68
+
69
+ def stat(path, opts = {})
70
+ follow = opts[:follow]
71
+
72
+ command = Kanrisuru::Command.new('stat')
73
+ command.append_flag('-L', follow)
74
+ command.append_arg('-c', '%A,%b,%D,%F,%g,%G,%h,%i,%n,%s,%u,%U,%x,%y,%z')
75
+ command << path
76
+
77
+ execute(command)
78
+
79
+ Kanrisuru::Result.new(command) do |cmd|
80
+ string = cmd.to_s
81
+ values = string.split(',')
82
+
83
+ FileStat.new(
84
+ Kanrisuru::Mode.new(values[0]),
85
+ values[1].to_i,
86
+ values[2],
87
+ values[3],
88
+ values[4].to_i,
89
+ values[5],
90
+ values[6].to_i,
91
+ values[7].to_i,
92
+ values[8],
93
+ values[9].to_i,
94
+ values[10].to_i,
95
+ values[11],
96
+ values[12] ? DateTime.parse(values[12]) : nil,
97
+ values[13] ? DateTime.parse(values[13]) : nil,
98
+ values[14] ? DateTime.parse(values[14]) : nil
99
+ )
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end