github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/overlord/configstate/configcore/refresh.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 // +build !nomanagers 3 4 /* 5 * Copyright (C) 2017-2018 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 "strconv" 26 "time" 27 28 "github.com/snapcore/snapd/overlord/configstate/config" 29 "github.com/snapcore/snapd/overlord/devicestate" 30 "github.com/snapcore/snapd/strutil" 31 "github.com/snapcore/snapd/timeutil" 32 ) 33 34 func init() { 35 supportedConfigurations["core.refresh.hold"] = true 36 supportedConfigurations["core.refresh.schedule"] = true 37 supportedConfigurations["core.refresh.timer"] = true 38 supportedConfigurations["core.refresh.metered"] = true 39 supportedConfigurations["core.refresh.retain"] = true 40 supportedConfigurations["core.refresh.rate-limit"] = true 41 } 42 43 func reportOrIgnoreInvalidManageRefreshes(tr config.Conf, optName string) error { 44 // check if the option is set as part of transaction changes; if not than 45 // it's already set in the config state and we shouldn't error out about it 46 // now. refreshScheduleManaged will do the right thing when refresh cannot 47 // be managed anymore. 48 for _, k := range tr.Changes() { 49 if k == "core."+optName { 50 return fmt.Errorf("cannot set schedule to managed") 51 } 52 } 53 return nil 54 } 55 56 func validateRefreshSchedule(tr config.Conf) error { 57 refreshRetainStr, err := coreCfg(tr, "refresh.retain") 58 if err != nil { 59 return err 60 } 61 if refreshRetainStr != "" { 62 if n, err := strconv.ParseUint(refreshRetainStr, 10, 8); err != nil || (n < 2 || n > 20) { 63 return fmt.Errorf("retain must be a number between 2 and 20, not %q", refreshRetainStr) 64 } 65 } 66 67 refreshHoldStr, err := coreCfg(tr, "refresh.hold") 68 if err != nil { 69 return err 70 } 71 if refreshHoldStr != "" { 72 if _, err := time.Parse(time.RFC3339, refreshHoldStr); err != nil { 73 return fmt.Errorf("refresh.hold cannot be parsed: %v", err) 74 } 75 } 76 77 refreshOnMeteredStr, err := coreCfg(tr, "refresh.metered") 78 if err != nil { 79 return err 80 } 81 switch refreshOnMeteredStr { 82 case "", "hold": 83 // noop 84 default: 85 return fmt.Errorf("refresh.metered value %q is invalid", refreshOnMeteredStr) 86 } 87 88 // check (new) refresh.timer 89 refreshTimerStr, err := coreCfg(tr, "refresh.timer") 90 if err != nil { 91 return err 92 } 93 if refreshTimerStr == "managed" { 94 st := tr.State() 95 st.Lock() 96 defer st.Unlock() 97 98 if !devicestate.CanManageRefreshes(st) { 99 return reportOrIgnoreInvalidManageRefreshes(tr, "refresh.timer") 100 } 101 return nil 102 } 103 if refreshTimerStr != "" { 104 // try legacy refresh.schedule setting if new-style 105 // refresh.timer is not set 106 if _, err = timeutil.ParseSchedule(refreshTimerStr); err != nil { 107 return err 108 } 109 } 110 111 // check (legacy) refresh.schedule 112 refreshScheduleStr, err := coreCfg(tr, "refresh.schedule") 113 if err != nil { 114 return err 115 } 116 if refreshScheduleStr == "" { 117 return nil 118 } 119 120 if refreshScheduleStr == "managed" { 121 st := tr.State() 122 st.Lock() 123 defer st.Unlock() 124 125 if !devicestate.CanManageRefreshes(st) { 126 return reportOrIgnoreInvalidManageRefreshes(tr, "refresh.schedule") 127 } 128 return nil 129 } 130 131 _, err = timeutil.ParseLegacySchedule(refreshScheduleStr) 132 return err 133 } 134 135 func validateRefreshRateLimit(tr config.Conf) error { 136 refreshRateLimit, err := coreCfg(tr, "refresh.rate-limit") 137 if err != nil { 138 return err 139 } 140 // reset is fine 141 if len(refreshRateLimit) == 0 { 142 return nil 143 } 144 if _, err := strutil.ParseByteSize(refreshRateLimit); err != nil { 145 return err 146 } 147 return nil 148 }