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,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