Please review design for automated server installs

Well I would argue that if you’re using an installer in a VM you’re doing things a bit wrong. Why not use a cloud image?

or also just logging to the console and not having any tui running.

This is my current half-baked plan, yes.

mwhudson:

I’ve updated the docs to add error_commands and reporting sections to the config, made some clarifications to the descriptions of early_commands and late_commands and added something about cloud-init config to ‘possible future directions’

This is a useful change and along with the logging above addresses concerns I initially had about the lack of handling for error cases in the script.

TBH I hadn’t considered the error cases nearly as much as I should have. Score one for asking for feedback!

Not discussed so far and one use case I’m particularly interested in is the ability to install in an isolated or offline network environment, yet have the resulting image be correctly configured to work with e.g. dhcp on boot and have the default repositories set up.

So this should just work™ with the way things are put together in subiquity. The default is to run DHCP on all wired interfaces but only configure it in the target system for interfaces that got a response but this can be overridden.

When trying to do this with preseeding, the installation environment bleeds over into the runtime environment so e.g. if you install without a network the network then isn’t automatically set up in the target, or if you use repositories on a provisioning network the target expects to use those same repositories on boot, which isn’t what I’d like.

So the part about repositories isn’t supported yet – if there is no network at install time, the install process runs with just the repository on the install media available – but it would be fairly simple to add (after all, I had to implement a way to have different apt config for install time to implement the current behaviour). And I guess you can always reconfigure the repository in a late_command.

My main motivation for that use case is to have somewhat reproducible images which are built in an isolated environment and then deployed separately instead of e.g. installing with an internet connection and the installation image having updates installed during the installation, resulting in a different image each time you run the installation script. If this use case can be supported that would be great.

Makes some sense, although in general we do want people to install at least security updates!

A couple quick comments. I agree with a couple others that I usually need a semi-automated install, answering a few questions here or there that are unique to each installation (static IPs as was mentioned but also disk layout and formatting). I’ve used d-i preseeding in this manner quite successfully up to this point. Would there be a way for the new server installer to support a semi-automated mode like this?

Is it required that a user identity be created during installation? I normally allow root login and don’t populate user accounts until later using configuration management with specific UIDs, GIDs, etc.

Well, anything is possible… If you’re not providing values for the networking and disk layout, what are you providing answers for? Proxy/default repository I guess? Would it be OK to be able to change the default here vs providing a value and not asking the question?

In any case, I’ll keep this use case in mind. I don’t see why it would be particularly difficult to support.

Is it required that a user identity be created during installation? I normally allow root login and don’t populate user accounts until later using configuration management with specific UIDs, GIDs, etc.

Without thinking about this terribly hard, I think I’d prefer to handle this use case by allowing the admin to provide a complete cloud-init config for themselves. Would that make sense for you?

Hi all, I’ve made some updates to the spec to allow providing cloud-init config, and semi-interactive installs. I think looking at https://wiki.ubuntu.com/FoundationsTeam/AutomatedServerInstalls?action=diff&rev2=37&rev1=33 and https://wiki.ubuntu.com/FoundationsTeam/AutomatedServerInstalls/ConfigReference?action=diff&rev2=14&rev1=10 should give a sense of what I’ve changed.

I checked out the diffs and the changes look like they’ll meet our needs. It does seem strange, though, to use cloud-init just to avoid having to specify a user identity. But as long as there is a way to do it, I’m happy

Yes. There are, obviously, advantages and drawbacks to such an approach but, in general, I find that having all related configuration data in a “standard” space helps more than hinders.

This makes sense I guess. Can you give some examples of how you think this might look?

Apologies for the late reply.

Heh, a fair point, but there are a few reasons why you might want to install in a VM evironment.

For example, if you want a different filesystem layout/filesystem choice. That’s like a line or two in an installer, more effort with a could image/tarball. A use case for that would be e.g. creating a few of ubuntu VMs with different filesystems for benchmarking purposes.

Another slightly oddball use case is installing an image in a VM to be used on a bare metal machine. Installing via bare metal takes a while, mostly due to big servers taking minutes to get to the point they can even boot linux. Instead you could e.g. install in a VM environment with an iSCSI disk, then boot the bare metal machine with the disk you used in the VM. It’s a bit crazy, but it does work as long as you’re careful about your disk/network setup in the VM being not too dissimilar from bare metal.

And finally, just from a testing/development point of view surely doing a VM install makes sense?

Understood, a late_command is a viable alternative, it’s just one less thing to do though if the installer takes care of it.

Totally, the default should definitely be to have a fully updated system with all security updates applied. It’s really just about having the option not to do that.

Apologies for the late reply.

No worries, I haven’t done any actual implementation work on this yet.

