cfa_grub2 0.1.0
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 +7 -0
- data/lib/cfa/grub2/default.rb +230 -0
- data/lib/cfa/grub2/device_map.rb +67 -0
- data/lib/cfa/grub2/grub_cfg.rb +39 -0
- data/lib/cfa/grub2/install_device.rb +94 -0
- metadata +63 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 44d755734cf3e0bb54735aafb2eebe4ba46437eb
|
4
|
+
data.tar.gz: 875e4f91ca2d0b12f755fc2186ae7c4e007f9099
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3f9ddf0fe7a58edaa0a5f60a6a39a2bbadeed15f260a131d3f4d77754503cbf21248c2c96f3084fc20ac8e4126e5413f34a5d3ada6e6b6e72ca22a0fd293b367
|
7
|
+
data.tar.gz: 5e6bd382abf70b158c6b0b2ddcddd0f1d88273669cf7dbb7f0eb8aa4ef428197cfff816d76ac1d4dcc6ddb75f8f0a0dd70793fcc0f96efd202709c1890b659a7
|
@@ -0,0 +1,230 @@
|
|
1
|
+
require "cfa/base_model"
|
2
|
+
require "cfa/augeas_parser"
|
3
|
+
require "cfa/placer"
|
4
|
+
require "cfa/matcher"
|
5
|
+
|
6
|
+
module CFA
|
7
|
+
module Grub2
|
8
|
+
# Represents grub configuration in /etc/default/grub
|
9
|
+
# Main features:
|
10
|
+
#
|
11
|
+
# - Do not overwrite files
|
12
|
+
# - When setting value first try to just change value if key already exists
|
13
|
+
# - When key is not set, then try to find commented out line with key and
|
14
|
+
# replace it with real config
|
15
|
+
# - When even commented out code is not there, then append configuration
|
16
|
+
# to the end of file
|
17
|
+
class Default < BaseModel
|
18
|
+
attributes(
|
19
|
+
timeout: "GRUB_TIMEOUT",
|
20
|
+
distributor: "GRUB_DISTRIBUTOR",
|
21
|
+
gfxmode: "GRUB_GFXMODE",
|
22
|
+
theme: "GRUB_THEME"
|
23
|
+
)
|
24
|
+
|
25
|
+
PARSER = AugeasParser.new("sysconfig.lns")
|
26
|
+
PATH = "/etc/default/grub"
|
27
|
+
|
28
|
+
def initialize(file_handler: File)
|
29
|
+
super(PARSER, PATH, file_handler: file_handler)
|
30
|
+
end
|
31
|
+
|
32
|
+
def save(changes_only: false)
|
33
|
+
# serialize kernel params object before save
|
34
|
+
kernels = [@kernel_params, @xen_hypervisor_params, @xen_kernel_params,
|
35
|
+
@recovery_params]
|
36
|
+
kernels.each do |params|
|
37
|
+
# FIXME: this empty prevent writing explicit empty kernel params.
|
38
|
+
generic_set(params.key, params.serialize) if params && !params.empty?
|
39
|
+
end
|
40
|
+
|
41
|
+
super
|
42
|
+
end
|
43
|
+
|
44
|
+
def load
|
45
|
+
super
|
46
|
+
|
47
|
+
kernels = [kernel_params, xen_hypervisor_params, xen_kernel_params,
|
48
|
+
recovery_params]
|
49
|
+
kernels.each do |kernel|
|
50
|
+
param_line = data[kernel.key]
|
51
|
+
kernel.replace(param_line) if param_line
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def os_prober
|
56
|
+
@os_prober ||= BooleanValue.new(
|
57
|
+
"GRUB_DISABLE_OS_PROBER", self,
|
58
|
+
# grub key is disable, so use reverse logic
|
59
|
+
true_value: "false", false_value: "true"
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
def kernel_params
|
64
|
+
@kernel_params ||= KernelParams.new(
|
65
|
+
data["GRUB_CMDLINE_LINUX_DEFAULT"], "GRUB_CMDLINE_LINUX_DEFAULT"
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
def xen_hypervisor_params
|
70
|
+
@xen_hypervisor_params ||= KernelParams.new(
|
71
|
+
data["GRUB_CMDLINE_LINUX_XEN_REPLACE_DEFAULT"],
|
72
|
+
"GRUB_CMDLINE_LINUX_XEN_REPLACE_DEFAULT"
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
def xen_kernel_params
|
77
|
+
@xen_kernel_params ||= KernelParams.new(
|
78
|
+
data["GRUB_CMDLINE_LINUX_XEN"], "GRUB_CMDLINE_LINUX_XEN"
|
79
|
+
)
|
80
|
+
end
|
81
|
+
|
82
|
+
def recovery_params
|
83
|
+
@recovery_params ||= KernelParams.new(
|
84
|
+
data["GRUB_CMDLINE_LINUX_RECOVERY"], "GRUB_CMDLINE_LINUX_RECOVERY"
|
85
|
+
)
|
86
|
+
end
|
87
|
+
|
88
|
+
def recovery_entry
|
89
|
+
@recovery ||= BooleanValue.new(
|
90
|
+
"GRUB_DISABLE_RECOVERY", self,
|
91
|
+
# grub key is disable, so use reverse logic
|
92
|
+
true_value: "false", false_value: "true"
|
93
|
+
)
|
94
|
+
end
|
95
|
+
|
96
|
+
def cryptodisk
|
97
|
+
@cryptodisk ||= BooleanValue.new("GRUB_ENABLE_CRYPTODISK", self)
|
98
|
+
end
|
99
|
+
|
100
|
+
def terminal
|
101
|
+
case data["GRUB_TERMINAL"]
|
102
|
+
when "", nil then nil
|
103
|
+
when "console" then :console
|
104
|
+
when "serial" then :serial
|
105
|
+
when "gfxterm" then :gfxterm
|
106
|
+
else
|
107
|
+
raise "unknown GRUB_TERMINAL option #{data["GRUB_TERMINAL"].inspect}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
VALID_TERMINAL_OPTIONS = [:serial, :console, :gfxterm]
|
112
|
+
def terminal=(value)
|
113
|
+
if !VALID_TERMINAL_OPTIONS.include?(value)
|
114
|
+
raise ArgumentError, "invalid value #{value.inspect}"
|
115
|
+
end
|
116
|
+
|
117
|
+
generic_set("GRUB_TERMINAL", value.to_s)
|
118
|
+
end
|
119
|
+
|
120
|
+
def serial_console=(value)
|
121
|
+
self.terminal = :serial
|
122
|
+
generic_set("GRUB_SERIAL_COMMAND", value)
|
123
|
+
end
|
124
|
+
|
125
|
+
def serial_console
|
126
|
+
data["GRUB_SERIAL_COMMAND"]
|
127
|
+
end
|
128
|
+
|
129
|
+
# Represents kernel append line with helpers to easier modification.
|
130
|
+
# TODO: handle quoting, maybe have own lense to parse/serialize kernel
|
131
|
+
# params?
|
132
|
+
class KernelParams
|
133
|
+
attr_reader :key
|
134
|
+
|
135
|
+
def initialize(line, key)
|
136
|
+
@tree = ParamTree.new(line)
|
137
|
+
@key = key
|
138
|
+
end
|
139
|
+
|
140
|
+
def serialize
|
141
|
+
@tree.to_string
|
142
|
+
end
|
143
|
+
|
144
|
+
# replaces kernel params with passed line
|
145
|
+
def replace(line)
|
146
|
+
@tree = ParamTree.new(line)
|
147
|
+
end
|
148
|
+
|
149
|
+
# checks if there is any parameter
|
150
|
+
def empty?
|
151
|
+
serialize.empty?
|
152
|
+
end
|
153
|
+
|
154
|
+
# gets value for parameters.
|
155
|
+
# @return possible values are `false` when parameter missing,
|
156
|
+
# `true` when parameter without value placed, string if single
|
157
|
+
# instance with value is there and array if multiple instance with
|
158
|
+
# values are there.
|
159
|
+
#
|
160
|
+
# @example different values
|
161
|
+
# line = "quite console=S0 console=S1 vga=0x400"
|
162
|
+
# params = KernelParams.new(line)
|
163
|
+
# params.parameter("quite") # => true
|
164
|
+
# params.parameter("verbose") # => false
|
165
|
+
# params.parameter("vga") # => "0x400"
|
166
|
+
# params.parameter("console") # => ["S0", "S1"]
|
167
|
+
#
|
168
|
+
def parameter(key)
|
169
|
+
values = @tree.data
|
170
|
+
.select { |e| e[:key] == key }
|
171
|
+
.map { |e| e[:value] }
|
172
|
+
|
173
|
+
return false if values.empty?
|
174
|
+
return values if values.size > 1
|
175
|
+
return true if values.first == true
|
176
|
+
|
177
|
+
values.first
|
178
|
+
end
|
179
|
+
|
180
|
+
# Adds new parameter to kernel command line. Uses augeas placers.
|
181
|
+
# To replace value use {ReplacePlacer}
|
182
|
+
def add_parameter(key, value, placer = AppendPlacer.new)
|
183
|
+
element = placer.new_element(@tree)
|
184
|
+
|
185
|
+
element[:key] = key
|
186
|
+
element[:value] = value
|
187
|
+
end
|
188
|
+
|
189
|
+
# Removes parameter from kernel command line.
|
190
|
+
# @param matcher [Matcher] to find entry to remove
|
191
|
+
def remove_parameter(matcher)
|
192
|
+
@tree.data.reject!(&matcher)
|
193
|
+
end
|
194
|
+
|
195
|
+
# Represents parsed kernel parameters tree. Parses in initialization
|
196
|
+
# and backserilized by `to_string`.
|
197
|
+
# TODO: replace it via augeas parser when someone write lense
|
198
|
+
class ParamTree
|
199
|
+
attr_reader :data
|
200
|
+
|
201
|
+
def initialize(line)
|
202
|
+
line ||= ""
|
203
|
+
pairs = line.split(/\s/)
|
204
|
+
.reject(&:empty?)
|
205
|
+
.map { |e| e.split("=", 2) }
|
206
|
+
|
207
|
+
@data = pairs.map do |k, v|
|
208
|
+
{
|
209
|
+
key: k,
|
210
|
+
value: v || true, # kernel param without value have true
|
211
|
+
}
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def to_string
|
216
|
+
snippets = @data.map do |e|
|
217
|
+
if e[:value] == true
|
218
|
+
e[:key]
|
219
|
+
else
|
220
|
+
"#{e[:key]}=#{e[:value]}"
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
snippets.join(" ")
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "cfa/base_model"
|
2
|
+
require "cfa/augeas_parser"
|
3
|
+
require "cfa/placer"
|
4
|
+
require "cfa/matcher"
|
5
|
+
|
6
|
+
module CFA
|
7
|
+
module Grub2
|
8
|
+
# Represents grub device map in /etc/grub2/device_map
|
9
|
+
# for details see https://www.gnu.org/software/grub/manual/html_node/Device-map.html
|
10
|
+
# Main features:
|
11
|
+
#
|
12
|
+
# - Do not overwrite files
|
13
|
+
# - When setting value first try to just change value if key already exists
|
14
|
+
# - When grub key is not there, then add to file
|
15
|
+
# - checks and raise exception if number of mappings exceed limit 8.
|
16
|
+
# Limitation is caused by BIOS Int 13 used by grub2 for selecting boot
|
17
|
+
# device.
|
18
|
+
class DeviceMap < BaseModel
|
19
|
+
PARSER = AugeasParser.new("device_map.lns")
|
20
|
+
PATH = "/etc/grub2/device.map"
|
21
|
+
|
22
|
+
def initialize(file_handler: File)
|
23
|
+
super(PARSER, PATH, file_handler: file_handler)
|
24
|
+
end
|
25
|
+
|
26
|
+
def save(changes_only: false)
|
27
|
+
raise "Too much grub devices. Limit is 8." if grub_devices.size > 8
|
28
|
+
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [String] grub device name for given system device
|
33
|
+
def grub_device_for(system_dev)
|
34
|
+
matcher = Matcher.new(value_matcher: system_dev)
|
35
|
+
entry = data.select(matcher)
|
36
|
+
|
37
|
+
entry.empty? ? nil : entry.first[:key]
|
38
|
+
end
|
39
|
+
|
40
|
+
# @return [String] system device name for given grub device
|
41
|
+
def system_device_for(grub_device)
|
42
|
+
data[grub_device]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Appends to configuration mapping between grub_device and system_device
|
46
|
+
# @note if mapping for given grub device is already defined, it will be
|
47
|
+
# overwritten
|
48
|
+
def add_mapping(grub_device, system_device)
|
49
|
+
generic_set(grub_device, system_device)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Removes mapping for given grub device
|
53
|
+
def remove_mapping(grub_device)
|
54
|
+
data.delete(grub_device)
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return [Array<String>] list of all grub devices which have mapping.
|
58
|
+
# If there is no mapping, then it return empty list.
|
59
|
+
def grub_devices
|
60
|
+
matcher = Matcher.new { |k, _v| k !~ /comment/ }
|
61
|
+
entries = data.select(matcher)
|
62
|
+
|
63
|
+
entries.map { |e| e[:key] }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "cfa/base_model"
|
2
|
+
|
3
|
+
module CFA
|
4
|
+
module Grub2
|
5
|
+
# Represents generated grub configuration at /boot/grub2/grub.cfg
|
6
|
+
# Main features:
|
7
|
+
#
|
8
|
+
# - List of generated sections including translations
|
9
|
+
class GrubCfg < BaseModel
|
10
|
+
PATH = "/boot/grub2/grub.cfg"
|
11
|
+
|
12
|
+
# @private only internal parser
|
13
|
+
class Parser
|
14
|
+
def self.parse(string)
|
15
|
+
menu_lines = string.lines.grep(/menuentry\s*'/)
|
16
|
+
menu_lines.map { |line| line[/\s*menuentry\s*'([^']+)'.*/, 1] }
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.serialize(_string)
|
20
|
+
raise NotImplementedError,
|
21
|
+
"Serializing not implemented, use grub2 generator"
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.empty
|
25
|
+
[]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(file_handler: File)
|
30
|
+
super(Parser, PATH, file_handler: file_handler)
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return [Array<String>] sections from grub.cfg in order as they appear
|
34
|
+
def sections
|
35
|
+
data
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require "cfa/base_model"
|
2
|
+
|
3
|
+
module CFA
|
4
|
+
module Grub2
|
5
|
+
# specific parser for install devices.
|
6
|
+
# File format is easy element per line without comments.
|
7
|
+
# for better readability special values generic_mbr and activate is at
|
8
|
+
# the end of file
|
9
|
+
module InstallDeviceParser
|
10
|
+
# returns list of non-empty lines
|
11
|
+
def self.parse(string)
|
12
|
+
string.lines.map(&:strip).delete_if(&:empty?)
|
13
|
+
end
|
14
|
+
|
15
|
+
# gets list of devices and create file content from it
|
16
|
+
def self.serialize(data)
|
17
|
+
activate = data.delete("activate")
|
18
|
+
generic_mbr = data.delete("generic_mbr")
|
19
|
+
|
20
|
+
res = data.join("\n")
|
21
|
+
res << "\n" unless res.empty?
|
22
|
+
|
23
|
+
res << "activate\n" if activate
|
24
|
+
res << "generic_mbr\n" if generic_mbr
|
25
|
+
|
26
|
+
res
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.empty
|
30
|
+
[]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Model representing configuration in file /etc/default/grub_installdevice
|
35
|
+
class InstallDevice < BaseModel
|
36
|
+
PATH = "/etc/default/grub_installdevice"
|
37
|
+
|
38
|
+
def initialize(file_handler: File)
|
39
|
+
super(InstallDeviceParser, PATH, file_handler: file_handler)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Adds new install device. Does nothing if it is already there.
|
43
|
+
def add_device(dev)
|
44
|
+
data << dev unless data.include?(dev)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Removes install device. Does nothing if already not there.
|
48
|
+
def remove_device(dev)
|
49
|
+
data.delete(dev)
|
50
|
+
end
|
51
|
+
|
52
|
+
# @return [Array<String>] non-special devices from configuration
|
53
|
+
def devices
|
54
|
+
res = data.dup
|
55
|
+
res.delete("generic_mbr")
|
56
|
+
res.delete("activate")
|
57
|
+
|
58
|
+
res
|
59
|
+
end
|
60
|
+
|
61
|
+
# ask if special entry for generic_mbr is there
|
62
|
+
def generic_mbr?
|
63
|
+
data.include?("generic_mbr")
|
64
|
+
end
|
65
|
+
|
66
|
+
# sets special entry generic_mbr
|
67
|
+
def generic_mbr=(enabled)
|
68
|
+
if enabled
|
69
|
+
return if generic_mbr?
|
70
|
+
|
71
|
+
data << "generic_mbr"
|
72
|
+
else
|
73
|
+
data.delete("generic_mbr")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Ask if special entry for activate is there
|
78
|
+
def activate?
|
79
|
+
data.include?("activate")
|
80
|
+
end
|
81
|
+
|
82
|
+
# sets special entry activate
|
83
|
+
def activate=(enabled)
|
84
|
+
if enabled
|
85
|
+
return if activate?
|
86
|
+
|
87
|
+
data << "activate"
|
88
|
+
else
|
89
|
+
data.delete("activate")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cfa_grub2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Josef Reidinger
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-12-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: cfa ~> 0.2
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: Models allowing easy read and modification of GRUB2 configuration files.
|
28
|
+
It is a plugin for cfa framework.
|
29
|
+
email:
|
30
|
+
- jreidinger@suse.cz
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- lib/cfa/grub2/default.rb
|
36
|
+
- lib/cfa/grub2/device_map.rb
|
37
|
+
- lib/cfa/grub2/grub_cfg.rb
|
38
|
+
- lib/cfa/grub2/install_device.rb
|
39
|
+
homepage: http://github.com/config-files-api/config_files_api_grub2
|
40
|
+
licenses: []
|
41
|
+
metadata: {}
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 1.3.6
|
56
|
+
requirements: []
|
57
|
+
rubyforge_project:
|
58
|
+
rubygems_version: 2.2.2
|
59
|
+
signing_key:
|
60
|
+
specification_version: 4
|
61
|
+
summary: Models for GRUB2 configuration files.
|
62
|
+
test_files: []
|
63
|
+
has_rdoc:
|