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,1032 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ipaddr'
4
+
5
+ module Kanrisuru
6
+ module Core
7
+ module IP
8
+ extend OsPackage::Define
9
+
10
+ IPROUTE2_JSON_VERSION = 180_129
11
+
12
+ IPLinkProperty = Struct.new(
13
+ :index, :name, :flags, :mtu,
14
+ :qdisc, :state, :group, :qlen,
15
+ :link_mode, :link_type, :mac_address, :alias,
16
+ :stats
17
+ )
18
+
19
+ IPAddressProperty = Struct.new(
20
+ :index, :name, :flags, :mtu,
21
+ :qdisc, :state, :group, :qlen,
22
+ :link_type, :mac_address,
23
+ :address_info, :stats
24
+ )
25
+
26
+ IPAddressInfo = Struct.new(
27
+ :family, :ip, :broadcast, :scope,
28
+ :dynamic, :valid_life_time, :preferred_life_time
29
+ )
30
+
31
+ IPAddressLabel = Struct.new(
32
+ :address, :prefix_length, :label
33
+ )
34
+
35
+ IPRoute = Struct.new(
36
+ :destination, :gateway, :device, :protocol, :scope, :preferred_source, :metric, :flags
37
+ )
38
+
39
+ IPRule = Struct.new(:priority, :source, :table)
40
+
41
+ IPNeighbour = Struct.new(:destination, :device, :lladdr, :state, :stats)
42
+ IPNeighbourStats = Struct.new(:used, :confirmed, :updated, :probes, :ref_count)
43
+
44
+ IPMAddress = Struct.new(:index, :name, :maddr)
45
+ IPMAddressEntry = Struct.new(:family, :link, :address, :users)
46
+
47
+ IP_ROUTE_TYPES = %w[
48
+ unicast unreachable blackhole prohibit local
49
+ broadcast throw nat via anycast multicast
50
+ ].freeze
51
+
52
+ IPStats = Struct.new(:rx, :tx)
53
+ IPStatRX = Struct.new(:bytes, :packets, :errors, :dropped, :over_errors, :multicast)
54
+ IPStatTX = Struct.new(:bytes, :packets, :errors, :dropped, :carrier_errors, :collisions)
55
+
56
+ os_define :linux, :ip
57
+
58
+ def ip(object, action = nil, opts = {})
59
+ if action.instance_of?(Hash)
60
+ opts = action
61
+ action = 'show'
62
+ end
63
+
64
+ case object
65
+ when 'link', 'l'
66
+ ip_link(action, opts)
67
+ when 'address', 'addr', 'a'
68
+ ip_address(action, opts)
69
+ when 'addrlabel', 'addrl'
70
+ ip_address_label(action, opts)
71
+ when 'route', 'r', 'ro', 'rou', 'rout'
72
+ ip_route(action, opts)
73
+ when 'rule', 'ru'
74
+ ip_rule(action, opts)
75
+ when 'neighbour', 'neigh', 'n'
76
+ ip_neighbour(action, opts)
77
+ when 'maddress', 'maddr', 'm'
78
+ ip_maddress(action, opts)
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ def ip_version
85
+ command = Kanrisuru::Command.new('ip -V')
86
+ execute_shell(command)
87
+
88
+ raise 'ip command not found' if command.failure?
89
+
90
+ command.to_s.split('ip utility, iproute2-ss')[1].to_i
91
+ end
92
+
93
+ def ip_link(action, opts)
94
+ command = nil
95
+
96
+ case action
97
+ when 'show', 'list'
98
+ version = ip_version
99
+
100
+ command = Kanrisuru::Command.new('ip')
101
+ command.append_flag('-json') if version >= IPROUTE2_JSON_VERSION
102
+ command.append_flag('-s', opts[:stats])
103
+ command.append_arg('-family', opts[:family])
104
+ command << 'link show'
105
+
106
+ command.append_arg('dev', opts[:dev])
107
+ command.append_arg('group', opts[:group])
108
+ command.append_arg('master', opts[:master])
109
+ command.append_arg('type', opts[:type])
110
+ command.append_arg('vrf', opts[:vrf])
111
+
112
+ command.append_flag('up', opts[:up])
113
+ when 'set'
114
+ command = Kanrisuru::Command.new('ip link set')
115
+
116
+ raise ArgumentError, 'no device defined' unless opts[:dev]
117
+
118
+ command.append_arg('dev', opts[:dev])
119
+
120
+ case opts[:direction]
121
+ when 'up'
122
+ command.append_flag('up')
123
+ when 'down'
124
+ command.append_flag('down')
125
+ end
126
+
127
+ command.append_arg('arp', opts[:arp])
128
+ command.append_arg('multicast', opts[:multicast])
129
+ command.append_arg('dynamic', opts[:dynamic])
130
+ command.append_arg('name', opts[:name])
131
+ command.append_arg('txqueuelen', opts[:txqueuelen])
132
+ command.append_arg('txqlen', opts[:txqlen])
133
+ command.append_arg('mtu', opts[:mtu])
134
+ command.append_arg('address', opts[:address])
135
+ command.append_arg('broadcast', opts[:broadcast])
136
+ command.append_arg('brd', opts[:brd])
137
+ command.append_arg('peer', opts[:peer])
138
+ command.append_arg('netns', opts[:netns])
139
+
140
+ if Kanrisuru::Util.present?(opts[:vf])
141
+ command.append_arg('vf', opts[:vf])
142
+ command.append_arg('mac', opts[:mac])
143
+
144
+ if Kanrisuru::Util.present?(opts[:vlan])
145
+ command.append_arg('vlan', opts[:vlan])
146
+ command.append_arg('qos', opts[:qos])
147
+ end
148
+
149
+ command.append_arg('rate', opts[:rate])
150
+ end
151
+ end
152
+
153
+ execute_shell(command)
154
+
155
+ Kanrisuru::Result.new(command) do |cmd|
156
+ if %w[show list].include?(action)
157
+ if version >= IPROUTE2_JSON_VERSION
158
+ begin
159
+ ip_link_result_json(cmd.to_json)
160
+ rescue JSON::ParserError
161
+ ip_link_result_parse(cmd.to_a)
162
+ end
163
+ else
164
+ ip_link_result_parse(cmd.to_a)
165
+ end
166
+ end
167
+ end
168
+ end
169
+
170
+ def ip_address(action, opts)
171
+ command = nil
172
+
173
+ case action
174
+ when 'show', 'list'
175
+ version = ip_version
176
+
177
+ command = Kanrisuru::Command.new('ip')
178
+ command.append_flag('-json') if version >= IPROUTE2_JSON_VERSION
179
+ command.append_flag('-s', opts[:stats])
180
+ command.append_arg('-family', opts[:family])
181
+ command << 'address show'
182
+
183
+ command.append_arg('dev', opts[:dev])
184
+ command.append_arg('scope', opts[:scope])
185
+ command.append_arg('to', opts[:prefix])
186
+ command.append_arg('label', opts[:label])
187
+
188
+ command.append_flag('dynamic', opts[:dynamic])
189
+ command.append_flag('permanent', opts[:permanent])
190
+ command.append_flag('tenative', opts[:tenative])
191
+ command.append_flag('deprecated', opts[:deprecated])
192
+ command.append_flag('primary', opts[:primary])
193
+ command.append_flag('secondary', opts[:secondary])
194
+ command.append_flag('up', opts[:up])
195
+ when 'add'
196
+ command = Kanrisuru::Command.new('ip address add')
197
+ command << opts[:address]
198
+
199
+ command.append_arg('dev', opts[:dev])
200
+ command.append_arg('label', opts[:label])
201
+ command.append_arg('scope', opts[:scope])
202
+ when 'del', 'delete'
203
+ command = Kanrisuru::Command.new('ip address del')
204
+ command << opts[:address]
205
+
206
+ command.append_arg('dev', opts[:dev])
207
+ command.append_arg('label', opts[:label])
208
+ command.append_arg('scope', opts[:scope])
209
+ when 'flush'
210
+ command = Kanrisuru::Command.new('ip address flush')
211
+
212
+ command.append_arg('dev', opts[:dev])
213
+ command.append_arg('scope', opts[:scope])
214
+ comamnd.append_arg('to', opts[:prefix])
215
+ command.append_arg('label', opts[:label])
216
+
217
+ command.append_flag('dynamic', opts[:dynamic])
218
+ command.append_flag('permanent', opts[:permanent])
219
+ command.append_flag('tenative', opts[:tenative])
220
+ command.append_flag('deprecated', opts[:deprecated])
221
+ command.append_flag('primary', opts[:primary])
222
+ command.append_flag('secondary', opts[:secondary])
223
+ end
224
+
225
+ execute_shell(command)
226
+
227
+ Kanrisuru::Result.new(command) do |cmd|
228
+ if %w[show list].include?(action)
229
+ if version >= IPROUTE2_JSON_VERSION
230
+ begin
231
+ ip_address_result_json(cmd.to_json)
232
+ rescue JSON::ParserError
233
+ ip_address_result_parse(cmd.to_a)
234
+ end
235
+ else
236
+ ip_address_result_parse(cmd.to_a)
237
+ end
238
+ end
239
+ end
240
+ end
241
+
242
+ def ip_address_label(action, opts)
243
+ command = nil
244
+
245
+ case action
246
+ when 'show', 'list'
247
+ version = ip_version
248
+
249
+ command = Kanrisuru::Command.new('ip')
250
+ command.append_flag('-json') if version >= IPROUTE2_JSON_VERSION
251
+ command << 'addrlabel list'
252
+ when 'flush'
253
+ command = Kanrisuru::Command.new('ip addrlabel flush')
254
+ when 'add'
255
+ command = Kanrisuru::Command.new('ip addrlabel add')
256
+ command.append_arg('prefix', opts[:prefix])
257
+ command.append_arg('dev', opts[:dev])
258
+ command.append_arg('label', opts[:label])
259
+ when 'del'
260
+ command = Kanrisuru::Command.new('ip addrlabel del')
261
+ command.append_arg('prefix', opts[:prefix])
262
+ command.append_arg('dev', opts[:dev])
263
+ command.append_arg('label', opts[:label])
264
+ end
265
+
266
+ execute_shell(command)
267
+
268
+ Kanrisuru::Result.new(command) do |cmd|
269
+ if %w[show list].include?(action)
270
+ if version >= IPROUTE2_JSON_VERSION
271
+ begin
272
+ ip_address_label_result_json(cmd.to_json)
273
+ rescue JSON::ParserError
274
+ ip_address_label_result_parse(cmd.to_a)
275
+ end
276
+ else
277
+ ip_address_label_result_parse(cmd.to_a)
278
+ end
279
+ end
280
+ end
281
+ end
282
+
283
+ def ip_route(action, opts)
284
+ case action
285
+ when 'show', 'list'
286
+ version = ip_version
287
+
288
+ command = Kanrisuru::Command.new('ip')
289
+ command.append_flag('-json') if version >= IPROUTE2_JSON_VERSION
290
+ command.append_arg('-family', opts[:family])
291
+ command << 'route show'
292
+
293
+ command.append_arg('to', opts[:to])
294
+ command.append_arg('dev', opts[:dev])
295
+ command.append_arg('proto', opts[:proto])
296
+ command.append_arg('type', opts[:type])
297
+ command.append_arg('via', opts[:via])
298
+ command.append_arg('src', opts[:src])
299
+ command.append_arg('realms', opts[:realms])
300
+ when 'flush'
301
+ command = Kanrisuru::Command.new('ip')
302
+ command.append_arg('-family', opts[:family])
303
+ command << 'route flush'
304
+
305
+ command.append_arg('to', opts[:to])
306
+ command.append_arg('dev', opts[:dev])
307
+ command.append_arg('proto', opts[:proto])
308
+ command.append_arg('type', opts[:type])
309
+ command.append_arg('via', opts[:via])
310
+ command.append_arg('src', opts[:src])
311
+ command.append_arg('realm', opts[:realm])
312
+ command.append_arg('realms', opts[:realm])
313
+ when 'add', 'change', 'append', 'del', 'delete'
314
+ command = Kanrisuru::Command.new('ip route')
315
+ command << action
316
+
317
+ command.append_arg('to', opts[:to])
318
+ command.append_arg('tos', opts[:tos])
319
+ command.append_arg('dsfield', opts[:dsfield])
320
+ command.append_arg('metric', opts[:metric])
321
+ command.append_arg('preference', opts[:preference])
322
+ command.append_arg('table', opts[:table])
323
+ command.append_arg('vrf', opts[:vrf])
324
+ command.append_arg('dev', opts[:dev])
325
+ command.append_arg('via', opts[:via])
326
+ command.append_arg('src', opts[:src])
327
+ command.append_arg('realm', opts[:realm])
328
+
329
+ command.append_arg('mtu', opts[:mtu])
330
+ command.append_arg('window', opts[:window])
331
+ command.append_arg('rtt', opts[:rtt])
332
+ command.append_arg('rttvar', opts[:rttvar])
333
+ command.append_arg('rto_min', opts[:rto_min])
334
+ command.append_arg('ssthresh', opts[:ssthresh])
335
+ command.append_arg('cwnd', opts[:cwnd])
336
+ command.append_arg('initcwnd', opts[:initcwnd])
337
+ command.append_arg('initrwnd', opts[:initrwnd])
338
+ command.append_arg('features', opts[:features])
339
+ command.append_arg('quickack', opts[:quickack])
340
+ command.append_arg('fastopen_no_cookie', opts[:fastopen_no_cookie])
341
+
342
+ if Kanrisuru::Util.present?(opts[:congctl])
343
+ if Kanrisuru::Util.present?(opts[:congctl_lock])
344
+ command.append_arg('congctl', opts[:congctl])
345
+ else
346
+ command.append_arg('congctl lock', opts[:congctl])
347
+ end
348
+ end
349
+
350
+ command.append_arg('advmss', opts[:advmss])
351
+ command.append_arg('reordering', opts[:reordering])
352
+
353
+ if Kanrisuru::Util.present?(opts[:next_hop])
354
+ next_hop = opts[:next_hop]
355
+
356
+ command << 'next_hop'
357
+ command.append_arg('via', next_hop[:via])
358
+ command.append_arg('dev', next_hop[:dev])
359
+ command.append_arg('weight', next_hop[:weight])
360
+ end
361
+
362
+ command.append_arg('scope', opts[:scope])
363
+ command.append_arg('protocol', opts[:protocol])
364
+ command.append_flag('onlink', opts[:onlink])
365
+ command.append_arg('pref', opts[:pref])
366
+ when 'get'
367
+ command = Kanrisuru::Command.new('ip route get')
368
+
369
+ command.append_arg('to', opts[:to])
370
+ command.append_arg('from', opts[:from])
371
+ command.append_arg('tos', opts[:tos])
372
+ command.append_arg('dsfield', opts[:dsfield])
373
+ command.append_arg('iif', opts[:iif])
374
+ command.append_arg('oif', opts[:oif])
375
+ command.append_arg('mark', opts[:mark])
376
+ command.append_arg('vrf', opts[:vrf])
377
+ command.append_arg('ipproto', opts[:ipproto])
378
+ command.append_arg('sport', opts[:sport])
379
+ command.append_arg('dport', opts[:dport])
380
+
381
+ command.append_flag('connected', opts[:connected])
382
+ end
383
+
384
+ execute_shell(command)
385
+
386
+ Kanrisuru::Result.new(command) do |cmd|
387
+ if %w[show list].include?(action)
388
+ if version >= IPROUTE2_JSON_VERSION
389
+ begin
390
+ ip_route_result_json(cmd.to_json)
391
+ rescue JSON::ParserError
392
+ ip_route_result_parse(cmd.to_a)
393
+ end
394
+ else
395
+ ip_route_result_parse(cmd.to_a)
396
+ end
397
+ end
398
+ end
399
+ end
400
+
401
+ def ip_rule(action, opts)
402
+ case action
403
+ when 'show', 'list'
404
+ version = ip_version
405
+
406
+ command = Kanrisuru::Command.new('ip')
407
+ command.append_flag('-json') if version >= IPROUTE2_JSON_VERSION
408
+
409
+ command << 'rule show'
410
+ when 'flush'
411
+ command = Kanrisuru::Command.new('ip rule flush')
412
+ when 'add', 'delete'
413
+ command = Kanrisuru::Command.new('ip rule')
414
+ command << action
415
+
416
+ command.append_arg('type', opts[:type])
417
+ command.append_arg('from', opts[:from])
418
+ comamnd.append_arg('to', opts[:to])
419
+ command.append_arg('iif', opts[:iif])
420
+ comamnd.append_arg('tos', opts[:tos])
421
+ command.append_arg('dsfield', opts[:dsfield])
422
+ comamnd.append_arg('fwmark', opts[:fwmark])
423
+ comamnd.append_arg('priority', opts[:priority])
424
+ comamnd.append_arg('table', opts[:table])
425
+ comamnd.append_arg('realms', opts[:realms])
426
+ command.append_arg('nat', opts[:nat])
427
+ end
428
+
429
+ execute_shell(command)
430
+
431
+ Kanrisuru::Result.new(command) do |cmd|
432
+ if %w[show list].include?(action)
433
+ if version >= IPROUTE2_JSON_VERSION
434
+ begin
435
+ ip_rule_result_json(cmd.to_json)
436
+ rescue JSON::ParserError
437
+ ip_rule_result_parse(cmd.to_a)
438
+ end
439
+ else
440
+ ip_rule_result_parse(cmd.to_a)
441
+ end
442
+ end
443
+ end
444
+ end
445
+
446
+ def ip_neighbour(action, opts)
447
+ case action
448
+ when 'add', 'change', 'replace', 'del', 'delete'
449
+ command = Kanrisuru::Command.new('ip neighbour')
450
+ command << action
451
+
452
+ command.append_arg('to', opts[:to])
453
+ command.append_arg('dev', opts[:dev])
454
+
455
+ if action != 'del' && action != 'delete'
456
+ command.append_arg('lladdr', opts[:lladdr])
457
+ command.append_arg('nud', opts[:nud])
458
+ end
459
+
460
+ command.append_flag('permanent', opts[:permanent])
461
+ command.append_flag('noarp', opts[:noarp])
462
+ command.append_flag('reachable', opts[:reachable])
463
+ command.append_flag('stale', opts[:stale])
464
+ when 'show', 'list'
465
+ version = ip_version
466
+
467
+ command = Kanrisuru::Command.new('ip')
468
+ command.append_flag('-json') if version >= IPROUTE2_JSON_VERSION
469
+ command.append_flag('-s', opts[:stats])
470
+
471
+ command << 'neighbour show'
472
+
473
+ command.append_arg('to', opts[:to])
474
+ command.append_arg('dev', opts[:dev])
475
+ command.append_arg('nud', opts[:nud])
476
+
477
+ command.append_flag('unused', opts[:unused])
478
+ when 'flush'
479
+ command = Kanrisuru::Command.new('ip neighbour flush')
480
+ command.append_arg('to', opts[:to])
481
+ command.append_arg('dev', opts[:dev])
482
+ command.append_arg('nud', opts[:nud])
483
+
484
+ command.append_flag('unused', opts[:unused])
485
+ end
486
+
487
+ execute_shell(command)
488
+
489
+ Kanrisuru::Result.new(command) do |cmd|
490
+ if %w[show list].include?(action)
491
+ if version >= IPROUTE2_JSON_VERSION
492
+ begin
493
+ ip_neighbour_result_json(cmd.to_json)
494
+ rescue JSON::ParserError
495
+ ip_neighbour_result_parse(cmd.to_a)
496
+ end
497
+ else
498
+ ip_neighbour_result_parse(cmd.to_a)
499
+ end
500
+ end
501
+ end
502
+ end
503
+
504
+ def ip_maddress(action, opts)
505
+ case action
506
+ when 'show', 'list'
507
+ command = Kanrisuru::Command.new('ip')
508
+
509
+ version = ip_version
510
+ command.append_flag('-json') if version >= IPROUTE2_JSON_VERSION
511
+ command.append_arg('-family', opts[:family])
512
+ command << 'maddress show'
513
+
514
+ command.append_arg('dev', opts[:dev])
515
+ when 'add', 'delete', 'del'
516
+ command = Kanrisuru::Command.new('ip maddress')
517
+ command << action
518
+
519
+ command.append_arg('address', opts[:lladdress])
520
+ command.append_arg('dev', opts[:dev])
521
+ end
522
+
523
+ execute_shell(command)
524
+
525
+ Kanrisuru::Result.new(command) do |cmd|
526
+ if %w[show list].include?(action)
527
+ if version >= IPROUTE2_JSON_VERSION
528
+ begin
529
+ ip_maddress_result_json(cmd.to_json)
530
+ rescue JSON::ParserError
531
+ ip_maddress_result_parse(cmd.to_a)
532
+ end
533
+ else
534
+ ip_maddress_result_parse(cmd.to_a)
535
+ end
536
+ end
537
+ end
538
+ end
539
+
540
+ def ip_maddress_result_json(rows)
541
+ rows.map do |row|
542
+ maddress = IPMAddress.new(row['ifindex'], row['ifname'], [])
543
+
544
+ entries = row['maddr'] || []
545
+ entries.each do |entry|
546
+ ipmaddress_entry = IPMAddressEntry.new
547
+ entry.each do |key, value|
548
+ ipmaddress_entry[key] = value
549
+ end
550
+
551
+ maddress.maddr << ipmaddress_entry
552
+ end
553
+
554
+ maddress
555
+ end
556
+ end
557
+
558
+ def ip_maddress_result_parse(lines)
559
+ rows = []
560
+ current_row = nil
561
+
562
+ lines.each.with_index do |line, _index|
563
+ case line
564
+ when /^\d+:\s/
565
+ rows << current_row unless current_row.nil?
566
+
567
+ current_row = IPMAddress.new
568
+ parse_ip_maddr_name(current_row, line)
569
+ when /^link/
570
+ _, link = line.split
571
+
572
+ entry = IPMAddressEntry.new
573
+ entry.link = link
574
+
575
+ current_row.maddr << entry
576
+ when /^inet/
577
+ values = line.split
578
+
579
+ entry = IPMAddressEntry.new
580
+ values.each.with_index do |value, index|
581
+ case value
582
+ when 'inet', 'inet6'
583
+ entry.family = value
584
+ entry.address = values[index + 1]
585
+ when 'users'
586
+ entry.users = values[index + 1].to_i
587
+ end
588
+ end
589
+
590
+ current_row.maddr << entry
591
+ end
592
+ end
593
+
594
+ rows << current_row
595
+ rows
596
+ end
597
+
598
+ def ip_link_result_json(rows)
599
+ result = []
600
+ rows.each do |row|
601
+ next if row['ifindex'].instance_of?(NilClass)
602
+
603
+ new_row = IPLinkProperty.new(
604
+ row['ifindex'], row['ifname'], row['flags'], row['mtu'], row['qdisc'],
605
+ row['operstate'], row['group'], row['txqlen'], row['linkmode'],
606
+ row['link_type'], row['address'], row['ifalias'], nil
607
+ )
608
+
609
+ if row.key?('stats64')
610
+ rx = row['stats64']['rx']
611
+ tx = row['stats64']['tx']
612
+
613
+ new_row[:stats] = IPStats.new(
614
+ IPStatRX.new(
615
+ rx['bytes'], rx['packets'], rx['errors'],
616
+ rx['dropped'], rx['over_errors'], rx['multicast']
617
+ ),
618
+ IPStatTX.new(
619
+ tx['bytes'], tx['packets'], tx['errors'],
620
+ tx['dropped'], tx['carrier_errors'], tx['collisions']
621
+ )
622
+ )
623
+ end
624
+
625
+ result << new_row
626
+ end
627
+
628
+ result
629
+ end
630
+
631
+ def ip_address_result_json(rows)
632
+ result = []
633
+ rows.each do |row|
634
+ next if row['ifindex'].instance_of?(NilClass)
635
+
636
+ new_row = IPAddressProperty.new(
637
+ row['ifindex'], row['ifname'], row['flags'], row['mtu'], row['qdisc'],
638
+ row['operstate'], row['group'], row['txqlen'], row['link_type'], row['address'], []
639
+ )
640
+
641
+ if row.key?('stats64')
642
+ rx = row['stats64']['rx']
643
+ tx = row['stats64']['tx']
644
+
645
+ new_row[:stats] = IPStats.new(
646
+ IPStatRX.new(
647
+ rx['bytes'], rx['packets'], rx['errors'],
648
+ rx['dropped'], rx['over_errors'], rx['multicast']
649
+ ),
650
+ IPStatTX.new(
651
+ tx['bytes'], tx['packets'], tx['errors'],
652
+ tx['dropped'], tx['carrier_errors'], tx['collisions']
653
+ )
654
+ )
655
+ end
656
+
657
+ addr_info = row['addr_info'] || []
658
+
659
+ new_row[:address_info] = addr_info.map do |address|
660
+ dynamic = address['dynamic'] == true || address['dynamic'] == 'true'
661
+
662
+ IPAddressInfo.new(
663
+ address['family'],
664
+ IPAddr.new(address['local']),
665
+ address['broadcast'],
666
+ address['scope'],
667
+ dynamic,
668
+ address['valid_life_time'], address['preferred_life_time']
669
+ )
670
+ end
671
+
672
+ result << new_row
673
+ end
674
+
675
+ result
676
+ end
677
+
678
+ def ip_neighbour_result_json(rows)
679
+ rows.map do |row|
680
+ neighbour = IPNeighbour.new(
681
+ IPAddr.new(row['dst']),
682
+ row['dev'],
683
+ row['lladdr'],
684
+ row['state']
685
+ )
686
+
687
+ if row.key?('used') || row.key?('confirmed') ||
688
+ row.key?('refcnt') || row.key?('updated') ||
689
+ row.key?('probes')
690
+ neighbour.stats = IPNeighbourStats.new
691
+
692
+ neighbour.stats.ref_count = row['refcnt']
693
+ neighbour.stats.used = row['used']
694
+ neighbour.stats.confirmed = row['confirmed']
695
+ neighbour.stats.probes = row['probes']
696
+ neighbour.stats.updated = row['updated']
697
+ end
698
+
699
+ neighbour
700
+ end
701
+ end
702
+
703
+ def ip_neighbour_result_parse(lines)
704
+ rows = []
705
+ lines.each do |line|
706
+ values = line.split
707
+
708
+ neighbour = IPNeighbour.new(IPAddr.new(values[0]))
709
+ neighbour.state = [values[values.length - 1]]
710
+
711
+ if line.include?('probes') || line.include?('used') || line.include?('ref')
712
+ neighbour.stats = IPNeighbourStats.new
713
+ end
714
+
715
+ values.each.with_index do |value, index|
716
+ case value
717
+ when 'dev'
718
+ neighbour.device = values[index + 1]
719
+ when 'lladdr'
720
+ neighbour.lladdr = values[index + 1]
721
+ when 'ref'
722
+ neighbour.stats.ref_count = values[index + 1] ? values[index + 1].to_i : nil
723
+ when 'used'
724
+ used, confirmed, updated = values[index + 1].split('/')
725
+
726
+ neighbour.stats.used = used ? used.to_i : nil
727
+ neighbour.stats.updated = updated ? updated.to_i : nil
728
+ neighbour.stats.confirmed = confirmed ? confirmed.to_i : nil
729
+ when 'probes'
730
+ neighbour.stats.probes = values[index + 1] ? values[index + 1].to_i : nil
731
+ end
732
+ end
733
+
734
+ rows << neighbour
735
+ end
736
+
737
+ rows
738
+ end
739
+
740
+ def ip_address_label_result_json(rows)
741
+ result = []
742
+
743
+ rows.each do |row|
744
+ new_row = IPAddressLabel.new(
745
+ row['address'], row['prefixlen'], row['label']
746
+ )
747
+
748
+ result << new_row
749
+ end
750
+
751
+ result
752
+ end
753
+
754
+ def ip_route_result_json(rows)
755
+ rows.map do |row|
756
+ IPRoute.new(
757
+ row['dst'],
758
+ row['gateway'],
759
+ row['dev'],
760
+ row['protocol'],
761
+ row['scope'],
762
+ row['prefsrc'],
763
+ row['metric'],
764
+ row['flags']
765
+ )
766
+ end
767
+ end
768
+
769
+ def ip_route_result_parse(lines)
770
+ rows = []
771
+
772
+ lines.map do |line|
773
+ values = line.split(/\s/)
774
+
775
+ ip_route = IPRoute.new(values[0])
776
+ ip_route.flags = []
777
+
778
+ values.each.with_index do |value, index|
779
+ case value
780
+ when 'via'
781
+ ip_route.gateway = values[index + 1]
782
+ when 'dev'
783
+ ip_route.device = values[index + 1]
784
+ when 'proto'
785
+ ip_route.protocol = values[index + 1]
786
+ when 'src'
787
+ ip_route.preferred_source = values[index + 1]
788
+ when 'scope'
789
+ ip_route.scope = values[index + 1]
790
+ when 'flags'
791
+ ip_route.flags = values[index + 1]
792
+ when 'metric'
793
+ ip_route.metric = values[index + 1]
794
+ end
795
+ end
796
+
797
+ rows << ip_route
798
+ end
799
+
800
+ rows
801
+ end
802
+
803
+ def ip_rule_result_json(rows)
804
+ rows.map do |row|
805
+ IPRule.new(
806
+ row['priority'],
807
+ row['src'],
808
+ row['table']
809
+ )
810
+ end
811
+ end
812
+
813
+ def ip_rule_result_parse(lines)
814
+ rows = []
815
+ lines.each do |line|
816
+ _, priority, string = line.split(/(\d+):\s/)
817
+ values = string.split(/\s/)
818
+
819
+ rule = IPRule.new(priority)
820
+
821
+ values.each.with_index do |value, index|
822
+ case value
823
+ when 'from'
824
+ rule.source = values[index + 1]
825
+ when 'lookup'
826
+ rule.table = values[index + 1]
827
+ end
828
+ end
829
+
830
+ rows << rule
831
+ end
832
+
833
+ rows
834
+ end
835
+
836
+ def ip_link_result_parse(lines)
837
+ rows = []
838
+ current_row = nil
839
+
840
+ lines.each.with_index do |line, index|
841
+ case line
842
+ when /^\d+:\s/
843
+ rows << current_row unless current_row.nil?
844
+
845
+ current_row = IPLinkProperty.new
846
+ parse_ip_row(current_row, line)
847
+ when /^link/
848
+ parse_link(current_row, line)
849
+ when /^alias/
850
+ parse_alias(current_row, line)
851
+ when /^RX:/
852
+ parse_rx(current_row, lines[index + 1])
853
+ when /^TX:/
854
+ parse_tx(current_row, lines[index + 1])
855
+ end
856
+ end
857
+
858
+ rows << current_row
859
+ rows
860
+ end
861
+
862
+ def ip_address_result_parse(lines)
863
+ rows = []
864
+ current_row = nil
865
+
866
+ lines.each.with_index do |line, index|
867
+ case line
868
+ when /^\d+:\s/
869
+ rows << current_row unless current_row.nil?
870
+
871
+ current_row = IPAddressProperty.new
872
+ current_row.address_info = []
873
+
874
+ parse_ip_row(current_row, line)
875
+ when /^link/
876
+ parse_link(current_row, line)
877
+ when /^inet/
878
+ parse_address_info(current_row, line)
879
+ when /^valid_lft/
880
+ parse_valid(current_row, line)
881
+ when /^RX:/
882
+ parse_rx(current_row, lines[index + 1])
883
+ when /^TX:/
884
+ parse_tx(current_row, lines[index + 1])
885
+ end
886
+ end
887
+
888
+ rows << current_row
889
+ rows
890
+ end
891
+
892
+ def ip_address_label_result_parse(lines)
893
+ lines.map do |line|
894
+ _, addr, _, label = line.split(/\s/)
895
+ address, prefix_length = addr.split(%r{/})
896
+
897
+ IPAddressLabel.new(address, prefix_length.to_i, label)
898
+ end
899
+ end
900
+
901
+ def parse_alias(row, line)
902
+ _, alias_string = line.split('alias')
903
+ row.alias = alias_string
904
+ end
905
+
906
+ def parse_ip_maddr_name(row, line)
907
+ index = line.match(/^\d+/).to_s.to_i
908
+ _, name = line.split(/^\d+:\s/)
909
+
910
+ row.index = index
911
+ row.name = name
912
+ row.maddr = []
913
+ end
914
+
915
+ def parse_ip_row(row, line)
916
+ index = line.match(/^\d+/).to_s.to_i
917
+ _, string = line.split(/^\d+:\s/)
918
+ name = string.match(/^\w+/).to_s
919
+ _, string = string.split(/^\w+:\s/)
920
+ _, flags, string = string.split(/(<.+>)\s/)
921
+
922
+ flags = flags.gsub(/<?>?/, '')
923
+ flags = flags.split(',')
924
+
925
+ row.index = index
926
+ row.name = name
927
+ row.flags = flags
928
+
929
+ values = string.split(/\s/)
930
+ values.each.with_index do |_, i|
931
+ case values[i]
932
+ when 'mtu'
933
+ row.mtu = values[i + 1].to_i
934
+ when 'qdisc'
935
+ row.qdisc = values[i + 1]
936
+ when 'state'
937
+ row.state = values[i + 1]
938
+ when 'group'
939
+ row.group = values[i + 1]
940
+ when 'qlen'
941
+ row.qlen = values[i + 1].to_i
942
+ when 'mode'
943
+ row.link_mode = values[i + 1]
944
+ end
945
+ end
946
+ end
947
+
948
+ def parse_link(row, line)
949
+ _, string = line.split(%r{^link/})
950
+ link_type, mac_address = string.split
951
+
952
+ row.link_type = link_type
953
+ row.mac_address = mac_address
954
+ end
955
+
956
+ def parse_address_info(row, line)
957
+ values = line.split
958
+ address_info = IPAddressInfo.new
959
+
960
+ values.each.with_index do |_, index|
961
+ case values[index]
962
+ when 'inet', 'inet6'
963
+ address_info.family = values[index]
964
+ address_info.ip = IPAddr.new(values[index + 1].split('/')[0])
965
+ when 'brd'
966
+ address_info.broadcast = values[index + 1]
967
+ when 'scope'
968
+ address_info.scope = values[index + 1]
969
+ when 'dynamic'
970
+ address_info.dynamic = true
971
+ end
972
+ end
973
+
974
+ row.address_info << address_info
975
+ end
976
+
977
+ def parse_valid(row, line)
978
+ values = line.split
979
+
980
+ values.each.with_index do |_, index|
981
+ case values[index]
982
+ when 'valid_lft'
983
+ row.address_info.last.valid_life_time = values[index + 1]
984
+ when 'preferred_lft'
985
+ row.address_info.last.preferred_life_time = values[index + 1]
986
+ end
987
+ end
988
+ end
989
+
990
+ def parse_rx(row, line)
991
+ values = line.split
992
+
993
+ bytes = values[0].to_i
994
+ packets = values[1].to_i
995
+ errors = values[2].to_i
996
+ dropped = values[3].to_i
997
+ over_errors = values[4].to_i
998
+ multicast = values[5].to_i
999
+
1000
+ row.stats = IPStats.new
1001
+ row.stats.rx = IPStatRX.new(
1002
+ bytes,
1003
+ packets,
1004
+ errors,
1005
+ dropped,
1006
+ over_errors,
1007
+ multicast
1008
+ )
1009
+ end
1010
+
1011
+ def parse_tx(row, line)
1012
+ values = line.split
1013
+
1014
+ bytes = values[0].to_i
1015
+ packets = values[1].to_i
1016
+ errors = values[2].to_i
1017
+ dropped = values[3].to_i
1018
+ carrier_errors = values[4].to_i
1019
+ collisions = values[5].to_i
1020
+
1021
+ row.stats.tx = IPStatTX.new(
1022
+ bytes,
1023
+ packets,
1024
+ errors,
1025
+ dropped,
1026
+ carrier_errors,
1027
+ collisions
1028
+ )
1029
+ end
1030
+ end
1031
+ end
1032
+ end