Well I would argue that if you’re using an installer in a VM you’re doing things a bit wrong. Why not use a cloud image?

Heh, a fair point, but there are a few reasons why you might want to install in a VM evironment.

Oh sure, I don’t want to say that it’s not a supported thing to do or anything like that. But in general, installing to a VM is a slightly strange way of going about things, so I’m not sure support for VM-only things like logging via a virtio char device is really worth it (that example is also probably not very much effort so maybe it would be!)

For example, if you want a different filesystem layout/filesystem choice. That’s like a line or two in an installer, more effort with a could image/tarball. A use case for that would be e.g. creating a few of ubuntu VMs with different filesystems for benchmarking purposes.

Another slightly oddball use case is installing an image in a VM to be used on a bare metal machine. Installing via bare metal takes a while, mostly due to big servers taking minutes to get to the point they can even boot linux. Instead you could e.g. install in a VM environment with an iSCSI disk, then boot the bare metal machine with the disk you used in the VM. It’s a bit crazy, but it does work as long as you’re careful about your disk/network setup in the VM being not too dissimilar from bare metal.

I guess these make some kinds of sense :slight_smile: Neither necessarily seem like a use case for automated installs though…

And finally, just from a testing/development point of view surely doing a VM install makes sense?

Oh yes, I certainly do this a lot!

Overall the design seems very straightforward and easy to understand which I really like. There does seem to be a difference in how network: is handled versus filesystem:. network: is a complete pass through to netplan (which is great) where as the filesystem: is not a complete pass through to curtin the installer used under the hood.

While I do like that filesystem: allows the layouts and the automated server installer will then build a simple curtin layout, it would be nice to support a passthrough method just like network: passes through to netplan.

Curtin uses the key storage: to define the storage layout could the automated server installer support either storage: or filesystem: for those wanting to provide very specific storage layout configuration. In the case that both are provided it could be an error or storage could take precendence over filesystem: with a warning about that choice.

Thanks for the comments!

Yay!

There does seem to be a difference in how network: is handled versus filesystem:. network: is a complete pass through to netplan (which is great) where as the filesystem: is not a complete pass through to curtin the installer used under the hood.

So maybe I’ve been unclear here. The idea is very much that anything that is valid curtin storage config can go under filesystem: and just be passed through. What’s different to network/netplan is that the syntax is extended to allow other things (basically, netplan supports some degree of wildcarding natively, curtin does not). BTW, exactly how this extension of curtin syntax will work is the part of all this I am fuzziest on, if people have thoughts on how it should work in detail I’m all ears.

While I do like that filesystem: allows the layouts and the automated server installer will then build a simple curtin layout, it would be nice to support a passthrough method just like network: passes through to netplan.

As above, that’s the plan.

Curtin uses the key storage: to define the storage layout could the automated server installer support either storage: or filesystem: for those wanting to provide very specific storage layout configuration. In the case that both are provided it could be an error or storage could take precendence over filesystem: with a warning about that choice.

Do you mean the difference between block-meta simple and block-meta custom here? Subiquity currently always generates a config that puts curtin into custom mode. And hmmmmm I’d forgotten that simple and custom are configured by different top-level keys (“storage” for custom and “block-meta” for simple) so I think I see what you meant above now (and we can’t do a neat thing of just transplanting what’s under a key in the autoinstall file to some key in the curtin config). So let me brain dump for a bit:

There are three broad types of filesystem configuration we might expect the user to supply:

  1. configuration for the curtin’s block-meta simple mode
  2. configuration for curtin’s block-meta custom mode (actually probably some extension of this)
  3. one of the guided layouts such as lvm or lvm-luks

We could do this just by looking at which keys are present under the filesystem: top-level key: ‘block-meta’ for block meta simple, ‘config’ (and version?) for block-meta custom, ‘layout’ for a guided layout (and handle more than one of these being present by either defining a precedence or erroring). This seems simple enough.

Would you want the configuration for block-meta simple to support wildcarding in any sense?

I think in almost all cases you will need some type of matching either with wildcarding and/or regexing to make the storage selection flexible enough to be useful.

Being that netplan does support some form of wildcarding why not push that same level of support to curtin that way others benefit from that versus only adding it in the automated server installer. That would give more consistency in the installer being that it just consistently relies on the underlying tools to do the hard work.

Based on the current YAML design how is the code going to be able to distinguishes between the 3 different ways your describe storage can be defined. Seems very vague to me at the moment and a clear design there would be beneficial before implementation. It would also help to ensure that it could easily be validated before hand.

The block-meta mode can be specified, but it typically is derived from the presence of ‘storage’ config. The logic curtin implements looks like this:

  1. if the install source is a dd-able image, then we always use meta-simple path
  2. if ‘storage’ is present and the user isn’t setting the force-mode flag, we use meta-custom
  3. use the mode specified by the user.

