github.com/Lephar/snapd@v0.0.0-20210825215435-c7fba9cef4d2/overlord/configstate/configcore/handlers.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2021 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(sysconfig.Device, 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 filterFunc 50 } 51 52 type fsOnlyHandler struct { 53 validateFunc func(config.ConfGetter) error 54 handleFunc func(sysconfig.Device, 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 // swap.size 89 addFSOnlyHandler(validateSystemSwapConfiguration, handlesystemSwapConfiguration, coreOnly) 90 91 // system.kernel.printk.console-loglevel 92 addFSOnlyHandler(validateSysctlOptions, handleSysctlConfiguration, coreOnly) 93 94 // journal.persistent 95 addFSOnlyHandler(validateJournalSettings, handleJournalConfiguration, coreOnly) 96 97 // system.timezone 98 addFSOnlyHandler(validateTimezoneSettings, handleTimezoneConfiguration, coreOnly) 99 100 // system.hostname 101 addFSOnlyHandler(validateHostnameSettings, handleHostnameConfiguration, coreOnly) 102 103 sysconfig.ApplyFilesystemOnlyDefaultsImpl = filesystemOnlyApply 104 } 105 106 // addFSOnlyHandler registers functions to validate and handle a subset of 107 // system config options that do not require to manipulate state but only 108 // the file system. 109 func addFSOnlyHandler(validate func(config.ConfGetter) error, handle func(sysconfig.Device, config.ConfGetter, *fsOnlyContext) error, flags *flags) { 110 if handle == nil { 111 panic("cannot have nil handle with fsOnlyHandler") 112 } 113 h := &fsOnlyHandler{ 114 validateFunc: validate, 115 handleFunc: handle, 116 } 117 if flags != nil { 118 h.configFlags = *flags 119 } 120 handlers = append(handlers, h) 121 } 122 123 func (h *fsOnlyHandler) needsState() bool { 124 return false 125 } 126 127 func (h *fsOnlyHandler) flags() flags { 128 return h.configFlags 129 } 130 131 func (h *fsOnlyHandler) validate(cfg config.ConfGetter) error { 132 if h.validateFunc != nil { 133 return h.validateFunc(cfg) 134 } 135 return nil 136 } 137 138 func (h *fsOnlyHandler) handle(dev sysconfig.Device, cfg config.ConfGetter, opts *fsOnlyContext) error { 139 // handleFunc is guaranteed to be non-nil by addFSOnlyHandler 140 return h.handleFunc(dev, cfg, opts) 141 } 142 143 // filesystemOnlyApply applies filesystem modifications under rootDir, according to the 144 // cfg configuration. This is a subset of core config options that is important 145 // early during boot, before all the configuration is applied as part of 146 // normal execution of configure hook. 147 // Exposed for use via sysconfig.ApplyFilesystemOnlyDefaults. 148 func filesystemOnlyApply(dev sysconfig.Device, rootDir string, values map[string]interface{}) error { 149 if rootDir == "" { 150 return fmt.Errorf("internal error: root directory for configcore.FilesystemOnlyApply() not set") 151 } 152 153 cfg := plainCoreConfig(values) 154 155 ctx := &fsOnlyContext{ 156 RootDir: rootDir, 157 } 158 for _, h := range handlers { 159 if h.needsState() { 160 continue 161 } 162 if err := h.validate(cfg); err != nil { 163 return err 164 } 165 } 166 167 for _, h := range handlers { 168 if h.needsState() { 169 continue 170 } 171 if h.flags().coreOnlyConfig && dev.Classic() { 172 continue 173 } 174 if err := h.handle(dev, cfg, ctx); err != nil { 175 return err 176 } 177 } 178 return nil 179 }