github.com/bugraaydogar/snapd@v0.0.0-20210315170335-8c70bb858939/overlord/configstate/configcore/handlers.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package configcore 21 22 import ( 23 "fmt" 24 25 "github.com/snapcore/snapd/overlord/configstate/config" 26 "github.com/snapcore/snapd/sysconfig" 27 ) 28 29 type configHandler interface { 30 validate(config.ConfGetter) error 31 handle(config.ConfGetter, *fsOnlyContext) error 32 needsState() bool 33 flags() flags 34 } 35 36 // flags carries extra flags that influence how the handler is called. 37 type flags struct { 38 // coreOnlyConfig tells Run/FilesystemOnlyApply to apply the config on core 39 // systems only. 40 coreOnlyConfig bool 41 // validatedOnlyStateConfig tells that the config requires only validation, 42 // its options are applied dynamically elsewhere. 43 validatedOnlyStateConfig bool 44 // earlyConfigFilter expresses whether the handler supports 45 // any early configuration options (that can and must be 46 // set before even seeding is finished). 47 // If set the function should copy such options from values 48 // to early. 49 earlyConfigFilter func(values, early map[string]interface{}) 50 } 51 52 type fsOnlyHandler struct { 53 validateFunc func(config.ConfGetter) error 54 handleFunc func(config.ConfGetter, *fsOnlyContext) error 55 configFlags flags 56 } 57 58 var handlers []configHandler 59 60 func init() { 61 // Most of these handlers are no-op on classic. 62 // TODO: consider allowing some of these on classic too? 63 // consider erroring on core-only options on classic? 64 65 coreOnly := &flags{coreOnlyConfig: true} 66 67 // watchdog.{runtime-timeout,shutdown-timeout} 68 addFSOnlyHandler(validateWatchdogOptions, handleWatchdogConfiguration, coreOnly) 69 70 // Export experimental.* flags to a place easily accessible from snapd helpers. 71 addFSOnlyHandler(validateExperimentalSettings, doExportExperimentalFlags, &flags{earlyConfigFilter: earlyExperimentalSettingsFilter}) 72 73 // network.disable-ipv6 74 addFSOnlyHandler(validateNetworkSettings, handleNetworkConfiguration, coreOnly) 75 76 // service.*.disable 77 addFSOnlyHandler(nil, handleServiceDisableConfiguration, coreOnly) 78 79 // system.power-key-action 80 addFSOnlyHandler(nil, handlePowerButtonConfiguration, coreOnly) 81 82 // pi-config.* 83 addFSOnlyHandler(nil, handlePiConfiguration, coreOnly) 84 85 // system.disable-backlight-service 86 addFSOnlyHandler(validateBacklightServiceSettings, handleBacklightServiceConfiguration, coreOnly) 87 88 // system.kernel.printk.console-loglevel 89 addFSOnlyHandler(validateSysctlOptions, handleSysctlConfiguration, coreOnly) 90 91 // journal.persistent 92 addFSOnlyHandler(validateJournalSettings, handleJournalConfiguration, coreOnly) 93 94 // system.timezone 95 addFSOnlyHandler(validateTimezoneSettings, handleTimezoneConfiguration, coreOnly) 96 97 sysconfig.ApplyFilesystemOnlyDefaultsImpl = func(rootDir string, defaults map[string]interface{}, options *sysconfig.FilesystemOnlyApplyOptions) error { 98 return filesystemOnlyApply(rootDir, plainCoreConfig(defaults), options) 99 } 100 } 101 102 // addFSOnlyHandler registers functions to validate and handle a subset of 103 // system config options that do not require to manipulate state but only 104 // the file system. 105 func addFSOnlyHandler(validate func(config.ConfGetter) error, handle func(config.ConfGetter, *fsOnlyContext) error, flags *flags) { 106 if handle == nil { 107 panic("cannot have nil handle with fsOnlyHandler") 108 } 109 h := &fsOnlyHandler{ 110 validateFunc: validate, 111 handleFunc: handle, 112 } 113 if flags != nil { 114 h.configFlags = *flags 115 } 116 handlers = append(handlers, h) 117 } 118 119 func (h *fsOnlyHandler) needsState() bool { 120 return false 121 } 122 123 func (h *fsOnlyHandler) flags() flags { 124 return h.configFlags 125 } 126 127 func (h *fsOnlyHandler) validate(cfg config.ConfGetter) error { 128 if h.validateFunc != nil { 129 return h.validateFunc(cfg) 130 } 131 return nil 132 } 133 134 func (h *fsOnlyHandler) handle(cfg config.ConfGetter, opts *fsOnlyContext) error { 135 // handleFunc is guaranteed to be non-nil by addFSOnlyHandler 136 return h.handleFunc(cfg, opts) 137 } 138 139 // filesystemOnlyApply applies filesystem modifications under rootDir, according to the 140 // cfg configuration. This is a subset of core config options that is important 141 // early during boot, before all the configuration is applied as part of 142 // normal execution of configure hook. 143 // Exposed for use via sysconfig.ApplyFilesystemOnlyDefaults. 144 func filesystemOnlyApply(rootDir string, cfg config.ConfGetter, opts *sysconfig.FilesystemOnlyApplyOptions) error { 145 if rootDir == "" { 146 return fmt.Errorf("internal error: root directory for configcore.FilesystemOnlyApply() not set") 147 } 148 149 ctx := &fsOnlyContext{RootDir: rootDir} 150 for _, h := range handlers { 151 if h.needsState() { 152 continue 153 } 154 if err := h.validate(cfg); err != nil { 155 return err 156 } 157 } 158 159 for _, h := range handlers { 160 if h.needsState() { 161 continue 162 } 163 if h.flags().coreOnlyConfig && opts != nil && opts.Classic { 164 continue 165 } 166 if err := h.handle(cfg, ctx); err != nil { 167 return err 168 } 169 } 170 return nil 171 }