Note, in meta-simple, curtin will look at storage-config (if present) to determine which disk should be the boot disk.

Generally, meta-simple enumerates host block devices, picks a target disk (ignoring multipath, mounted devices and such) will create a single partition, put ext4 on it and make it bootable.

I can’t think of a case where subiquity would ever not pass a storage config to curtin, so we’ll definitely down the meta-custom path. I don’t think subiquity should accept any block-meta keys; only accept ‘storage’ or ‘filesystems’ in the absence of ‘storage’.

W.r.t the wildcarding, this has been suggested. In particular areas that could utilize some abstract values are:

  • sizes for partitions, raids, lvms (accepting percentages)
  • disk serial/wwn/path values

[comment amended to remove the confusion between answers.yaml and autoinstall.]

Hi, just a question on:

when the answer to a question is not present in a preseed, d-i stops and asks the user for input. autoinstalls are not like this: by default, if there is any autoinstall config at all, the installer takes the default for any unanswered question (and fails if there is no default).

What happens if subiquity refreshes and introduces a new question with no default? I think this would break existing autoinstalling setups, making them stop at the new question. Can we prevent this from happening? We could require defaults for each question, but there are cases where defaults don’t really make sense (e.g. the user’s password).

Right. We’d better avoid doing this then!

I don’t think there’s any overarching approach here and I’m not sure what is even possible. If we add new questions, we should avoid adding ones that don’t have defaults. If we have to add a question with no default (and I really can’t think why we’d do that), then yes, everyone gets to update their configs. Which sucks, which is why we should try to avoid doing it.

It would be nice to have also a ‘file’ boot option for preseeding in addition to the ‘url’ option and the fixed /autoinstall.yaml path. Consider the following use case:

an usb bootable disk with one or more official ubuntu iso images (unmodified) and one or more grub menu entries specifying different preseed files for different types of installation. The preseed files would preferably be installed in the filesystem of the usb disk and not inside the iso or initrd, which should be left unchanged. For example:

menuentry "Install 1" {
    loopback loop /ubuntu/ubuntu-20.04-server.iso
    linux (loop)/casper/vmlinuz iso-scan/filename=/ubuntu/ubuntu-20.04-server.iso file=/isodevice/configs/autoinstall-1.yaml 
    initrd (loop)/casper/initrd
}
menuentry "Install 2" {
    loopback loop /ubuntu/ubuntu-20.04-server.iso
    linux (loop)/casper/vmlinuz iso-scan/filename=/ubuntu/ubuntu-20.04-server.iso file=/isodevice/configs/autoinstall-2.yaml 
    initrd (loop)/casper/initrd
}

where /isodevice should be the mount point of the usb partition where the iso is found by the installer and loop mounted on /cdrom.

Your proposed design provides a fixed /autoinstall.yaml file on a filesystem with label “autoinstall”, but in this way we can’t have more than one preseed on the same install media. With a file option we could select different files on the same media. Also file=“LABEL=<label>/<path>” or “UUID=<uuid>/<path>” would be even better.

Hmm, that’s an interesting idea. I’ll think about it!

One thing that I’d like to see is a document / page which provides a few complete examples of an autoinstall.yaml file. Having a complete example will help piece together all of the various options, and will also help with getting the proper indentation for each of the components.

I agree with dz1. A ‘file’ parameter similar to the one used for Debian installer preseed which can be passed with the boot command would be nice.

It would also be helpful if we can pass in additional custom parameters with the boot command and use those parameter within autoinstall.yaml.

Does early_command/late_command/error_command support running scripts from the usb drive?

My use case would be to have a usb drive with multiple unmodified isos, only one autoinstall.yaml, and multiple install scripts which is specified by different grub menu entries.

Grub menu would look like:

menuentry “Install K8S” {
loopback loop /ubuntu1804.iso
iso-scan/filename=/ubuntu1804.iso
linux (loop)/casper/vmlinuz boot=casper
initrd (loop)/casper/initrd
file=/root/isodevice/autoinstall.yaml
early_script=/root/isodevice/someConfigCheck
late_script=/root/isodevice/installK8s
}

autoinstall.yaml would look like:

version: 1
early-commands:
- ${early_script}.sh
identity:
username: xxxx
password: $crypted_pass
late-commands:
- curtin in-target – ${late_script}.sh

For people following this topic but not the server category generally, I’ve just posted an update Cloud-init and the live server installer that is relevant to some of the recent posts.

As for examples: yes clearly we need them. I should probably try to write up some hypothetical ones (and they try to keep them up to date as things inevitably shift slightly when the implementation actually happens).