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