New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
many: move firstboot code into the snapd daemon #2033
Conversation
But keep `snap firstboot` around because we can not update files in the writable area once they are moved out of the snap (yes, this sucks!).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few suggestions, and LGTM
return boot.FirstBoot() | ||
println(` | ||
This command does nothing, its only there because we can not update files | ||
in the writable space after they got copied out of the snap. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to perhaps do:
fmt.Fprintf(Stderr, "firstboot command is deprecated")
and comment more clearly about the circumstances which makes us keep this in place, so that we won't forget either to keep it or to remove it, once we feel it's time to do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, done. The old message was really more meant for you/the other reviewers as a reminder that we need to think a bit about the writable space :)
ovld, err := overlord.New() | ||
func PopulateStateFromSeed(st *state.State) error { | ||
// check that the state is empty | ||
all, err := snapstate.All(st) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we check something more explicit, such as as "seeded" flag? I'm concerned about the possibility of a seeded state that has no snaps (think classic).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question still open here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, sorry for the slow reply. This is added now.
@@ -111,31 +94,13 @@ func populateStateFromSeed() error { | |||
return nil | |||
} | |||
|
|||
st.Lock() | |||
msg := fmt.Sprintf("First boot seeding") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we please tweak that to a more user-oriented "Initialize system state"
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, done.
m.state.Lock() | ||
defer m.state.Unlock() | ||
|
||
// FIXME: enable on classic? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, let's enable it, but let's do that later as we need to review our model assertions and make sure it's all hanging together for old installations.
return nil | ||
} | ||
|
||
all, err := snapstate.All(m.state) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a tech debt microtask item to our board:
- Add snapstate.IsEmpty to avoid len(snapstate.All(st)) == 0 checks
// a failed boot that falls back to the previous version for | ||
// example) | ||
m.state.Lock() | ||
wasRun := m.state.Cached(cachedUpdateRevisionsWasRun{}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use a simpler bool like m.firstEnsure
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, fixed.
if wasRun == nil { | ||
m.state.Lock() | ||
err := UpdateRevisions(m.state) | ||
m.state.EnsureBefore(0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we let UpdateRevisions itself do that if actually necessary? Otherwise we're assuming we know what happened there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, yes, this moved into UpdateRevisions()
@@ -55,6 +54,15 @@ func checkAssumes(s *snap.Info) error { | |||
|
|||
var openSnapFile = backend.OpenSnapFile | |||
|
|||
// FIXME: drop and get the gadget name from the model assertion instead | |||
func isFirstBoot(st *state.State) bool { | |||
chg := st.Change("1") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can easily have a different initial change without realizing we're breaking this.
I suggest dropping the use of isFirstBoot below, and adding a card for the RC to fix the race condition properly. During normal working, the remaining logic will catch and prevent the problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dropped this.
@@ -94,7 +89,9 @@ func UpdateRevisions(ovld *overlord.Overlord) error { | |||
for snapName, snapState := range installed { | |||
if name == snapName { | |||
if rev != snapState.Current { | |||
ts, err := snapstate.RevertToRevision(st, name, rev, snapstate.Flags(0)) | |||
// FIXME: check that there is no task |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is already done. We just need to make the error have a proper type and enough metadata so we can tell we're ignoring the right thing here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's please add a card to the RC to fix that. This sounds like the sort of thing that may break down a device permanently in the wild.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I added a card https://trello.com/c/oJhUNofF for this.
return err | ||
} | ||
return boot.UpdateRevisions(ovld) | ||
fmt.Fprintf(Stderr, "firstboot command is deprecated") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should it say booted command ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, good catch.
"github.com/snapcore/snapd/overlord" | ||
"github.com/snapcore/snapd/overlord/boot" | ||
"github.com/snapcore/snapd/partition" | ||
"github.com/snapcore/snapd/release" | ||
) | ||
|
||
type cmdBooted struct{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needs the same kind of comment as firstboot?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, added that.
@@ -38,6 +38,9 @@ import ( | |||
"github.com/snapcore/snapd/snap" | |||
"github.com/snapcore/snapd/snap/squashfs" | |||
"github.com/snapcore/snapd/store" | |||
|
|||
// important so that the testkeys get imported |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as I said we should organize things differently but we can work that out during RC, is not visible to users
assertSeedDir := filepath.Join(dirs.SnapSeedDir, "assertions") | ||
dc, err := ioutil.ReadDir(assertSeedDir) | ||
if os.IsNotExist(err) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
notice that in that case there will be no model though, anyway I suppoe prepare-image atm always put that dir there
|
||
st.EnsureBefore(0) | ||
<-chg.Ready() | ||
snapstate.SetGlobalFlag(st, snapstate.Seeded) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if I understand this means we will not try to make this change again even if it failed, I suppose that's ok until we learn something else
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also should this be flags|snapstate.Seeded if we go with flags?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed I reworked this to a single flag in the state. Much simpler and nicer this way.
return nil | ||
} | ||
|
||
for _, chg := range m.state.Changes() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need this now? afaict PopulateStateFromSeed will make the change once and commit and then never work again because of the flag
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking we need it for the case when PopulateStateFromSeed will trigger the change and then the system reboots. It will reach firstboot again and the "seeded" flag is not set in the state because the changes are not finished yet (well, currently the flag is set before the tasks are all completed so there it is unneeded, however if we set it only after the seed tasks are all successful we need this check).
) | ||
|
||
// GlobalFlags returns a set of flags related to the snapstate | ||
func GlobalFlags(s *state.State) (int, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure why don't simply use top level bools instate for this ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, did that now, thank you!
logger.Debugf("Ignoring 'booted' on classic") | ||
return nil | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the rest of this function doesn't seem tested
// settles we disable it. | ||
if release.OnClassic { | ||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the rest of this function doesn't seem to be tested
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, sorry for that, I added tests for this now.
@@ -144,6 +148,22 @@ func makeTestSnap(c *C, snapYamlContent string) string { | |||
return snaptest.MakeTestSnapWithFiles(c, snapYamlContent, nil) | |||
} | |||
|
|||
func (ms *mgrsSuite) makePopulatedState(c *C) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not needed anymore I suppose
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I removed it.
@@ -204,11 +199,19 @@ func (s *checkSnapSuite) TestCheckSnapGadgetMissingPrior(c *C) { | |||
st.Lock() | |||
defer st.Unlock() | |||
|
|||
snapstate.Set(st, "not-firstboot", &snapstate.SnapState{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
set seeded instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, fixed.
@@ -10,20 +10,26 @@ prepare: | | |||
touch $SEED_DIR/seed.yaml |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this test is removing stamp which is not needed anymore right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, thank you! removed.
@@ -54,7 +51,7 @@ func nameAndRevnoFromSnap(sn string) (string, snap.Revision, error) { | |||
// still has the "active" version set to "v2" which is | |||
// misleading. This code will check what kernel/os booted and set | |||
// those versions active. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add here something like "To do this it creates a Change and kick starts it directly."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, added.
st := ovld.State() | ||
st.Lock() | ||
installed, err := snapstate.All(st) | ||
installed, err := All(st) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not a blocker, but still wondering why this doesn't just use snapstate.CurrentInfo(st, kernelSnap|osSnap) instead of All
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think this is pretty old code, I fixed it to use CurrentInfo() now.
c.Assert(called, Equals, false) | ||
} | ||
|
||
func (s *deviceMgrSuite) TestDeviceManagerEnsureSeedYamlHappy(c *C) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we want a run-through version, so we test doMarkSeed ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think this is a good idea, slightly worried about timing. I will work on it after lunch.
return fmt.Errorf(i18n.G("cannot mark boot successful: %s"), err) | ||
} | ||
|
||
if err := partition.MarkBootSuccessful(bootloader); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this going to write the boot env each 5 minutes? maybe we should have a flag on m that we set just after this one, so we do it once per snapd invocation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent point, it will run this every 5min. It won't actually write the bootloader bits every 5min because it checks internally if the var has actually changed. However its still silly, so added a flag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, maybe I wasn't clear, I would have put the flag only around MarkBootSuccessful itself
func UpdateRevisions(ovld *overlord.Overlord) error { | ||
// those versions active.To do this it creates a Change and kicks | ||
// start it directly. | ||
func UpdateRevisions(st *state.State) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
didn't think of this so far but now that is under snapstate the name is a bit generic, UpdateBootRevisions ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this makes sense, updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
Imported using git-ubuntu import. Changelog parent: d92891f New changelog entries: * New upstream release, LP: #1637215: - release: os-release on core has changed - tests: /dev/ptmx does not work on powerpc, skip here - docs: moved to github.com/snapcore/snapd/wiki (snapcore#2258) - debian: golang is not installable on powerpc, use golang-any * New upstream release, LP: #1637215: - overlord/ifacestate: add unit tests for undo of setup-snap- security (snapcore#2243) - daemon,overlord,snap,tests: download to .partial in final dir (snapcore#2237) - overlord/state: marshaling tests for lanes (snapcore#2245) - overlord/state: introduce state lanes (snapcore#2241) - overlord/snapstate: fix revert+refresh (snapcore#2224) - interfaces/sytemd: enable/disable generated service units (snapcore#2229) - many: fix incorrect security files generation on undo - overlord/snapstate: add dynamic snapdX.Y assumes (snapcore#2227) - interfaces: network-manager: give slot full read-write access to /run/NetworkManager - docs: update the name of the command for the cross-build - overlord/snapstate: fix missing argument to Noticef - snapstate: ensure gadget/core/kernel can not be disabled (snapcore#2218) - asserts: limit to 1y only if len(models) == 0 (snapcore#2219) - debian: only install share/locale if available (missing on powerpc) - overlrod/snapstate: fix revert followed by refresh to old-current (snapcore#2214) - interfaces/builtin: network-manager and bluez can change hostname (snapcore#2204) - snap: switch the auto-import dir to /run/snapd/auto-import - docs: less details about cloud.cfg as requested in trello (snapcore#2206) - spread.yaml: Ensure ubuntu user has passwordless sudo for autopkgtests (snapcore#2201) - interfaces/builtin: add dcdbas-control interface - boot: do not set boot to try mode if the revision is unchanged - interfaces: add shutdown interface (snapcore#2162) - interfaces: add system-power-control interface - many: use the new systemd backend for configuring GPIOs - overlord/ifacestate: setup security for slots before plugs - snap: spool assertion candidates if snapd is not up yet - store,daemon,overlord: download things to a partials dir - asserts,daemon: implement system-user-authority header/concept - interfaces/builtin: home base declaration rule using on-classic for its policy - interfaces/builtin: finish decl based checks - asserts: bump snap-declaration to allow signing with new-style plugs and slots - overlord: checks for kernel installation/refresh based on model assertion and previous kernel - tests/lib/fakestore: fix logic to distinguish assertion not found errors - client: add a few explicit error types (around the request cycle) - tests/lib/fakestore/cmd/fakestore: make it log, and fix a typo - overlord/snapstate: two bugs for one - snappy: disable auto-import of assertions on classic (snapcore#2122) - overlord/snapstate: move trash cleanup to a cleanup handler (snapcore#2173) - daemon: make create-user --known fail on classic without --force- managed (snapcore#2123) - asserts,interfaces/policy: implement on-classic plug/slot constraints - overlord: check that the first installed gadget matches the model assertion - tests: use the snapd-control-consumer snap from the store - cmd/snap: make snap run not talk to snapd for finding the revision - snap/squashfs: try to hard link instead of copying. Also, switch to osutil.CopyFile for cp invocation. - store: send supported max-format when retrieving assertions - snapstate, devicestate: do not remove seed - boot,image,overlord,partition: read/write boot variables in single operation - tests: reenable ubuntu-core tests on qemu - asserts,interfaces/policy: allow OR-ing of subrule constraints in plug/slot rules - many: move from flags as ints to flags as structs-of-bools (snapcore#2156) - many: add supports for keeping and finding assertions with different format iterations - snap: stop using ubuntu-core-launcher, use snap-confine - many: introduce an assertion format iteration concept, refuse to add unsupported assertion - interfaces: tweak wording and comment - spread.yaml: dump apparmor denials on spread failure - tests: unflake ubuntu-core-reboot (snapcore#2150) - cmd/snap: tweak unknown command error message (snapcore#2139) - client,daemon,cmd: add payment-declined error kind (snapcore#2107) - cmd/snap: update remove command help (snapcore#2145) - many: removed frameworks target and fixed service files (snapcore#2138) - asserts,snap: validate attributes to a JSON-compatible type subset (snapcore#2140) - asserts: remove unused serial-proof type - tests: skip auto-import tests on systems without test keys (snapcore#2142) - overlord/devicestate: don't spam the debug log on classic (snapcore#2141) - cmd/snap: simplify auto-import mountinfo parsing (snapcore#2135) - tests: run ubuntu-core upgrades on isolated machine (snapcore#2137) - overlord/devicestate: recover seeding from old external approach (snapcore#2134) - overlord: merge overlord/boot pkg into overlord/devicestate (snapcore#2118) - daemon: add postCreateUserSuite test suite (snapcore#2124) - tests: abort tests if an update process is scheduled (snapcore#2119) - snapstate: avoid reboots if nothing in the boot setup has changed (snapcore#2117) - cmd/snap: do not auto-import from loop or non-dev devices (snapcore#2121) - tests: add spread test for `snap auto-import` (snapcore#2126) - tests: add test for auto-mount assertion import (snapcore#2127) - osutil: add missing unit tests for IsMounted (snapcore#2133) - tests: check for failure creating user on managed ubuntu-core systems (snapcore#2096) - snap: ignore /dev/loop addings from udev (snapcore#2111) - tests: remove snapd.boot-ok reference (snapcore#2109) - tests: enable tests related to the home interface in all-snaps (snapcore#2106) - snapstate: only import defaults from gadget on install (snapcore#2105) - many: move firstboot code into the snapd daemon (snapcore#2033) - store: send correct JSON type of string for expected payment amount (snapcore#2103) - cmd/snap: rename is-managed to managed and tune (snapcore#2102) - interfaces,overlord/ifacestate: initial cleaning up of no arg AutoConnect related bits (snapcore#2090) - client, cmd: prompt for password when buying (snapcore#2086) - snapstate: fix hanging `snap remove` if snap is no longer mounted - image: support gadget specific cloud.conf file (snapcore#2101) - cmd/snap,ctlcmd: fix behavior of snap(ctl) get (snapcore#2093) - store: local users download from the anonymous url (snapcore#2100) - docs/hooks.md: fix typos (snapcore#2099) - many: check installation of slots and plugs against declarations - docs: fix missing "=" in the systemd-active docs - store: do not set store auth for local users (snapcore#2092) - interfaces,overlord/ifacestate: use declaration-based checking for auto-connect (snapcore#2071) - overlord, daemon, snap: support gadget config defaults (snapcore#2082)The main semantic changes are: - tests: fix snap-disconnect tests after core rename (snapcore#2088) - client,daemon,overlord,cmd: add /v2/users and create-user on auto- import (snapcore#2074) - many: abbreviated forms of disconnect (snapcore#2066) - asserts: require lowercase model until insensitive matching is ready (snapcore#2076) - cmd/snap: add version command, same as --version (snapcore#2075) - all: use "core" by default but allow "ubuntu-core" still (snapcore#2070) - overlord/devicestate, docs/hooks.md: nest prepare-device configuration options - daemon: fix login API to return local macaroons (snapcore#2078) - daemon: do not hardcode UID in userLookup (snapcore#2080) - client, cmd: connect fixes (snapcore#2026) - many: preparations for switching most of autoconnect to use the declarationsfor now: - overlord/auth: update CheckMacaroon to verify local snapd macaroons (snapcore#2069) - cmd/snap: trivial auto-import and download tweaks (snapcore#2067) - interfaces: add repo.ResolveConnect that handles name resolution - interfaces/policy: introduce InstallCandidate and its checks - interfaces/policy,overlord: check connection requests against the declarations in ifacestate - many: setup snapd macaroon for local users (snapcore#2051)Next step: do snapd macaroons verification. - interfaces/policy: implement snap-id/publisher-id checks - many: change Connect to take ConnRef instead of strings (snapcore#2060) - snap: auto mount block devices and import assertions (snapcore#2047) - daemon: add `snap create-user --force-managed` support (snapcore#2041) - docs: remove references to removed buying features (snapcore#2057) - interfaces,docs: allow sharing SNAP{,_DATA,_COMMON} via content iface (snapcore#2063) - interfaces: add Plug/Slot/Connection reference helpers (snapcore#2056) - client,daemon,cmd/snap: improve create-user APIs (snapcore#2054) - many: introduce snap refresh --ignore-validation <snap> to override refresh validation (snapcore#2052) - daemon: add support for `snap create-user --known` (snapcore#2040) - interfaces/policy: start of interface policy checking code based on declarations (snapcore#2050) - overlord/configstate: support nested configuration (snapcore#2039) - asserts,interfaces/builtin,overlord/assertstate: introduce base- declaration (snapcore#2037) - interfaces: builtin: Allow writing DHCP lease files to /run/NetworkManager/dhcp (snapcore#2049) - many: remove all traces of the /v2/buy/methods endpoint (snapcore#2045) - tests: add external spread backend (snapcore#1918) - asserts: parse the slot rules in snap-declarations (snapcore#2035) - interfaces: allow read of /etc/ld.so.preload by default for armhf on series 16 (snapcore#2048) - store: change purchase to order and store clean up first pass (snapcore#2043) - daemon, store: switch to new store APIs in snapd (snapcore#2036) - many: add email to UserState (snapcore#2038) - asserts: support parsing the plugs stanza i.e. plug rules in snap- declarations (snapcore#2027) - store: apply deltas if explicitly enabled (snapcore#2031) - tests: fix create-key/snap-sign test isolation (snapcore#2032) - snap/implicit: don't restrict the camera iface to clasic (snapcore#2025) - client, cmd: change buy command to match UX document (snapcore#2011) - coreconfig: nuke it. Also, ignore po/snappy.pot. (snapcore#2030) - store: download deltas if explicitly enabled (snapcore#2017) - many: allow use of the system user assertion with create-user (snapcore#1990) - asserts,overlord,snap: add prepare-device hook for device registration (snapcore#2005) - debian: adjust packaging for trusty/deputy systemd (snapcore#2003) - asserts: introduce AttributeConstraints (snapcore#2015) - interface/builtin: access system bus on screen-inhibit-control - tests: add firewall-control interface test (snapcore#2009) - snapstate: pass errors from ListRefresh in updateInfo (snapcore#2018) - README: add links to IRC, mailing list and social media (snapcore#2022) - docs: add `configure` hook to hooks list (snapcore#2024)LP: #1596629 - cmd/snap,configstate: rename apply-config variables to configure. (snapcore#2023) - store: retry download on 500 (snapcore#2019) - interfaces/builtin: support time and date settings via 'org.freedesktop.timedate1 (snapcore#1832)
This drops the firstboot systemd job we currently have and replace it with code inside snapd itself.