github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/overlord/configstate/configcore/runwithstate.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 // +build !nomanagers 3 4 /* 5 * Copyright (C) 2020 Canonical Ltd 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 3 as 9 * published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 package configcore 22 23 import ( 24 "fmt" 25 "strings" 26 27 "github.com/snapcore/snapd/overlord/configstate/config" 28 "github.com/snapcore/snapd/release" 29 ) 30 31 func init() { 32 // Most of these handlers are no-op on classic. 33 // TODO: consider allowing some of these on classic too? 34 // consider erroring on core-only options on classic? 35 36 coreOnly := &flags{coreOnlyConfig: true} 37 38 // capture cloud information 39 addWithStateHandler(nil, setCloudInfoWhenSeeding, nil) 40 41 // proxy.{http,https,ftp} 42 addWithStateHandler(validateProxyStore, handleProxyConfiguration, coreOnly) 43 44 // resilience.vitality-hint 45 addWithStateHandler(validateVitalitySettings, handleVitalityConfiguration, nil) 46 47 // XXX: this should become a FSOnlyHandler. We need to 48 // add/implement Changes() to the ConfGetter interface 49 // store-certs.* 50 addWithStateHandler(validateCertSettings, handleCertConfiguration, nil) 51 52 validateOnly := &flags{validatedOnlyStateConfig: true} 53 addWithStateHandler(validateRefreshSchedule, nil, validateOnly) 54 addWithStateHandler(validateRefreshRateLimit, nil, validateOnly) 55 addWithStateHandler(validateAutomaticSnapshotsExpiration, nil, validateOnly) 56 } 57 58 type withStateHandler struct { 59 validateFunc func(config.Conf) error 60 handleFunc func(config.Conf, *fsOnlyContext) error 61 configFlags flags 62 } 63 64 func (h *withStateHandler) validate(cfg config.ConfGetter) error { 65 conf := cfg.(config.Conf) 66 if h.validateFunc != nil { 67 return h.validateFunc(conf) 68 } 69 return nil 70 } 71 72 func (h *withStateHandler) handle(cfg config.ConfGetter, opts *fsOnlyContext) error { 73 conf := cfg.(config.Conf) 74 if h.handleFunc != nil { 75 return h.handleFunc(conf, opts) 76 } 77 return nil 78 } 79 80 func (h *withStateHandler) needsState() bool { 81 return true 82 } 83 84 func (h *withStateHandler) flags() flags { 85 return h.configFlags 86 } 87 88 // addWithStateHandler registers functions to validate and handle a subset of 89 // system config options requiring to access and manipulate state. 90 func addWithStateHandler(validate func(config.Conf) error, handle func(config.Conf, *fsOnlyContext) error, flags *flags) { 91 if handle == nil && (flags == nil || !flags.validatedOnlyStateConfig) { 92 panic("cannot have nil handle with addWithStateHandler if validatedOnlyStateConfig flag is not set") 93 } 94 h := &withStateHandler{ 95 validateFunc: validate, 96 handleFunc: handle, 97 } 98 if flags != nil { 99 h.configFlags = *flags 100 } 101 handlers = append(handlers, h) 102 } 103 104 func Run(cfg config.Conf) error { 105 // check if the changes 106 for _, k := range cfg.Changes() { 107 switch { 108 case strings.HasPrefix(k, "core.store-certs."): 109 if !validCertOption(k) { 110 return fmt.Errorf("cannot set store ssl certificate under name %q: name must only contain word characters or a dash", k) 111 } 112 case !supportedConfigurations[k]: 113 return fmt.Errorf("cannot set %q: unsupported system option", k) 114 } 115 } 116 117 for _, h := range handlers { 118 if err := h.validate(cfg); err != nil { 119 return err 120 } 121 } 122 123 for _, h := range handlers { 124 if h.flags().coreOnlyConfig && release.OnClassic { 125 continue 126 } 127 if err := h.handle(cfg, nil); err != nil { 128 return err 129 } 130 } 131 return nil 132 }