cloud-init-dev team mailing list archive
-
cloud-init-dev team
-
Mailing list archive
-
Message #01288
Re: [Merge] ~raharper/cloud-init:snapuser-create into cloud-init:master
On Wed, Oct 19, 2016 at 8:04 AM, Scott Moser <smoser@xxxxxxxxxx> wrote:
> over all, looks good.
> you dont have to clean up the handle, but if you see easy way to do that
> that'd be nice.
>
> is the snappy path now valid on non-snappy system ? (ubuntu server with
> 'snap' support).
>
It is, and util.is_system_snappy() I think passes where it works; I'll
confirm.
>
>
> lastly, please just review your commit message and make sure its up to
> date with all changes (it may well be, just think you made some changes
> since you wrote it).
>
ACK, it needs updating to account for the snappy: namespace changes.
>
>
> Diff comments:
>
> > diff --git a/cloudinit/config/cc_snap_config.py
> b/cloudinit/config/cc_snap_config.py
> > new file mode 100644
> > index 0000000..667b9c6
> > --- /dev/null
> > +++ b/cloudinit/config/cc_snap_config.py
> > @@ -0,0 +1,177 @@
> > +# vi: ts=4 expandtab
> > +#
> > +# Copyright (C) 2016 Canonical Ltd.
> > +#
> > +# Author: Ryan Harper <ryan.harper@xxxxxxxxxxxxx>
> > +#
> > +# This program is free software: you can redistribute it and/or
> modify
> > +# it under the terms of the GNU General Public License version 3, as
> > +# published by the Free Software Foundation.
> > +#
> > +# This program is distributed in the hope that it will be useful,
> > +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > +# GNU General Public License for more details.
> > +#
> > +# You should have received a copy of the GNU General Public License
> > +# along with this program. If not, see <
> http://www.gnu.org/licenses/>.
> > +
> > +"""
> > +Snappy
> > +------
> > +**Summary:** snap_config modules allows configuration of snapd.
> > +
> > +This module uses the same ``snappy`` namespace for configuration but
> > +acts only only a subset of the configuration.
> > +
> > +If ``assertions`` is set and the user has included a list of assertions
> > +then cloud-init will collect the assertions into a single assertion file
> > +and invoke ``snap ack <path to file with assertions>`` which will
> attempt
> > +to load the provided assertions into the snapd assertion database.
> > +
> > +If ``email`` is set, this value is used to create an authorized user for
> > +contacting and installing snaps from the Ubuntu Store. This is done by
> > +calling ``snap create-user`` command.
> > +
> > +If ``known`` is set to True, then it is expected the user also included
> > +an assertion of type ``system-user``. When ``snap create-user`` is
> called
> > +cloud-init will append '--known' flag which instructs snapd to look for
> > +a system-user assertion with the details. If ``known`` is not set, then
> > +``snap create-user`` will contact the Ubuntu SSO for validating and
> importing
> > +a system-user for the instance.
> > +
> > +.. note::
> > + If the system is already managed, then cloud-init will not attempt
> to
> > + create a system-user.
> > +
> > +**Internal name:** ``cc_snap_config``
> > +
> > +**Module frequency:** per instance
> > +
> > +**Supported distros:** ubuntu
> > +
> > +**Config keys**::
> > +
> > + #cloud-config
> > + snappy:
> > + assertions:
> > + - |
>
> should we support assertions as a dictionary ?
> it seemed that an assertion is in fact a dictionary, why not allow the
> user to provide it as one rather than a yaml rendered blob, and then we can
> render it.
>
It's not a dictionary, unfortunately; it's a stream of text separated by
newlines;
The format of an assertion is defined here, if you like:
https://github.com/snapcore/snapd/blob/master/asserts/asserts.go#L304
So, each entry in the list is blob of one or more assertions. For example
you can do the following:
snap download hello
vi hello_*.snap.assertions
And see there are roughly 5 or so assertions in that single file.
>
> > + <assertion 1>
> > + - |
> > + <assertion 2>
> > + email: user@xxxxxxxx
> > + known: true
> > +
> > +"""
> > +
> > +from cloudinit import log as logging
> > +from cloudinit.settings import PER_INSTANCE
> > +from cloudinit import util
> > +
> > +LOG = logging.getLogger(__name__)
>
> logexc is really just for logging an exception. with a traceback to the
> log. agreed its a kind of weird function (taking a logger).
>
not following this feedback. I want a logger so I can call LOG.NNN
>
> > +
> > +frequency = PER_INSTANCE
> > +SNAPPY_CMD = "snap"
> > +ASSERTIONS_FILE = "/var/lib/cloud/instance/snapd.assertions"
> > +
> > +distros = ['ubuntu']
>
> is this just ubuntu? or any distro with snap?
>
Could be other distros with snap. I don't have an exhaustive list yet.
>
> > +
> > +
> > +def set_snappy_command():
> > + global SNAPPY_CMD
> > + if util.which("snappy-go"):
> > + SNAPPY_CMD = "snappy-go"
> > + elif util.which("snappy"):
> > + SNAPPY_CMD = "snappy"
> > + else:
> > + SNAPPY_CMD = "snap"
> > + LOG.debug("snappy command is '%s'", SNAPPY_CMD)
> > +
> > +
> > +"""
> > +snappy:
> > + assertions:
> > + - |
> > + <snap assertion 1>
> > + - |
> > + <snap assertion 2>
> > + email: foo@xxxxxx
> > + known: true
> > +"""
> > +
> > +
> > +def add_assertions(assertions):
> > + """ Import list of assertions by concatenating each
> > + assertion into a string separated by a '\n'.
> > + Write this string to a instance file and
> > + then invoke `snap ack /path/to/file`
> > + and check for errors.
> > +
> > + If snap exits 0, then all assertions are imported.
> > + """
> > + if not assertions:
>
> the other thing that this sort of thing does (not necessarily here) is
> avoid a trap on python object initialization.
>
> def foo(mylist=[])
> mylist.append("foo")
> return mylist
>
> calling that multiple times like this:
> mylist()
> ret = mylist()
>
> will actually update the '[]' list. so thats wy we often do the:
> def foo(mylist=None)
> if foo is None:
> foo = []
>
ACK, will fix.
>
> > + assertions = []
> > +
> > + if not isinstance(assertions, list):
> > + raise ValueError('assertion parameter was not a list: %s',
> assertions)
> > +
> > + snap_cmd = [SNAPPY_CMD, 'ack']
> > + combined = "\n".join(assertions)
> > + if len(combined) == 0:
> > + raise ValueError("Assertion list is empty")
> > +
> > + for asrt in assertions:
> > + LOG.debug('Acking: %s', asrt.split('\n')[0:2])
> > +
> > + util.write_file(ASSERTIONS_FILE, combined.encode('utf-8'))
> > + util.subp(snap_cmd + [ASSERTIONS_FILE], capture=True)
> > +
> > +
> > +def handle(name, cfg, cloud, log, args):
> > + cfgin = cfg.get('snappy')
> > + if not cfgin:
> > + LOG.debug('No snappy config provided, skipping')
> > + return
> > +
> > + if not(util.system_is_snappy()):
> > + LOG.debug("%s: system not snappy", name)
> > + return
> > +
> > + set_snappy_command()
> > +
> > + assertions = cfgin.get('assertions', [])
> > + if len(assertions) > 0:
> > + LOG.debug('Importing user-provided snap assertions')
> > + add_assertions(assertions)
> > +
> > + # Create a snap user if requested.
>
> the less you do in a 'handle' the easier test is in myopinion.
> you can add a metdho that does this hunk of code below and then unit test
> it by itself and avoid the wierd signature of handle.
>
ACK, will move.
>
> > + # Snap systems contact the store with a user's email
> > + # and extract information needed to create a local user.
> > + # A user may provide a 'system-user' assertion which includes
> > + # the required information. Using such an assertion to create
> > + # a local user requires specifying 'known: true' in the supplied
> > + # user-data.
> > + snapuser = cfgin.get('email', None)
> > + if snapuser:
> > + usercfg = {
> > + 'snapuser': snapuser,
> > + 'known': cfgin.get('known', False),
> > + }
> > +
> > + # query if we're already registered
> > + out, _ = util.subp([SNAPPY_CMD, 'managed'], capture=True)
> > + if out.strip() == "true":
> > + LOG.warning('This device is already managed. '
> > + 'Skipping system-user creation')
> > + return
> > +
> > + if usercfg.get('known'):
> > + # Check that we imported a system-user assertion
> > + out, _ = util.subp([SNAPPY_CMD, 'known', 'system-user'],
> > + capture=True)
> > + if len(out) == 0:
> > + LOG.error('Missing "system-user" assertion. '
> > + 'Check "snappy" user-data assertions.')
> > + return
> > +
> > + cloud.distro.create_user(snapuser, **usercfg)
> > diff --git a/cloudinit/config/cc_snappy.py b/cloudinit/config/cc_snappy.
> py
> > index 36db9e6..e03ec48 100644
> > --- a/cloudinit/config/cc_snappy.py
> > +++ b/cloudinit/config/cc_snappy.py
> > @@ -257,24 +257,14 @@ def disable_enable_ssh(enabled):
> > util.write_file(not_to_be_run, "cloud-init\n")
> >
> >
> > -def system_is_snappy():
> > - # channel.ini is configparser loadable.
> > - # snappy will move to using /etc/system-image/config.d/*.ini
> > - # this is certainly not a perfect test, but good enough for now.
> > - content = util.load_file("/etc/system-image/channel.ini",
> quiet=True)
> > - if 'ubuntu-core' in content.lower():
> > - return True
> > - if os.path.isdir("/etc/system-image/config.d/"):
> > - return True
> > - return False
> > -
> > -
> > def set_snappy_command():
> > global SNAPPY_CMD
> > if util.which("snappy-go"):
> > SNAPPY_CMD = "snappy-go"
> > - else:
> > + elif util.which("snappy"):
> > SNAPPY_CMD = "snappy"
> > + else:
> > + SNAPPY_CMD = "snap"
>
> we could probably drop legacy snappy . that path would only be taken on
> 15.04 , right?
>
Possibly; I just don't know if someone builds a new cloud-init and runs on
an older system.
I've never tested anything but the current snapd/all-snap systems.
It's certainly likely that a system that has 'snappy' won't have any of the
commands I use:
create-user, managed, known, ack
I wonder if we should confirm we have those sub commands in snapd or just
let it fail
naturally?
>
> > LOG.debug("snappy command is '%s'", SNAPPY_CMD)
> >
> >
>
>
> --
> https://code.launchpad.net/~raharper/cloud-init/+git/
> cloud-init/+merge/304700
> You are the owner of ~raharper/cloud-init:snapuser-create.
>
--
https://code.launchpad.net/~raharper/cloud-init/+git/cloud-init/+merge/304700
Your team cloud init development team is requested to review the proposed merge of ~raharper/cloud-init:snapuser-create into cloud-init:master.
Follow ups
References