Merge ~kwmonroe/layer-snap:feature/snapd-refresh into ~stub/layer-snap:master

Proposed by Kevin W Monroe
Status: Merged
Merged at revision: 7d8eb64030161e7451db5968bae7d4874ae87353
Proposed branch: ~kwmonroe/layer-snap:feature/snapd-refresh
Merge into: ~stub/layer-snap:master
Diff against target: 156 lines (+94/-1)
4 files modified
README.md (+40/-1)
config.yaml (+9/-0)
lib/charms/layer/snap.py (+36/-0)
reactive/snap.py (+9/-0)
Reviewer Review Type Date Requested Status
Stuart Bishop Approve
Review via email: mp+349067@code.launchpad.net

Commit message

Support a new 'snapd_refresh' config option, which sets the snapd refresh.timer option.

To post a comment you must log in.
Revision history for this message
Stuart Bishop (stub) wrote :

This all looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/README.md b/README.md
2index 254649a..1ba2ebe 100644
3--- a/README.md
4+++ b/README.md
5@@ -86,13 +86,52 @@ have been installed, so you do not need to worry about installation
6 order.
7
8
9+### Snap Refresh
10+
11+By default, the `snapd` daemon will query the Snap Store four (4)
12+times per day to process updates for installed snaps. This layer provides
13+a charm configuration option for authors and operators to control this
14+refresh frequency.
15+
16+>NOTE: this is a global configuration option and will affect the refresh
17+time for all snaps installed on a system.
18+
19+>NOTE: requires snapd 2.31 or higher.
20+
21+Examples:
22+
23+```sh
24+## refresh snaps every tuesday
25+juju config telegraf snapd_refresh="tue"
26+
27+## refresh snaps at 11pm on the last (5th) friday of the month
28+juju config telegraf snapd_refresh="fri5,23:00"
29+
30+## use the system default refresh timer
31+juju config telegraf snapd_refresh=""
32+```
33+
34+Currently, the `snapd` refresh timer may be delayed up to one (1) month. This
35+can be configured using the `max` option:
36+
37+```sh
38+## delay snap refreshes as long as possible
39+juju config telegraf snapd_refresh="max"
40+```
41+
42+For more information on the possible values for `snapd_refresh`, see the
43+*refresh.timer* section in the [system options][] documentation.
44+
45+[system options]: https://forum.snapcraft.io/t/system-options/87
46+
47+
48 ## Usage
49
50 If you have defined your snaps in layer.yaml for automatic installation
51 and updates, there is nothing further to do.
52
53 ### API
54-
55+
56 If your charm need to control installation, update and removal of snaps
57 itself, the following methods are available via the `charms.layer.snap`
58 package::
59diff --git a/config.yaml b/config.yaml
60index 754d46a..939cf3d 100644
61--- a/config.yaml
62+++ b/config.yaml
63@@ -25,3 +25,12 @@ options:
64 description: |
65 The address of a Snappy Enterprise Proxy to use for snaps
66 e.g. http://snap-proxy.example.com
67+ snapd_refresh:
68+ default: ""
69+ type: string
70+ description: |
71+ How often snapd handles updates for installed snaps. The default
72+ (an empty string) is 4x per day. Set to "max" to check once per month
73+ based on the charm deployment date. You may also set a custom string as
74+ described in the 'refresh.timer' section here:
75+ https://forum.snapcraft.io/t/system-options/87
76diff --git a/lib/charms/layer/snap.py b/lib/charms/layer/snap.py
77index 80e94e4..be32056 100644
78--- a/lib/charms/layer/snap.py
79+++ b/lib/charms/layer/snap.py
80@@ -22,6 +22,7 @@ from charms import layer
81 from charms import reactive
82 from charms.reactive.helpers import any_file_changed, data_changed
83 from time import sleep
84+from datetime import datetime, timedelta
85
86
87 def install(snapname, **kw):
88@@ -178,6 +179,41 @@ def set(snapname, key, value):
89 ['snap', 'set', snapname, '{}={}'.format(key, value)])
90
91
92+def set_refresh_timer(timer=''):
93+ '''Set the system refresh.timer option (snapd 2.31+)
94+
95+ This method sets how often snapd will refresh installed snaps. Call with
96+ an empty timer string to use the system default (currently 4x per day).
97+ Use 'max' to schedule refreshes as far into the future as possible
98+ (currently 1 month). Also accepts custom timer strings as defined in the
99+ refresh.timer section here:
100+ https://forum.snapcraft.io/t/system-options/87
101+
102+ This method does not validate custom strings and will lead to a
103+ CalledProcessError if an invalid string is given.
104+
105+ :param: timer: empty string (default), 'max', or custom string
106+ '''
107+ if timer == 'max':
108+ # A month from yesterday is the farthest we should delay to safely stay
109+ # under the 1 month max. Translate that to a valid refresh.timer value.
110+ # Examples:
111+ # - Today is Friday the 13th, set the refresh timer to
112+ # 'thu2' (Thursday the 12th is the 2nd thursday of the month).
113+ # - Today is Tuesday the 1st, set the refresh timer to
114+ # 'mon5' (Monday the [28..31] is the 5th monday of the month).
115+ yesterday = datetime.now() - timedelta(1)
116+ dow = yesterday.strftime('%a').lower()
117+ # increment after int division because we want occurrence 1-5, not 0-4.
118+ occurrence = yesterday.day // 7 + 1
119+ timer = '{}{}'.format(dow, occurrence)
120+
121+ # NB: 'system' became synonymous with 'core' in 2.32.5, but we use 'core'
122+ # here to ensure max compatibility.
123+ set(snapname='core', key='refresh.timer', value=timer)
124+ subprocess.check_call(['systemctl', 'restart', 'snapd.service'])
125+
126+
127 def get(snapname, key):
128 '''Gets configuration options for a snap
129
130diff --git a/reactive/snap.py b/reactive/snap.py
131index 884dc63..d646527 100644
132--- a/reactive/snap.py
133+++ b/reactive/snap.py
134@@ -31,6 +31,7 @@ from charmhelpers.core.host import write_file
135 from charms import layer
136 from charms import reactive
137 from charms.layer import snap
138+from charms.reactive import when
139 from charms.reactive.helpers import data_changed
140
141
142@@ -263,6 +264,14 @@ def configure_snap_enterprise_proxy():
143 'Proxy ID from header did not match store assertion: ' + e.output)
144
145
146+@when('config.changed.snapd_refresh')
147+def change_snapd_refresh():
148+ """Set the system refresh.timer option"""
149+ ensure_snapd_min_version('2.31')
150+ timer = hookenv.config()['snapd_refresh']
151+ snap.set_refresh_timer(timer)
152+
153+
154 # Per https://github.com/juju-solutions/charms.reactive/issues/33,
155 # this module may be imported multiple times so ensure the
156 # initialization hook is only registered once. I have to piggy back

Subscribers

People subscribed via source and target branches

to all changes: