kanrisuru 0.16.2 → 0.16.6
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +4 -7
- data/lib/kanrisuru/core/dmi/parsers/dmi.rb +14 -10
- data/lib/kanrisuru/mode/permission.rb +103 -0
- data/lib/kanrisuru/mode.rb +2 -98
- data/lib/kanrisuru/remote/fstab/entry.rb +154 -0
- data/lib/kanrisuru/remote/fstab/options.rb +143 -0
- data/lib/kanrisuru/remote/fstab.rb +9 -283
- data/lib/kanrisuru/version.rb +1 -1
- data/logo/kanrisuru-logo.png +0 -0
- data/spec/functional/remote/fstab_spec.rb +21 -0
- metadata +7 -4
- data/.rubocop_todo.yml +0 -0
- data/.travis.yml +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d786b070ee49222d70b394c5511e792c62899aff324f6f07b2a2edcd219b96a6
|
4
|
+
data.tar.gz: 1be24b3977601eeb24c0702b4e13d82fa86a36df561a5b78bf67bc488a752b82
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 33702dac744a1d6f232aebef781c447a67a4e4aa76af7fe89edb36284668937f3dc4c18dd152c5bc58811562cfdc68e983b9f9e6af3bbfb879d3c8edd9fccf61
|
7
|
+
data.tar.gz: ab67d01b9f71a8e7ba5dad6b060a1a9beb4f36fc36493b961524ccded3a0672a93fd3655f4ad1dd0d1aaf9828c49c60366a0a0a06d16b4ca93a0fa69cbc81f3b
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
## Kanrisuru 0.16.6 (December 26, 2021) ##
|
2
|
+
* Add `delete` to fstab class to delete an entry from the fstab.
|
3
|
+
|
4
|
+
## Kanrisuru 0.16.5 (December 25, 2021) ##
|
5
|
+
* Refactor `dmi_field_translate` to reduce complexity.
|
6
|
+
|
7
|
+
## Kanrisuru 0.16.4 (December 25, 2021) ##
|
8
|
+
* Refactor `Kanrisuru::Fstab::Entry` and `Kanrisuru::Fstab::Options` classes into separate files.
|
9
|
+
|
10
|
+
## Kanrisuru 0.16.3 (December 25, 2021) ##
|
11
|
+
* Refactor `Kanrisuru::Mode::Permission` class into separate file.
|
12
|
+
|
1
13
|
## Kanrisuru 0.16.2 (December 19, 2021) ##
|
2
14
|
* Organize functional ip specs
|
3
15
|
* Log in realtime, debug output the stdout from the remote server, as opposed to waiting until after the command is done.
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
<
|
2
|
-
<img src="
|
3
|
-
</
|
1
|
+
<h1>
|
2
|
+
<img src="./logo/kanrisuru-logo.png" alt="Kanrisuru" width="400" height="100%"/>
|
3
|
+
</h1>
|
4
4
|
|
5
|
-
<p
|
5
|
+
<p>
|
6
6
|
<a href="https://rubygems.org/gems/kanrisuru">
|
7
7
|
<img src="https://img.shields.io/gem/v/kanrisuru?style=flat-square" alt="Latest version" />
|
8
8
|
</a>
|
@@ -15,8 +15,6 @@
|
|
15
15
|
<img src="https://img.shields.io/codeclimate/maintainability/avamia/kanrisuru?style=flat-square" alt="Code Climate maintainability" />
|
16
16
|
</p>
|
17
17
|
|
18
|
-
# Kanrisuru
|
19
|
-
|
20
18
|
Kanrisuru (manage) helps you remotely control infrastructure using Ruby. This is done over SSH. I'm working on building up some basic functionality to help quickly provision, deploy and manage a single host or cluster of hosts.
|
21
19
|
|
22
20
|
The idea behind this project is not to replace the numerous other projects to manage your infrastrucutre, however, I've found there usually meant to be a standalone project that have their own ecosystem. With Kanrisuru, you essentailly plug the library directly into your ruby project.
|
@@ -104,7 +102,6 @@ HOSTS=ubuntu,debian,centos rspec
|
|
104
102
|
|
105
103
|
This will run tests on the ubuntu, debian and centos instances.
|
106
104
|
|
107
|
-
|
108
105
|
Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
109
106
|
|
110
107
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
@@ -93,37 +93,41 @@ module Kanrisuru
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def dmi_field_translate(struct, field)
|
96
|
-
field = field
|
97
|
-
field = field.gsub(/\s/, '_')
|
98
|
-
field = field.gsub('-', '_')
|
99
|
-
field = field.gsub(':', '')
|
96
|
+
field = dmi_scrub_field(field)
|
100
97
|
|
101
98
|
case struct.dmi_type
|
102
99
|
when 'Memory Device'
|
103
100
|
case field
|
104
101
|
when 'size'
|
105
|
-
|
102
|
+
'mem_size'
|
106
103
|
end
|
107
104
|
when 'System Slots'
|
108
105
|
case field
|
109
106
|
when 'length'
|
110
|
-
|
107
|
+
'slot_length'
|
111
108
|
end
|
112
109
|
when 'OEM Strings'
|
113
110
|
case field
|
114
111
|
when /^string/
|
115
|
-
|
112
|
+
'strings'
|
116
113
|
end
|
117
114
|
when 'Boot Integrity Services'
|
118
115
|
case field
|
119
116
|
when '16_bit_entry_point_address'
|
120
|
-
|
117
|
+
'sixteen_bit_entry_point_address'
|
121
118
|
when '32_bit_entry_point_address'
|
122
|
-
|
119
|
+
'thirty_two_bit_entry_point_address'
|
123
120
|
end
|
121
|
+
else
|
122
|
+
field
|
124
123
|
end
|
124
|
+
end
|
125
125
|
|
126
|
-
|
126
|
+
def dmi_scrub_field(field)
|
127
|
+
field = field.downcase
|
128
|
+
field = field.gsub(/\s/, '_')
|
129
|
+
field = field.gsub('-', '_')
|
130
|
+
field.gsub(':', '')
|
127
131
|
end
|
128
132
|
|
129
133
|
def dmi_type_to_struct(type)
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kanrisuru
|
4
|
+
class Mode
|
5
|
+
class Permission
|
6
|
+
attr_reader :symbolic
|
7
|
+
|
8
|
+
def initialize(numeric, symbolic)
|
9
|
+
@numeric = numeric
|
10
|
+
@symbolic = symbolic
|
11
|
+
|
12
|
+
update_symbolic_rwx
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_i
|
16
|
+
numeric.to_i
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
symbolic
|
21
|
+
end
|
22
|
+
|
23
|
+
def numeric
|
24
|
+
@numeric.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
def all?
|
28
|
+
read? && write? && execute?
|
29
|
+
end
|
30
|
+
|
31
|
+
def symbolic=(symbolic)
|
32
|
+
@symbolic = symbolic
|
33
|
+
|
34
|
+
update_symbolic_rwx
|
35
|
+
update_numeric
|
36
|
+
end
|
37
|
+
|
38
|
+
def numeric=(numeric)
|
39
|
+
@numeric = numeric
|
40
|
+
|
41
|
+
update_numeric_rwx
|
42
|
+
update_symbolic
|
43
|
+
end
|
44
|
+
|
45
|
+
def read=(boolean)
|
46
|
+
@readable = boolean
|
47
|
+
|
48
|
+
update_numeric
|
49
|
+
update_symbolic
|
50
|
+
end
|
51
|
+
|
52
|
+
def write=(boolean)
|
53
|
+
@writeable = boolean
|
54
|
+
|
55
|
+
update_numeric
|
56
|
+
update_symbolic
|
57
|
+
end
|
58
|
+
|
59
|
+
def execute=(boolean)
|
60
|
+
@executable = boolean
|
61
|
+
|
62
|
+
update_numeric
|
63
|
+
update_symbolic
|
64
|
+
end
|
65
|
+
|
66
|
+
def read?
|
67
|
+
@readable
|
68
|
+
end
|
69
|
+
|
70
|
+
def write?
|
71
|
+
@writeable
|
72
|
+
end
|
73
|
+
|
74
|
+
def execute?
|
75
|
+
@executable
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def update_symbolic_rwx
|
81
|
+
@readable = @symbolic.include?('r')
|
82
|
+
@writeable = @symbolic.include?('w')
|
83
|
+
@executable = @symbolic.include?('x')
|
84
|
+
end
|
85
|
+
|
86
|
+
def update_numeric_rwx
|
87
|
+
mode = @numeric.to_i(8)
|
88
|
+
|
89
|
+
@readable = ((mode >> 2) & 0b001) == 1
|
90
|
+
@writeable = ((mode >> 1) & 0b001) == 1
|
91
|
+
@executable = ((mode >> 0) & 0b001) == 1
|
92
|
+
end
|
93
|
+
|
94
|
+
def update_numeric
|
95
|
+
@numeric = (((read? ? 1 : 0) << 2) + ((write? ? 1 : 0) << 1) + (execute? ? 1 : 0)).to_s
|
96
|
+
end
|
97
|
+
|
98
|
+
def update_symbolic
|
99
|
+
@symbolic = "#{read? ? 'r' : '-'}#{write? ? 'w' : '-'}#{execute? ? 'x' : '-'}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/kanrisuru/mode.rb
CHANGED
@@ -1,105 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'mode/permission'
|
4
|
+
|
3
5
|
module Kanrisuru
|
4
6
|
class Mode
|
5
|
-
class Permission
|
6
|
-
attr_reader :symbolic
|
7
|
-
|
8
|
-
def initialize(numeric, symbolic)
|
9
|
-
@numeric = numeric
|
10
|
-
@symbolic = symbolic
|
11
|
-
|
12
|
-
update_symbolic_rwx
|
13
|
-
end
|
14
|
-
|
15
|
-
def to_i
|
16
|
-
numeric.to_i
|
17
|
-
end
|
18
|
-
|
19
|
-
def to_s
|
20
|
-
symbolic
|
21
|
-
end
|
22
|
-
|
23
|
-
def numeric
|
24
|
-
@numeric.to_s
|
25
|
-
end
|
26
|
-
|
27
|
-
def all?
|
28
|
-
read? && write? && execute?
|
29
|
-
end
|
30
|
-
|
31
|
-
def symbolic=(symbolic)
|
32
|
-
@symbolic = symbolic
|
33
|
-
|
34
|
-
update_symbolic_rwx
|
35
|
-
update_numeric
|
36
|
-
end
|
37
|
-
|
38
|
-
def numeric=(numeric)
|
39
|
-
@numeric = numeric
|
40
|
-
|
41
|
-
update_numeric_rwx
|
42
|
-
update_symbolic
|
43
|
-
end
|
44
|
-
|
45
|
-
def read=(boolean)
|
46
|
-
@readable = boolean
|
47
|
-
|
48
|
-
update_numeric
|
49
|
-
update_symbolic
|
50
|
-
end
|
51
|
-
|
52
|
-
def write=(boolean)
|
53
|
-
@writeable = boolean
|
54
|
-
|
55
|
-
update_numeric
|
56
|
-
update_symbolic
|
57
|
-
end
|
58
|
-
|
59
|
-
def execute=(boolean)
|
60
|
-
@executable = boolean
|
61
|
-
|
62
|
-
update_numeric
|
63
|
-
update_symbolic
|
64
|
-
end
|
65
|
-
|
66
|
-
def read?
|
67
|
-
@readable
|
68
|
-
end
|
69
|
-
|
70
|
-
def write?
|
71
|
-
@writeable
|
72
|
-
end
|
73
|
-
|
74
|
-
def execute?
|
75
|
-
@executable
|
76
|
-
end
|
77
|
-
|
78
|
-
private
|
79
|
-
|
80
|
-
def update_symbolic_rwx
|
81
|
-
@readable = @symbolic.include?('r')
|
82
|
-
@writeable = @symbolic.include?('w')
|
83
|
-
@executable = @symbolic.include?('x')
|
84
|
-
end
|
85
|
-
|
86
|
-
def update_numeric_rwx
|
87
|
-
mode = @numeric.to_i(8)
|
88
|
-
|
89
|
-
@readable = ((mode >> 2) & 0b001) == 1
|
90
|
-
@writeable = ((mode >> 1) & 0b001) == 1
|
91
|
-
@executable = ((mode >> 0) & 0b001) == 1
|
92
|
-
end
|
93
|
-
|
94
|
-
def update_numeric
|
95
|
-
@numeric = (((read? ? 1 : 0) << 2) + ((write? ? 1 : 0) << 1) + (execute? ? 1 : 0)).to_s
|
96
|
-
end
|
97
|
-
|
98
|
-
def update_symbolic
|
99
|
-
@symbolic = "#{read? ? 'r' : '-'}#{write? ? 'w' : '-'}#{execute? ? 'x' : '-'}"
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
7
|
attr_reader :owner, :group, :other
|
104
8
|
|
105
9
|
def initialize(mode)
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kanrisuru
|
4
|
+
module Remote
|
5
|
+
class Fstab
|
6
|
+
class Entry
|
7
|
+
attr_reader :device, :uuid, :invalid, :label, :type, :opts, :freq, :passno
|
8
|
+
attr_accessor :mount_point
|
9
|
+
|
10
|
+
def initialize(opts = {})
|
11
|
+
@host = opts[:host]
|
12
|
+
@line = opts[:line]
|
13
|
+
|
14
|
+
@default = nil
|
15
|
+
|
16
|
+
@device = opts[:device] || nil
|
17
|
+
@opts = opts[:opts] || nil
|
18
|
+
@label = opts[:label] || nil
|
19
|
+
@uuid = opts[:uuid] || nil
|
20
|
+
@mount_point = opts[:mount_point] || nil
|
21
|
+
@type = opts[:type] || nil
|
22
|
+
@freq = opts[:freq] || nil
|
23
|
+
@passno = opts[:passno] || nil
|
24
|
+
|
25
|
+
@changed = false
|
26
|
+
|
27
|
+
@ucount = 0
|
28
|
+
@special = false
|
29
|
+
@invalid = false
|
30
|
+
|
31
|
+
if Kanrisuru::Util.present?(@line) && @line.instance_of?(String)
|
32
|
+
parse_line!
|
33
|
+
elsif (Kanrisuru::Util.present?(@opts) && @opts.instance_of?(String)) || @opts.instance_of?(Hash)
|
34
|
+
@opts = Kanrisuru::Remote::Fstab::Options.new(@type, @opts)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def inspect
|
39
|
+
str = '#<Kanrisuru::Remote::Fstab::Entry:0x%<object_id>s ' \
|
40
|
+
'@line=%<line>s @device=%<device>s @label=%<label>s' \
|
41
|
+
'@uuid=%<uuid>s @freq=%<freq>s @pasno=%<passno>s' \
|
42
|
+
'@opts=%<opts>s}>'
|
43
|
+
|
44
|
+
format(
|
45
|
+
str,
|
46
|
+
object_id: object_id,
|
47
|
+
line: @line,
|
48
|
+
device: @device,
|
49
|
+
label: @label,
|
50
|
+
uuid: @uuid,
|
51
|
+
freq: @freq,
|
52
|
+
passno: @passno,
|
53
|
+
opts: @opts.inspect
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
def valid?
|
58
|
+
!@invalid
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_s(override = nil)
|
62
|
+
mode = override || @default
|
63
|
+
|
64
|
+
case mode
|
65
|
+
when 'uuid'
|
66
|
+
"UUID=#{@uuid} #{@mount_point} #{@type} #{@opts} #{@freq} #{@passno}"
|
67
|
+
when 'label'
|
68
|
+
"LABEL=#{@label} #{@mount_point} #{@type} #{@opts} #{@freq} #{@passno}"
|
69
|
+
else
|
70
|
+
"#{@device} #{@mount_point} #{@type} #{@opts} #{@freq} #{@passno}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def parse_line!
|
77
|
+
fsline, mp, @type, opts, freq, passno = @line.split
|
78
|
+
|
79
|
+
@mount_point = mp
|
80
|
+
@freq = freq || '0'
|
81
|
+
@passno = passno || '0'
|
82
|
+
|
83
|
+
@opts = Fstab::Options.new(@type, opts)
|
84
|
+
|
85
|
+
case @line
|
86
|
+
when /^\s*LABEL=/
|
87
|
+
@default = 'label'
|
88
|
+
parse_label(fsline)
|
89
|
+
when /^\s*UUID=/
|
90
|
+
@default = 'uuid'
|
91
|
+
parse_uuid(fsline)
|
92
|
+
when %r{^\s*/dev}
|
93
|
+
@default = 'dev'
|
94
|
+
parse_dev(fsline)
|
95
|
+
else
|
96
|
+
# TODO: somewhat risky to assume that everything else
|
97
|
+
# can be considered a special device, but validating this
|
98
|
+
# is really tricky.
|
99
|
+
@special = true
|
100
|
+
@device = fsline
|
101
|
+
end
|
102
|
+
|
103
|
+
# Fstab entries not matching real devices have device unknown
|
104
|
+
@invalid = (@line.split.count != 6) # invalid entry if < 6 columns
|
105
|
+
|
106
|
+
if (@uuid.nil? && @label.nil? && !@special) ||
|
107
|
+
@device =~ /^unknown_/ ||
|
108
|
+
(!@host.inode?(@device) && !@special)
|
109
|
+
@invalid = true
|
110
|
+
@ucount += 1
|
111
|
+
end
|
112
|
+
|
113
|
+
@invalid = true unless @freq =~ /0|1|2/ && @passno =~ /0|1|2/
|
114
|
+
end
|
115
|
+
|
116
|
+
def parse_label(fsline)
|
117
|
+
@label = fsline.split('=').last.strip.chomp
|
118
|
+
path = @host.realpath("/dev/disk/by-label/#{@label}").path
|
119
|
+
|
120
|
+
@device = begin
|
121
|
+
"/dev/#{path.split('/').last}"
|
122
|
+
rescue StandardError
|
123
|
+
"unknown_#{@ucount}"
|
124
|
+
end
|
125
|
+
|
126
|
+
result = @host.blkid(device: @device)
|
127
|
+
@uuid = result.success? ? result[0].uuid : nil
|
128
|
+
end
|
129
|
+
|
130
|
+
def parse_uuid(fsline)
|
131
|
+
@uuid = fsline.split('=').last.strip.chomp
|
132
|
+
path = @host.realpath("/dev/disk/by-uuid/#{uuid}").path
|
133
|
+
|
134
|
+
@device = begin
|
135
|
+
"/dev/#{path.split('/').last}"
|
136
|
+
rescue StandardError
|
137
|
+
"unknown_#{@ucount}"
|
138
|
+
end
|
139
|
+
|
140
|
+
result = @host.blkid(device: @device)
|
141
|
+
@label = result.success? ? result[0].label : nil
|
142
|
+
end
|
143
|
+
|
144
|
+
def parse_dev(fsline)
|
145
|
+
@device = fsline
|
146
|
+
result = @host.blkid(device: @device)
|
147
|
+
|
148
|
+
@label = result.success? ? result[0].label : nil
|
149
|
+
@uuid = result.success? ? result[0].uuid : nil
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kanrisuru
|
4
|
+
module Remote
|
5
|
+
class Fstab
|
6
|
+
class Options
|
7
|
+
def initialize(type, opts)
|
8
|
+
@type = type
|
9
|
+
@valid = false
|
10
|
+
|
11
|
+
if opts.instance_of?(String)
|
12
|
+
@opts = parse_opts(opts)
|
13
|
+
elsif opts.instance_of?(Hash)
|
14
|
+
@opts = opts.transform_keys(&:to_s)
|
15
|
+
else
|
16
|
+
raise ArgumentError, 'Invalid option type'
|
17
|
+
end
|
18
|
+
|
19
|
+
validate_opts!
|
20
|
+
end
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
format('<Kanrisuru::Remote::Fstab::Options:0x%<object_id>s @opts=%<opts>s @type=%<type>s>',
|
24
|
+
object_id: object_id, opts: @opts, type: @type)
|
25
|
+
end
|
26
|
+
|
27
|
+
def [](option)
|
28
|
+
@opts[option]
|
29
|
+
end
|
30
|
+
|
31
|
+
def []=(option, value)
|
32
|
+
option = option.to_s
|
33
|
+
|
34
|
+
unless Kanrisuru::Remote::Fstab::Options.option_exists?(option, @type)
|
35
|
+
raise ArgumentError,
|
36
|
+
"Invalid option: #{option} for #{@type} file system."
|
37
|
+
end
|
38
|
+
|
39
|
+
unless Kanrisuru::Remote::Fstab::Options.valid_option?(option, value, @type)
|
40
|
+
raise ArgumentError,
|
41
|
+
"Invalid option value: #{value} for #{option} on #{@type} file system."
|
42
|
+
end
|
43
|
+
|
44
|
+
@opts[option] = value
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_s
|
48
|
+
string = ''
|
49
|
+
opts_length = @opts.length
|
50
|
+
|
51
|
+
@opts.each_with_index do |(key, value), index|
|
52
|
+
append_comma = true
|
53
|
+
|
54
|
+
if value == true
|
55
|
+
string += key.to_s
|
56
|
+
elsif value.instance_of?(String) || value.instance_of?(Integer) || value.instance_of?(Float)
|
57
|
+
string += "#{key}=#{value}"
|
58
|
+
else
|
59
|
+
append_comma = false
|
60
|
+
end
|
61
|
+
|
62
|
+
string += ',' if append_comma && index < opts_length - 1
|
63
|
+
end
|
64
|
+
|
65
|
+
string
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_h
|
69
|
+
@opts
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.option_exists?(value, type = nil)
|
73
|
+
value = value.to_sym
|
74
|
+
type = type ? type.to_sym : nil
|
75
|
+
|
76
|
+
common = Kanrisuru::Util::FsMountOpts[:common]
|
77
|
+
fs_opts = Kanrisuru::Util::FsMountOpts[type]
|
78
|
+
|
79
|
+
common.key?(value) ||
|
80
|
+
fs_opts&.key?(value)
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.valid_option?(value, field, type = nil)
|
84
|
+
value = value.to_sym
|
85
|
+
type = type ? type.to_sym : nil
|
86
|
+
|
87
|
+
common = Kanrisuru::Util::FsMountOpts[:common]
|
88
|
+
fs_opts = Kanrisuru::Util::FsMountOpts[type]
|
89
|
+
|
90
|
+
if common.key?(value)
|
91
|
+
case common[value]
|
92
|
+
when 'boolean'
|
93
|
+
[true, false].include?(field)
|
94
|
+
when 'value'
|
95
|
+
field.instance_of?(String) || field.instance_of?(Float) || field.instance_of?(Integer)
|
96
|
+
else
|
97
|
+
false
|
98
|
+
end
|
99
|
+
elsif fs_opts&.key?(value)
|
100
|
+
case fs_opts[value]
|
101
|
+
when 'boolean'
|
102
|
+
[true, false].include?(field)
|
103
|
+
when 'value'
|
104
|
+
field.instance_of?(String) || field.instance_of?(Float) || field.instance_of?(Integer)
|
105
|
+
else
|
106
|
+
false
|
107
|
+
end
|
108
|
+
else
|
109
|
+
raise ArgumentError, 'Invalid option'
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def validate_opts!
|
116
|
+
@opts.each do |key, value|
|
117
|
+
unless Kanrisuru::Remote::Fstab::Options.valid_option?(key, value, @type)
|
118
|
+
raise ArgumentError, "Invalid option: #{key} for #{@type}"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
@valid = true
|
123
|
+
end
|
124
|
+
|
125
|
+
def parse_opts(string)
|
126
|
+
opts = {}
|
127
|
+
|
128
|
+
options = string.split(',')
|
129
|
+
options.each do |option|
|
130
|
+
if option.include?('=')
|
131
|
+
opt, value = option.split('=')
|
132
|
+
opts[opt] = value
|
133
|
+
else
|
134
|
+
opts[option] = true
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
opts
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'fstab/entry'
|
4
|
+
require_relative 'fstab/options'
|
5
|
+
|
3
6
|
module Kanrisuru
|
4
7
|
module Remote
|
5
8
|
class Fstab
|
@@ -18,6 +21,12 @@ module Kanrisuru
|
|
18
21
|
get_entry(device)
|
19
22
|
end
|
20
23
|
|
24
|
+
def delete(device)
|
25
|
+
return false unless @entries.key?(device)
|
26
|
+
|
27
|
+
@entries.delete(device)
|
28
|
+
end
|
29
|
+
|
21
30
|
def get_entry(device)
|
22
31
|
result = @entries[device]
|
23
32
|
|
@@ -133,289 +142,6 @@ module Kanrisuru
|
|
133
142
|
}
|
134
143
|
end
|
135
144
|
end
|
136
|
-
|
137
|
-
class Entry
|
138
|
-
attr_reader :device, :uuid, :invalid, :label, :type, :opts, :freq, :passno
|
139
|
-
attr_accessor :mount_point
|
140
|
-
|
141
|
-
def initialize(opts = {})
|
142
|
-
@host = opts[:host]
|
143
|
-
@line = opts[:line]
|
144
|
-
|
145
|
-
@default = nil
|
146
|
-
|
147
|
-
@device = opts[:device] || nil
|
148
|
-
@opts = opts[:opts] || nil
|
149
|
-
@label = opts[:label] || nil
|
150
|
-
@uuid = opts[:uuid] || nil
|
151
|
-
@mount_point = opts[:mount_point] || nil
|
152
|
-
@type = opts[:type] || nil
|
153
|
-
@freq = opts[:freq] || nil
|
154
|
-
@passno = opts[:passno] || nil
|
155
|
-
|
156
|
-
@changed = false
|
157
|
-
|
158
|
-
@ucount = 0
|
159
|
-
@special = false
|
160
|
-
@invalid = false
|
161
|
-
|
162
|
-
if Kanrisuru::Util.present?(@line) && @line.instance_of?(String)
|
163
|
-
parse_line!
|
164
|
-
elsif (Kanrisuru::Util.present?(@opts) && @opts.instance_of?(String)) || @opts.instance_of?(Hash)
|
165
|
-
@opts = Kanrisuru::Remote::Fstab::Options.new(@type, @opts)
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
def inspect
|
170
|
-
str = '#<Kanrisuru::Remote::Fstab::Entry:0x%<object_id>s ' \
|
171
|
-
'@line=%<line>s @device=%<device>s @label=%<label>s' \
|
172
|
-
'@uuid=%<uuid>s @freq=%<freq>s @pasno=%<passno>s' \
|
173
|
-
'@opts=%<opts>s}>'
|
174
|
-
|
175
|
-
format(
|
176
|
-
str,
|
177
|
-
object_id: object_id,
|
178
|
-
line: @line,
|
179
|
-
device: @device,
|
180
|
-
label: @label,
|
181
|
-
uuid: @uuid,
|
182
|
-
freq: @freq,
|
183
|
-
passno: @passno,
|
184
|
-
opts: @opts.inspect
|
185
|
-
)
|
186
|
-
end
|
187
|
-
|
188
|
-
def valid?
|
189
|
-
!@invalid
|
190
|
-
end
|
191
|
-
|
192
|
-
def to_s(override = nil)
|
193
|
-
mode = override || @default
|
194
|
-
|
195
|
-
case mode
|
196
|
-
when 'uuid'
|
197
|
-
"UUID=#{@uuid} #{@mount_point} #{@type} #{@opts} #{@freq} #{@passno}"
|
198
|
-
when 'label'
|
199
|
-
"LABEL=#{@label} #{@mount_point} #{@type} #{@opts} #{@freq} #{@passno}"
|
200
|
-
else
|
201
|
-
"#{@device} #{@mount_point} #{@type} #{@opts} #{@freq} #{@passno}"
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
private
|
206
|
-
|
207
|
-
def parse_line!
|
208
|
-
fsline, mp, @type, opts, freq, passno = @line.split
|
209
|
-
|
210
|
-
@mount_point = mp
|
211
|
-
@freq = freq || '0'
|
212
|
-
@passno = passno || '0'
|
213
|
-
|
214
|
-
@opts = Fstab::Options.new(@type, opts)
|
215
|
-
|
216
|
-
case @line
|
217
|
-
when /^\s*LABEL=/
|
218
|
-
@default = 'label'
|
219
|
-
parse_label(fsline)
|
220
|
-
when /^\s*UUID=/
|
221
|
-
@default = 'uuid'
|
222
|
-
parse_uuid(fsline)
|
223
|
-
when %r{^\s*/dev}
|
224
|
-
@default = 'dev'
|
225
|
-
parse_dev(fsline)
|
226
|
-
else
|
227
|
-
# TODO: somewhat risky to assume that everything else
|
228
|
-
# can be considered a special device, but validating this
|
229
|
-
# is really tricky.
|
230
|
-
@special = true
|
231
|
-
@device = fsline
|
232
|
-
end
|
233
|
-
|
234
|
-
# Fstab entries not matching real devices have device unknown
|
235
|
-
@invalid = (@line.split.count != 6) # invalid entry if < 6 columns
|
236
|
-
|
237
|
-
if (@uuid.nil? && @label.nil? && !@special) ||
|
238
|
-
@device =~ /^unknown_/ ||
|
239
|
-
(!@host.inode?(@device) && !@special)
|
240
|
-
@invalid = true
|
241
|
-
@ucount += 1
|
242
|
-
end
|
243
|
-
|
244
|
-
@invalid = true unless @freq =~ /0|1|2/ && @passno =~ /0|1|2/
|
245
|
-
end
|
246
|
-
|
247
|
-
def parse_label(fsline)
|
248
|
-
@label = fsline.split('=').last.strip.chomp
|
249
|
-
path = @host.realpath("/dev/disk/by-label/#{@label}").path
|
250
|
-
|
251
|
-
@device = begin
|
252
|
-
"/dev/#{path.split('/').last}"
|
253
|
-
rescue StandardError
|
254
|
-
"unknown_#{@ucount}"
|
255
|
-
end
|
256
|
-
|
257
|
-
result = @host.blkid(device: @device)
|
258
|
-
@uuid = result.success? ? result[0].uuid : nil
|
259
|
-
end
|
260
|
-
|
261
|
-
def parse_uuid(fsline)
|
262
|
-
@uuid = fsline.split('=').last.strip.chomp
|
263
|
-
path = @host.realpath("/dev/disk/by-uuid/#{uuid}").path
|
264
|
-
|
265
|
-
@device = begin
|
266
|
-
"/dev/#{path.split('/').last}"
|
267
|
-
rescue StandardError
|
268
|
-
"unknown_#{@ucount}"
|
269
|
-
end
|
270
|
-
|
271
|
-
result = @host.blkid(device: @device)
|
272
|
-
@label = result.success? ? result[0].label : nil
|
273
|
-
end
|
274
|
-
|
275
|
-
def parse_dev(fsline)
|
276
|
-
@device = fsline
|
277
|
-
result = @host.blkid(device: @device)
|
278
|
-
|
279
|
-
@label = result.success? ? result[0].label : nil
|
280
|
-
@uuid = result.success? ? result[0].uuid : nil
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
284
|
-
class Options
|
285
|
-
def initialize(type, opts)
|
286
|
-
@type = type
|
287
|
-
@valid = false
|
288
|
-
|
289
|
-
if opts.instance_of?(String)
|
290
|
-
@opts = parse_opts(opts)
|
291
|
-
elsif opts.instance_of?(Hash)
|
292
|
-
@opts = opts.transform_keys(&:to_s)
|
293
|
-
else
|
294
|
-
raise ArgumentError, 'Invalid option type'
|
295
|
-
end
|
296
|
-
|
297
|
-
validate_opts!
|
298
|
-
end
|
299
|
-
|
300
|
-
def inspect
|
301
|
-
format('<Kanrisuru::Remote::Fstab::Options:0x%<object_id>s @opts=%<opts>s @type=%<type>s>',
|
302
|
-
object_id: object_id, opts: @opts, type: @type)
|
303
|
-
end
|
304
|
-
|
305
|
-
def [](option)
|
306
|
-
@opts[option]
|
307
|
-
end
|
308
|
-
|
309
|
-
def []=(option, value)
|
310
|
-
option = option.to_s
|
311
|
-
|
312
|
-
unless Kanrisuru::Remote::Fstab::Options.option_exists?(option, @type)
|
313
|
-
raise ArgumentError,
|
314
|
-
"Invalid option: #{option} for #{@type} file system."
|
315
|
-
end
|
316
|
-
|
317
|
-
unless Kanrisuru::Remote::Fstab::Options.valid_option?(option, value, @type)
|
318
|
-
raise ArgumentError,
|
319
|
-
"Invalid option value: #{value} for #{option} on #{@type} file system."
|
320
|
-
end
|
321
|
-
|
322
|
-
@opts[option] = value
|
323
|
-
end
|
324
|
-
|
325
|
-
def to_s
|
326
|
-
string = ''
|
327
|
-
opts_length = @opts.length
|
328
|
-
|
329
|
-
@opts.each_with_index do |(key, value), index|
|
330
|
-
append_comma = true
|
331
|
-
|
332
|
-
if value == true
|
333
|
-
string += key.to_s
|
334
|
-
elsif value.instance_of?(String) || value.instance_of?(Integer) || value.instance_of?(Float)
|
335
|
-
string += "#{key}=#{value}"
|
336
|
-
else
|
337
|
-
append_comma = false
|
338
|
-
end
|
339
|
-
|
340
|
-
string += ',' if append_comma && index < opts_length - 1
|
341
|
-
end
|
342
|
-
|
343
|
-
string
|
344
|
-
end
|
345
|
-
|
346
|
-
def to_h
|
347
|
-
@opts
|
348
|
-
end
|
349
|
-
|
350
|
-
def self.option_exists?(value, type = nil)
|
351
|
-
value = value.to_sym
|
352
|
-
type = type ? type.to_sym : nil
|
353
|
-
|
354
|
-
common = Kanrisuru::Util::FsMountOpts[:common]
|
355
|
-
fs_opts = Kanrisuru::Util::FsMountOpts[type]
|
356
|
-
|
357
|
-
common.key?(value) ||
|
358
|
-
fs_opts&.key?(value)
|
359
|
-
end
|
360
|
-
|
361
|
-
def self.valid_option?(value, field, type = nil)
|
362
|
-
value = value.to_sym
|
363
|
-
type = type ? type.to_sym : nil
|
364
|
-
|
365
|
-
common = Kanrisuru::Util::FsMountOpts[:common]
|
366
|
-
fs_opts = Kanrisuru::Util::FsMountOpts[type]
|
367
|
-
|
368
|
-
if common.key?(value)
|
369
|
-
case common[value]
|
370
|
-
when 'boolean'
|
371
|
-
[true, false].include?(field)
|
372
|
-
when 'value'
|
373
|
-
field.instance_of?(String) || field.instance_of?(Float) || field.instance_of?(Integer)
|
374
|
-
else
|
375
|
-
false
|
376
|
-
end
|
377
|
-
elsif fs_opts&.key?(value)
|
378
|
-
case fs_opts[value]
|
379
|
-
when 'boolean'
|
380
|
-
[true, false].include?(field)
|
381
|
-
when 'value'
|
382
|
-
field.instance_of?(String) || field.instance_of?(Float) || field.instance_of?(Integer)
|
383
|
-
else
|
384
|
-
false
|
385
|
-
end
|
386
|
-
else
|
387
|
-
raise ArgumentError, 'Invalid option'
|
388
|
-
end
|
389
|
-
end
|
390
|
-
|
391
|
-
private
|
392
|
-
|
393
|
-
def validate_opts!
|
394
|
-
@opts.each do |key, value|
|
395
|
-
unless Kanrisuru::Remote::Fstab::Options.valid_option?(key, value, @type)
|
396
|
-
raise ArgumentError, "Invalid option: #{key} for #{@type}"
|
397
|
-
end
|
398
|
-
end
|
399
|
-
|
400
|
-
@valid = true
|
401
|
-
end
|
402
|
-
|
403
|
-
def parse_opts(string)
|
404
|
-
opts = {}
|
405
|
-
|
406
|
-
options = string.split(',')
|
407
|
-
options.each do |option|
|
408
|
-
if option.include?('=')
|
409
|
-
opt, value = option.split('=')
|
410
|
-
opts[opt] = value
|
411
|
-
else
|
412
|
-
opts[option] = true
|
413
|
-
end
|
414
|
-
end
|
415
|
-
|
416
|
-
opts
|
417
|
-
end
|
418
|
-
end
|
419
145
|
end
|
420
146
|
end
|
421
147
|
end
|
data/lib/kanrisuru/version.rb
CHANGED
Binary file
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Kanrisuru::Remote::Cluster do
|
6
|
+
before(:all) do
|
7
|
+
StubNetwork.stub!
|
8
|
+
end
|
9
|
+
|
10
|
+
after(:all) do
|
11
|
+
StubNetwork.unstub!
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:host) do
|
15
|
+
Kanrisuru::Remote::Host.new(
|
16
|
+
host: 'localhost',
|
17
|
+
username: 'ubuntu',
|
18
|
+
keys: ['id_rsa']
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kanrisuru
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.16.
|
4
|
+
version: 0.16.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Mammina
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-12-
|
11
|
+
date: 2021-12-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parallel_tests
|
@@ -149,8 +149,6 @@ files:
|
|
149
149
|
- ".gitignore"
|
150
150
|
- ".rspec"
|
151
151
|
- ".rubocop.yml"
|
152
|
-
- ".rubocop_todo.yml"
|
153
|
-
- ".travis.yml"
|
154
152
|
- CHANGELOG.md
|
155
153
|
- CODE_OF_CONDUCT.md
|
156
154
|
- Gemfile
|
@@ -417,6 +415,7 @@ files:
|
|
417
415
|
- lib/kanrisuru/core/zypper/types.rb
|
418
416
|
- lib/kanrisuru/logger.rb
|
419
417
|
- lib/kanrisuru/mode.rb
|
418
|
+
- lib/kanrisuru/mode/permission.rb
|
420
419
|
- lib/kanrisuru/os_package.rb
|
421
420
|
- lib/kanrisuru/os_package/collection.rb
|
422
421
|
- lib/kanrisuru/os_package/define.rb
|
@@ -427,6 +426,8 @@ files:
|
|
427
426
|
- lib/kanrisuru/remote/env.rb
|
428
427
|
- lib/kanrisuru/remote/file.rb
|
429
428
|
- lib/kanrisuru/remote/fstab.rb
|
429
|
+
- lib/kanrisuru/remote/fstab/entry.rb
|
430
|
+
- lib/kanrisuru/remote/fstab/options.rb
|
430
431
|
- lib/kanrisuru/remote/host.rb
|
431
432
|
- lib/kanrisuru/remote/memory.rb
|
432
433
|
- lib/kanrisuru/remote/os.rb
|
@@ -439,6 +440,7 @@ files:
|
|
439
440
|
- lib/kanrisuru/util/os_family.rb
|
440
441
|
- lib/kanrisuru/util/signal.rb
|
441
442
|
- lib/kanrisuru/version.rb
|
443
|
+
- logo/kanrisuru-logo.png
|
442
444
|
- spec/functional/core/apt_spec.rb
|
443
445
|
- spec/functional/core/archive_spec.rb
|
444
446
|
- spec/functional/core/disk_spec.rb
|
@@ -467,6 +469,7 @@ files:
|
|
467
469
|
- spec/functional/remote/cluster_spec.rb
|
468
470
|
- spec/functional/remote/cpu_spec.rb
|
469
471
|
- spec/functional/remote/env_spec.rb
|
472
|
+
- spec/functional/remote/fstab_spec.rb
|
470
473
|
- spec/functional/result_spec.rb
|
471
474
|
- spec/helper/expect_helpers.rb
|
472
475
|
- spec/helper/hosts.json
|
data/.rubocop_todo.yml
DELETED
File without changes
|