github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/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 // validatedOnylStateConfig tells that the config requires only validation, 42 // its options are applied dynamically elsewhere. 43 validatedOnlyStateConfig bool 44 } 45 46 type fsOnlyHandler struct { 47 validateFunc func(config.ConfGetter) error 48 handleFunc func(config.ConfGetter, *fsOnlyContext) error 49 configFlags flags 50 } 51 52 var handlers []configHandler 53 54 func init() { 55 // Most of these handlers are no-op on classic. 56 // TODO: consider allowing some of these on classic too? 57 // consider erroring on core-only options on classic? 58 59 coreOnly := &flags{coreOnlyConfig: true} 60 61 // watchdog.{runtime-timeout,shutdown-timeout} 62 addFSOnlyHandler(validateWatchdogOptions, handleWatchdogConfiguration, coreOnly) 63 64 // Export experimental.* flags to a place easily accessible from snapd helpers. 65 addFSOnlyHandler(validateExperimentalSettings, doExportExperimentalFlags, nil) 66 67 // network.disable-ipv6 68 addFSOnlyHandler(validateNetworkSettings, handleNetworkConfiguration, coreOnly) 69 70 // service.*.disable 71 addFSOnlyHandler(nil, handleServiceDisableConfiguration, coreOnly) 72 73 // system.power-key-action 74 addFSOnlyHandler(nil, handlePowerButtonConfiguration, coreOnly) 75 76 // pi-config.* 77 addFSOnlyHandler(nil, handlePiConfiguration, coreOnly) 78 79 // system.disable-backlight-service 80 addFSOnlyHandler(validateBacklightServiceSettings, handleBacklightServiceConfiguration, coreOnly) 81 82 // system.kernel.printk.console-loglevel 83 addFSOnlyHandler(validateSysctlOptions, handleSysctlConfiguration, coreOnly) 84 85 // journal.persistent 86 addFSOnlyHandler(validateJournalSettings, handleJournalConfiguration, coreOnly) 87 88 // system.timezone 89 addFSOnlyHandler(validateTimezoneSettings, handleTimezoneConfiguration, coreOnly) 90 91 sysconfig.ApplyFilesystemOnlyDefaultsImpl = func(rootDir string, defaults map[string]interface{}, options *sysconfig.FilesystemOnlyApplyOptions) error { 92 return filesystemOnlyApply(rootDir, plainCoreConfig(defaults), options) 93 } 94 } 95 96 // addFSOnlyHandler registers functions to validate and handle a subset of 97 // system config options that do not require to manipulate state but only 98 // the file system. 99 func addFSOnlyHandler(validate func(config.ConfGetter) error, handle func(config.ConfGetter, *fsOnlyContext) error, flags *flags) { 100 if handle == nil { 101 panic("cannot have nil handle with fsOnlyHandler") 102 } 103 h := &fsOnlyHandler{ 104 validateFunc: validate, 105 handleFunc: handle, 106 } 107 if flags != nil { 108 h.configFlags = *flags 109 } 110 handlers = append(handlers, h) 111 } 112 113 func (h *fsOnlyHandler) needsState() bool { 114 return false 115 } 116 117 func (h *fsOnlyHandler) flags() flags { 118 return h.configFlags 119 } 120 121 func (h *fsOnlyHandler) validate(cfg config.ConfGetter) error { 122 if h.validateFunc != nil { 123 return h.validateFunc(cfg) 124 } 125 return nil 126 } 127 128 func (h *fsOnlyHandler) handle(cfg config.ConfGetter, opts *fsOnlyContext) error { 129 // handleFunc is guaranteed to be non-nil by addFSOnlyHandler 130 return h.handleFunc(cfg, opts) 131 } 132 133 // filesystemOnlyApply applies filesystem modifications under rootDir, according to the 134 // cfg configuration. This is a subset of core config options that is important 135 // early during boot, before all the configuration is applied as part of 136 // normal execution of configure hook. 137 // Exposed for use via sysconfig.ApplyFilesystemOnlyDefaults. 138 func filesystemOnlyApply(rootDir string, cfg config.ConfGetter, opts *sysconfig.FilesystemOnlyApplyOptions) error { 139 if rootDir == "" { 140 return fmt.Errorf("internal error: root directory for configcore.FilesystemOnlyApply() not set") 141 } 142 143 ctx := &fsOnlyContext{RootDir: rootDir} 144 for _, h := range handlers { 145 if h.needsState() { 146 continue 147 } 148 if err := h.validate(cfg); err != nil { 149 return err 150 } 151 } 152 153 for _, h := range handlers { 154 if h.needsState() { 155 continue 156 } 157 if h.flags().coreOnlyConfig && opts != nil && opts.Classic { 158 continue 159 } 160 if err := h.handle(cfg, ctx); err != nil { 161 return err 162 } 163 } 164 return nil 165 }