Recent changes to this wiki:

merged libvirt
diff --git a/debian/changelog b/debian/changelog
index e9c8bb00..99236fff 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,6 +1,7 @@
 propellor (5.5.1) UNRELEASED; urgency=medium
 
   * Some openbsd portability fixes. Thanks, rsiddharth.
+  * Added Libvirt module. Thanks, Sean Whitton.
 
  -- Joey Hess <id@joeyh.name>  Tue, 23 Oct 2018 11:37:16 -0400
 
diff --git a/doc/todo/support_for_libvirt_KVM_VMs/comment_13_066d41df795b69e096487ae7334824d0._comment b/doc/todo/support_for_libvirt_KVM_VMs/comment_13_066d41df795b69e096487ae7334824d0._comment
new file mode 100644
index 00000000..07b32566
--- /dev/null
+++ b/doc/todo/support_for_libvirt_KVM_VMs/comment_13_066d41df795b69e096487ae7334824d0._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 13"""
+ date="2018-11-11T20:58:35Z"
+ content="""
+I've merged the branch, unsure if this should remain open for anything
+discussed above, so leaving it for now.
+"""]]

Added a comment
diff --git a/doc/todo/support_for_libvirt_KVM_VMs/comment_12_2a42bef328b8dc17754050e3cdb7e7d2._comment b/doc/todo/support_for_libvirt_KVM_VMs/comment_12_2a42bef328b8dc17754050e3cdb7e7d2._comment
new file mode 100644
index 00000000..84fa1ada
--- /dev/null
+++ b/doc/todo/support_for_libvirt_KVM_VMs/comment_12_2a42bef328b8dc17754050e3cdb7e7d2._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="comment 12"
+ date="2018-11-10T23:29:35Z"
+ content="""
+(Hmm, here on Debian stretch, passing `--autostart` does not actually cause the VM to be marked for autostarting.  This is a bug in virt-install, though, as we're using the command line interface as documented --  I confirmed this using `PROPELLOR_DEBUG=1`.)
+"""]]

Added a comment
diff --git a/doc/todo/support_for_libvirt_KVM_VMs/comment_11_feec29fe99528e66b0cbc0388793e10e._comment b/doc/todo/support_for_libvirt_KVM_VMs/comment_11_feec29fe99528e66b0cbc0388793e10e._comment
new file mode 100644
index 00000000..97467c3b
--- /dev/null
+++ b/doc/todo/support_for_libvirt_KVM_VMs/comment_11_feec29fe99528e66b0cbc0388793e10e._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="comment 11"
+ date="2018-11-10T23:17:52Z"
+ content="""
+All done, I think.  Thank you for a useful review.  Commit messages and comments should explain my changes.
+"""]]

code review
diff --git a/doc/todo/support_for_libvirt_KVM_VMs/comment_10_b48444a7ec6a69019a2fda927925cac1._comment b/doc/todo/support_for_libvirt_KVM_VMs/comment_10_b48444a7ec6a69019a2fda927925cac1._comment
new file mode 100644
index 00000000..9b142dcd
--- /dev/null
+++ b/doc/todo/support_for_libvirt_KVM_VMs/comment_10_b48444a7ec6a69019a2fda927925cac1._comment
@@ -0,0 +1,40 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""code review"""
+ date="2018-11-06T14:59:06Z"
+ content="""
+Let's comment out the QCow2 constructor until that case is handled.
+
+With NumVCPUs and MiBMemory both Int, and used in the same property, they
+could get mixed up. Recommend newtypes.
+
+Would it make sense for defaultNetworkAutostarted
+to itself run the virsh net-start? It would simplify the example.
+
+It's named kvmDefined; is it actually guaranteed to use kvm and not some other VM?
+
+What happens when osVariant is Nothing and no --os-variant is passed?
+When osType is Nothing? Is it still likely to work?
+
+Please make osType not have a default case and define it for all the
+current constructors. That way, the next person to
+add an Linux distro to propellor won't forget to update it.
+
+The chroot nuking code depends on some implementation details in DiskImage,
+so I'd be inclined to move it to that module. (Which probably has similar
+code that can be factored out.)
+
+The "defined" scriptProperty uses a lot of values that are unlikely to
+contain spaces or other script unsafe stuff, but it would still be good to
+shellEscape them. (Or it could be rewritten to run virt-install w/o a
+shell, read its output, and write the file.)
+
+The "started" scriptProperty also needs some escaping. (Although I'd be
+inclined to parse virsh list in haskell, but up to you.)
+
+Minor: The `& Libvirt.defaultNetworkAutostarted` example line is currently
+indented by spaces while the other lines use tabs.
+
+Minor: I'd use `$` in some of the places where you have a parenthesized
+do block or other multiline block of code.
+"""]]

Added a comment
diff --git a/doc/todo/support_for_libvirt_KVM_VMs/comment_9_4ba83dedf873a1a70fc050f22fca343e._comment b/doc/todo/support_for_libvirt_KVM_VMs/comment_9_4ba83dedf873a1a70fc050f22fca343e._comment
new file mode 100644
index 00000000..94f2ef9b
--- /dev/null
+++ b/doc/todo/support_for_libvirt_KVM_VMs/comment_9_4ba83dedf873a1a70fc050f22fca343e._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="comment 9"
+ date="2018-11-06T03:12:26Z"
+ content="""
+Thanks.  I've now implemented enough of this to support my usecase in the libvirt branch of <https://git.spwhitton.name/propellor>.
+
+There are TODOs, but now seems as good a time as any for someone to implement the qcow2 support . . .
+
+With regard to your idea, taking down the VM and running propellor on the qcow2 file seems like it will not be useful to very many people.  ISTM that treating the VM as a host and spinning it is right.
+"""]]

feedback
diff --git a/doc/todo/support_for_libvirt_KVM_VMs/comment_8_f7ceb2909d6884a9b13500b7c660469a._comment b/doc/todo/support_for_libvirt_KVM_VMs/comment_8_f7ceb2909d6884a9b13500b7c660469a._comment
new file mode 100644
index 00000000..0af0baaa
--- /dev/null
+++ b/doc/todo/support_for_libvirt_KVM_VMs/comment_8_f7ceb2909d6884a9b13500b7c660469a._comment
@@ -0,0 +1,23 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 8"""
+ date="2018-11-05T16:40:57Z"
+ content="""
+Seems that kvmRunning would need a warning that changes to the propellor
+configuration of the VM's Host won't affect the VM. Because it's unusual for
+propellor to only be able to set something up and not change it afterwards.
+
+But kvmRunning is certianly a useful low level property, and combining with
+other properties like that is good.
+
+Hmm, it's actually possible to mount a qcow2 image using libguestfs-tools.
+<http://ask.xmodulo.com/mount-qcow2-disk-image-linux.html>
+So, propellor could temporarily take down the VM and run inside the qcow2
+to update it! Although doing that every time propellor is run seems
+suboptimal. It could keep the chroot around and only update the qcow2 image
+if the chroot needed to be updated. I am not sure how I feel about that
+idea.
+
+We could also make conducting easier to set up, perhaps not needing `main`
+to be modified to use it.
+"""]]

Added a comment: New design: requesting feedback
diff --git a/doc/todo/support_for_libvirt_KVM_VMs/comment_7_246609ff0b30329fe64fe1c100b62c45._comment b/doc/todo/support_for_libvirt_KVM_VMs/comment_7_246609ff0b30329fe64fe1c100b62c45._comment
new file mode 100644
index 00000000..1aa82a09
--- /dev/null
+++ b/doc/todo/support_for_libvirt_KVM_VMs/comment_7_246609ff0b30329fe64fe1c100b62c45._comment
@@ -0,0 +1,49 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="New design: requesting feedback"
+ date="2018-11-04T17:39:51Z"
+ content="""
+Having slept on it, and also looked at some more of virt-install(1), I have a new design.  I'd be grateful for feedback on this, before implementation.
+
+We have two properties: `Libvirt.kvmRunning` and `Libvirt.kvmRunningConducted`, where
+
+    kvmRunningConnected host = conducts host `requires` kvmRunning host
+
+The basic reason for separating these two properties is that for the conducting to work, various network things have to be set up, and there isn't a configuration that it would be sensible to have as a default.  More generally, libvirt isn't at all suited to declarative configuration.  What propellor can do well is build an image and have libvirt generate a barebones XML configuration file to boot the image.  This is what `Libvirt.kvmRunning` will do.  After that, we're going to have to leave it up to the user.  I suspect that outside of the very simplest cases, they are going to have to make a series of virsh(1) calls, using `flagFile` to ensure that it only happens once.
+
+`Libvirt.kvmRunning` will work like this:
+
+1. ensure libvirt etc. are installed
+2. build the image if it doesn't exist
+3. nuke the chroot used to build the image
+3. if VM config does not exist,
+    1. `virt-install -n vm-hostname --description \"vm-hostname VM\" --os-type=Linux --os-variant=debian9 --ram=1024 --vcpus=2 --autostart --disk path=/var/lib/libvirt/images/vm-hostname.img,device=disk,bus=virtio --import --print-xml >/tmp/foo`
+    2. `virsh define /tmp/foo`
+        - `virt-install --print-xml` and then `virsh define` avoids the problem of virt-install not exiting until after the VM has been shutdown at least once/the virt-viewer instance launched by virt-install has been closed
+    3. `virsh start vm-hostname`
+
+Sample usage:
+
+    laptop :: Host
+    laptop = host \"iris.silentflame.com\" $ props
+    	& osDebian (Stable \"stretch\") X86_64
+    	& Libvirt.kvmRunning Raw 1GB 2 develacc -- specification of image type, RAM and vCPUs to assign
+    
+    develacc :: Host
+    develacc = host \"develacc.iris.silentflame.com\" $ props
+    	& osDebian Unstable X86_64
+    	& hasPartition
+    		( partition EXT4
+    			`mountedAt` \"/\"
+    			`addFreeSpace` MegaBytes 10240
+    		)
+    	& Apt.installed [\"linux-image-amd64\"]
+    	& Grub.installed PC
+    
+    	& ipv4 \"192.168.122.31\"
+    	& Network.static \"ens3\" (IPv4 \"192.168.122.31\")
+    		(Just (Network.Gateway (IPv4 \"192.168.122.1\")))
+    		`requires` Network.cleanInterfacesFile
+    	& Hostname.sane
+"""]]

Added a comment: creating the libvirt VM
diff --git a/doc/todo/support_for_libvirt_KVM_VMs/comment_6_9c2792cec842dba7a8fabb24c2c33da0._comment b/doc/todo/support_for_libvirt_KVM_VMs/comment_6_9c2792cec842dba7a8fabb24c2c33da0._comment
new file mode 100644
index 00000000..931b21fe
--- /dev/null
+++ b/doc/todo/support_for_libvirt_KVM_VMs/comment_6_9c2792cec842dba7a8fabb24c2c33da0._comment
@@ -0,0 +1,14 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="creating the libvirt VM"
+ date="2018-11-04T01:03:06Z"
+ content="""
+I've now an adhoc, proof-of-concept libvirt VM provisioned by my config.hs, just using a raw disk image.  It turns out that propellor should not be writing the XML configuration file in /etc, but having libvirt generate it.  This is because the config is not meant to be directly edited.  So, propellor should call virt-install(1) to setup and boot the VM.
+
+My code uses virt-install's --import option, also passing it the location of the disk image generated by propellor.  The main problem is that the invocation of virt-install won't return until after the VM first shuts down; the idea is that you are running the OS installer and then you reboot.  Possibly using --boot instead of --import will help here; not sure.
+
+We will need the user to specify how much RAM and how many vCPUs to assign to the VM.  All the other parameters to virt-install can be determined by looking at the properties of the VM `Host`.
+
+Otherwise, the user will need to set an IP property on the VM so that it can be conducted.  I think we will need to leave the user to do this, as there are so many possible network configurations for libvirt VMs.  But we could probably provide helper properties.  In particular, the standard setup will be to use `Network.static`, though I'm not sure about how to do that with indeterministic interface names.
+"""]]

Added a comment
diff --git a/doc/forum/Make_clean_fails_in_openbsd/comment_2_be7daa63ed7b5689f3e626eedd2fb648._comment b/doc/forum/Make_clean_fails_in_openbsd/comment_2_be7daa63ed7b5689f3e626eedd2fb648._comment
new file mode 100644
index 00000000..ca5c4c81
--- /dev/null
+++ b/doc/forum/Make_clean_fails_in_openbsd/comment_2_be7daa63ed7b5689f3e626eedd2fb648._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="s@aa9ff9ce06b08acfd2a93ebd342ce6879430fbdd"
+ nickname="s"
+ avatar="http://cdn.libravatar.org/avatar/81bf27f8b35011d1846711fa37a5588f"
+ subject="comment 2"
+ date="2018-10-28T19:43:55Z"
+ content="""
+Apologies for the haste. I'll post patches under [[/todo]] in<br/>
+the future
+"""]]

Added a comment
diff --git a/doc/forum/__96__Propellor.Bootstrap.cabalBuild__96___fails_in_openbsd/comment_2_b9f9c1903f1a54bad8d9021702056f41._comment b/doc/forum/__96__Propellor.Bootstrap.cabalBuild__96___fails_in_openbsd/comment_2_b9f9c1903f1a54bad8d9021702056f41._comment
new file mode 100644
index 00000000..09a5b01e
--- /dev/null
+++ b/doc/forum/__96__Propellor.Bootstrap.cabalBuild__96___fails_in_openbsd/comment_2_b9f9c1903f1a54bad8d9021702056f41._comment
@@ -0,0 +1,17 @@
+[[!comment format=mdwn
+ username="s@aa9ff9ce06b08acfd2a93ebd342ce6879430fbdd"
+ nickname="s"
+ avatar="http://cdn.libravatar.org/avatar/81bf27f8b35011d1846711fa37a5588f"
+ subject="comment 2"
+ date="2018-10-28T19:43:21Z"
+ content="""
+> ...I suspect it would be sufficient to use -p?
+
+I think you're right, `-pf` should be sufficient.
+
+> If you're going to be posting a bunch of openbsd porting patches, which I hope you are, please use [[/todo]] so they don't flood the forum and so it's obvious which have been applied and which not.
+
+Apologies for the haste. I'll post patches under [[/todo]] in<br/>
+the future and take a look at [[/contributing]]. Thanks for<br/>
+pointing out.
+"""]]

patch applied
diff --git a/debian/changelog b/debian/changelog
index b2051120..e9c8bb00 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+propellor (5.5.1) UNRELEASED; urgency=medium
+
+  * Some openbsd portability fixes. Thanks, rsiddharth.
+
+ -- Joey Hess <id@joeyh.name>  Tue, 23 Oct 2018 11:37:16 -0400
+
 propellor (5.5.0) unstable; urgency=medium
 
   * letsencrypt': Pass --expand to support expanding the list of domains
diff --git a/doc/forum/__96__Propellor.Bootstrap.cabalBuild__96___fails_in_openbsd/comment_1_ccf181b032aad9134ff513878956d1b2._comment b/doc/forum/__96__Propellor.Bootstrap.cabalBuild__96___fails_in_openbsd/comment_1_ccf181b032aad9134ff513878956d1b2._comment
new file mode 100644
index 00000000..f5ac7ae0
--- /dev/null
+++ b/doc/forum/__96__Propellor.Bootstrap.cabalBuild__96___fails_in_openbsd/comment_1_ccf181b032aad9134ff513878956d1b2._comment
@@ -0,0 +1,14 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2018-10-23T15:34:56Z"
+ content="""
+Thanks for the patch. I've applied it. I suspect it would be sufficient to
+use -p?<Down>
+
+If you're going to be posting a bunch of openbsd porting patches,
+which I hope you are, please use [[todo]] so they don't flood the forum
+and so it's obvious which have been applied and which not.
+
+Also, see [[contributing]] for some other useful things to do.
+"""]]

patch applied
diff --git a/doc/forum/Make_clean_fails_in_openbsd/comment_1_27faa3850b462e8930752209f41e2c2f._comment b/doc/forum/Make_clean_fails_in_openbsd/comment_1_27faa3850b462e8930752209f41e2c2f._comment
new file mode 100644
index 00000000..c7939851
--- /dev/null
+++ b/doc/forum/Make_clean_fails_in_openbsd/comment_1_27faa3850b462e8930752209f41e2c2f._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2018-10-23T15:31:13Z"
+ content="""
+Thanks for the patch. The only thing you could have done better is post
+this in [[todo]].
+"""]]

New forum post about an issue with `Make clean` in openbsd.
diff --git a/doc/forum/Make_clean_fails_in_openbsd.mdwn b/doc/forum/Make_clean_fails_in_openbsd.mdwn
new file mode 100644
index 00000000..0f73586a
--- /dev/null
+++ b/doc/forum/Make_clean_fails_in_openbsd.mdwn
@@ -0,0 +1,25 @@
+openbsd requires specifying the path for the [`find`][0] command. So this:
+
+    find -name \*.o
+    find: unknown option -- n
+    usage: find [-dHhLXx] [-f path] path ... [expression]
+
+
+fails.
+
+This works:
+
+
+    find . -name \*.o
+    ./dist/build/Utility/Applicative.o
+    ./dist/build/Utility/PosixFiles.o
+    ./dist/build/Utility/Split.o
+    ...
+
+
+as expected.
+
+Here's a patch for it: [0001-Makefile-Update-clean.patch][1].
+
+[0]: https://man.openbsd.org/find
+[1]: https://ricketyspace.net/patch/0001-Makefile-Update-clean.patch

New forum post about an issue with Propellor.Bootstrap.cabalBuild (patch available).
diff --git a/doc/forum/__96__Propellor.Bootstrap.cabalBuild__96___fails_in_openbsd.mdwn b/doc/forum/__96__Propellor.Bootstrap.cabalBuild__96___fails_in_openbsd.mdwn
new file mode 100644
index 00000000..c66bbc23
--- /dev/null
+++ b/doc/forum/__96__Propellor.Bootstrap.cabalBuild__96___fails_in_openbsd.mdwn
@@ -0,0 +1,6 @@
+The `-a` option is unfortunately [not available in openbsd's version][1] of the `cp` command.
+
+Here's a patch for it [0001-src-Update-Propellor.Bootstrap.cabalBuild.patch][2].
+
+[1]: https://man.openbsd.org/cp
+[2]: https://ricketyspace.net/patch/0001-src-Update-Propellor.Bootstrap.cabalBuild.patch

add news item for propellor 5.5.0
diff --git a/doc/news/version_5.3.4.mdwn b/doc/news/version_5.3.4.mdwn
deleted file mode 100644
index 09358138..00000000
--- a/doc/news/version_5.3.4.mdwn
+++ /dev/null
@@ -1,8 +0,0 @@
-propellor 5.3.4 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * Apt.trustsKey: Use apt-key to add key rather than manually driving gpg,
-     which seems to not work anymore.
-     Thanks, Russell Sim.
-   * Firewall: Reorder iptables parameters that are order
-     dependant to make --to-dest and --to-source work.
-     Thanks, Russell Sim"""]]
\ No newline at end of file
diff --git a/doc/news/version_5.5.0.mdwn b/doc/news/version_5.5.0.mdwn
new file mode 100644
index 00000000..360a5314
--- /dev/null
+++ b/doc/news/version_5.5.0.mdwn
@@ -0,0 +1,20 @@
+propellor 5.5.0 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+   * letsencrypt': Pass --expand to support expanding the list of domains
+   * Split mailname property out of Hostname.sane, since bad mailname
+     guesses can lead to ugly surprises. (API change)
+   * Removed HostingProvider.CloudatCost module as it lacks a maintainer.
+     (If anyone would like to maintain it, send a patch adding it back.)
+     (API change)
+   * Added Systemd.escapePath helper function useful when creating mount
+     units.
+   * Added Sudo.sudoersDFile property.
+   * Sudo.enabledFor: Write to /etc/sudoers.d/000users rather than to
+     /etc/sudoers. (Any old lines it wrote to /etc/sudoers will be removed.)
+     This fixes a potential ordering problem; the property used to append
+     the line to /etc/sudoers, but that would override more specific lines
+     in the include directory.
+   * Borg: Added UsesEnvVar.
+   * Added DiskImage.noBootloader, useful for eg, direct booting with
+     qemu. Thanks, David Bremner.
+   * Added Apt.backportInstalledMin."""]]
\ No newline at end of file

Added a comment
diff --git a/doc/forum/Adding_support_for_a_SQL_server/comment_8_2c604eb5c627c36ec68a1a7198e00710._comment b/doc/forum/Adding_support_for_a_SQL_server/comment_8_2c604eb5c627c36ec68a1a7198e00710._comment
new file mode 100644
index 00000000..0724001b
--- /dev/null
+++ b/doc/forum/Adding_support_for_a_SQL_server/comment_8_2c604eb5c627c36ec68a1a7198e00710._comment
@@ -0,0 +1,18 @@
+[[!comment format=mdwn
+ username="Nicolas.Schodet"
+ avatar="http://cdn.libravatar.org/avatar/0d7ec808ec329d04ee9a93c0da3c0089"
+ subject="comment 8"
+ date="2018-10-19T20:34:10Z"
+ content="""
+Hello,
+
+I have made a second version.
+
+About reverting `installed`, I noticed that it only removes the meta package, which is quite useless. May be I should just drop revertability on this one.
+
+The problem of installing a software just to revert a property can also be seen in `Apache.modEnabled` for exemple.
+
+Any comments are welcome.
+
+Thanks.
+"""]]

Added a comment: maybe some equivalent of CryptPassword
diff --git a/doc/forum/dm-crypt__47__LUKS_encryption_and_key_management/comment_3_a749abb97ebafd26bb695663b68673c5._comment b/doc/forum/dm-crypt__47__LUKS_encryption_and_key_management/comment_3_a749abb97ebafd26bb695663b68673c5._comment
new file mode 100644
index 00000000..f4448ddf
--- /dev/null
+++ b/doc/forum/dm-crypt__47__LUKS_encryption_and_key_management/comment_3_a749abb97ebafd26bb695663b68673c5._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="maybe some equivalent of CryptPassword"
+ date="2018-10-16T11:51:23Z"
+ content="""
+Storing plaintext luks passwords on disk doesn't sound great for most applications, but I wonder if the encrypted form could be stored in privdata. Something using e.g. \"cryptsetup luksDump\" or \"cryptsetup luksHeaderBackup\". I have no idea how practical it is to generate such data without being logged into the machine in question.
+"""]]

Added a comment: needs update-initramfs
diff --git a/doc/forum/__34__predictable__34___network_interface_names/comment_2_25a2911fa57ea3da20f25b25d7c4406b._comment b/doc/forum/__34__predictable__34___network_interface_names/comment_2_25a2911fa57ea3da20f25b25d7c4406b._comment
new file mode 100644
index 00000000..e284c8f1
--- /dev/null
+++ b/doc/forum/__34__predictable__34___network_interface_names/comment_2_25a2911fa57ea3da20f25b25d7c4406b._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="needs update-initramfs"
+ date="2018-10-14T21:03:28Z"
+ content="""
+I guess that's a more productive line of thinking, I wouldn't expect these vm's to have more than one network interface. One gotcha that took a bit to figure out is that the masking needs update-initramfs to be seen at boot. The following seems to be working for me:
+
+[[!format haskell \"\"\"
+& File.hasContent \"/etc/systemd/network/99-default.link\" []
+        `onChange` ( Cmd.cmdProperty \"update-initramfs\" [\"-u\"] `changesFile` \"/initrd.img\" )
+\"\"\"]]
+"""]]

Added Apt.backportInstalledMin.
This commit was sponsored by Boyd Stephen Smith Jr. on Patreon.
diff --git a/debian/changelog b/debian/changelog
index b0f7121b..5b283861 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -17,6 +17,7 @@ propellor (5.5.0) UNRELEASED; urgency=medium
   * Borg: Added UsesEnvVar.
   * Added DiskImage.noBootloader, useful for eg, direct booting with
     qemu. Thanks, David Bremner.
+  * Added Apt.backportInstalledMin.
 
  -- Joey Hess <id@joeyh.name>  Thu, 09 Aug 2018 10:54:41 -0400
 
diff --git a/doc/forum/Apt.backportInstalledMin___63__/comment_1_4e5e6b479e478897eea3337b9468db15._comment b/doc/forum/Apt.backportInstalledMin___63__/comment_1_4e5e6b479e478897eea3337b9468db15._comment
new file mode 100644
index 00000000..83b976d2
--- /dev/null
+++ b/doc/forum/Apt.backportInstalledMin___63__/comment_1_4e5e6b479e478897eea3337b9468db15._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2018-10-14T16:28:46Z"
+ content="""
+Indeed, that's the kind of improvement I will gladly
+accept any time, and should be very easy to add. So don't hesitate to add
+properties like that and send patches.
+
+(In this case I had 5 minutes so I implemented it already.)
+"""]]
diff --git a/src/Propellor/Property/Apt.hs b/src/Propellor/Property/Apt.hs
index 064221f9..6d7fc4d6 100644
--- a/src/Propellor/Property/Apt.hs
+++ b/src/Propellor/Property/Apt.hs
@@ -241,6 +241,10 @@ type Package = String
 installed :: [Package] -> Property DebianLike
 installed = installed' ["-y"]
 
+-- | Minimal install of package, without recommends.
+installedMin :: [Package] -> Property DebianLike
+installedMin = installed' ["--no-install-recommends", "-y"]
+
 installed' :: [String] -> [Package] -> Property DebianLike
 installed' params ps = robustly $ check (not <$> isInstalled' ps) go
 	`describe` unwords ("apt installed":ps)
@@ -253,20 +257,23 @@ installed' params ps = robustly $ check (not <$> isInstalled' ps) go
 -- dependencies from stable-backports too, you will need to include those
 -- dependencies in the list of packages passed to this function.
 backportInstalled :: [Package] -> Property Debian
-backportInstalled ps = withOS desc $ \w o -> case o of
+backportInstalled = backportInstalled' ["-y"]
+
+-- | Minimal install from the stable-backports suite, without recommends.
+backportInstalledMin :: [Package] -> Property Debian
+backportInstalledMin = backportInstalled' ["--no-install-recommends", "-y"]
+
+backportInstalled' :: [String] -> [Package] -> Property Debian
+backportInstalled' params ps = withOS desc $ \w o -> case o of
 	(Just (System (Debian _ suite) _)) -> case backportSuite suite of
 		Nothing -> unsupportedOS'
 		Just bs -> ensureProperty w $
-			runApt (["install", "-y"] ++ ((++ '/':bs) <$> ps))
+			runApt (("install":params) ++ ((++ '/':bs) <$> ps))
 				`changesFile` dpkgStatus
 	_ -> unsupportedOS'
   where
 	desc = unwords ("apt installed backport":ps)
 
--- | Minimal install of package, without recommends.
-installedMin :: [Package] -> Property DebianLike
-installedMin = installed' ["--no-install-recommends", "-y"]
-
 removed :: [Package] -> Property DebianLike
 removed ps = check (any (== IsInstalled) <$> getInstallStatus ps)
 	(runApt (["-y", "remove"] ++ ps))

comment
diff --git a/doc/forum/__34__predictable__34___network_interface_names/comment_1_6bf05129a9aa5b427c0838753b5b0673._comment b/doc/forum/__34__predictable__34___network_interface_names/comment_1_6bf05129a9aa5b427c0838753b5b0673._comment
new file mode 100644
index 00000000..c3e4e663
--- /dev/null
+++ b/doc/forum/__34__predictable__34___network_interface_names/comment_1_6bf05129a9aa5b427c0838753b5b0673._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2018-10-14T16:18:37Z"
+ content="""
+I don't think this is specific to disk image creation, you just need a
+property that arranges whatever configuration will lead to the names you
+want.
+
+You may be looking for /lib/systemd/network/99-default.link which can be
+masked to get the kernel's traditional names.
+"""]]

diff --git a/doc/forum/Apt.backportInstalledMin___63__.mdwn b/doc/forum/Apt.backportInstalledMin___63__.mdwn
new file mode 100644
index 00000000..64d95c72
--- /dev/null
+++ b/doc/forum/Apt.backportInstalledMin___63__.mdwn
@@ -0,0 +1 @@
+I just installed git-annex using Apt.backportInstalled on a server and was kindof of horrified by the dependendencies dragged in. I suspect much of this is probably just youtube-dl, which should be fixed soon, but anyway, shouldn't there be a way to install from backports without recommends?

diff --git a/doc/forum/__34__predictable__34___network_interface_names.mdwn b/doc/forum/__34__predictable__34___network_interface_names.mdwn
new file mode 100644
index 00000000..88b4b414
--- /dev/null
+++ b/doc/forum/__34__predictable__34___network_interface_names.mdwn
@@ -0,0 +1,3 @@
+When using propellor to install/create VM images, one naturally wants to set some kind of sane network configuration. Unfortunately the name of the network interface in the guest (or newly installed system) varies according to the hardware setup. As a concrete example, in a newly created stretch amd64 image it is ens0, while in a stretch s390x image it is enc0.  I guess the Debian installer must have some way of figuring this out and creating a sane /etc/network/interfaces. Is this something that Property.DiskImage can help with, or do I need to carry per-VM configuration information? I don't mind so much the extra config info, but it's a bit annoying that I need to boot the vm to see what the network device is called.
+
+I guess the Luddite solution is to turn off interface renaming via boot options; I'm not sure that option will always be available to me, e.g. when deploying images on someone else's host.

Added a comment: insufficient magic
diff --git a/doc/todo/support_for_libvirt_KVM_VMs/comment_5_364df45dda89ed83cf8db6fa4cbdc186._comment b/doc/todo/support_for_libvirt_KVM_VMs/comment_5_364df45dda89ed83cf8db6fa4cbdc186._comment
new file mode 100644
index 00000000..5062ed5d
--- /dev/null
+++ b/doc/todo/support_for_libvirt_KVM_VMs/comment_5_364df45dda89ed83cf8db6fa4cbdc186._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="insufficient magic"
+ date="2018-10-14T11:12:36Z"
+ content="""
+right, changing the backing image would probably break everything.
+"""]]

comment
diff --git a/doc/todo/support_for_libvirt_KVM_VMs/comment_4_dbd2c399c8ef8ac56ae06f1a701fdc45._comment b/doc/todo/support_for_libvirt_KVM_VMs/comment_4_dbd2c399c8ef8ac56ae06f1a701fdc45._comment
new file mode 100644
index 00000000..8ce06a1c
--- /dev/null
+++ b/doc/todo/support_for_libvirt_KVM_VMs/comment_4_dbd2c399c8ef8ac56ae06f1a701fdc45._comment
@@ -0,0 +1,19 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 4"""
+ date="2018-10-14T01:10:16Z"
+ content="""
+I do think that the conditional property would be a good way for this to
+work.
+
+I think there could also be VMs where you don't want the overhead of
+running propellor inside the VM (especially if the emulation is slow, or
+you don't want to allocate that much memory to the VM, or just have a lot
+of VMs), and the content is disposable. Then propellor could restart the VM
+when it changes the disk image.
+
+There's room for multiple ways to do it.. 
+
+The disk image building side of this looks easy to me, so if you do the libvirt
+stuff, Sean, I might contribute something. :)
+"""]]

name bikeshedding
diff --git a/debian/changelog b/debian/changelog
index cc0e0a15..b0f7121b 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -15,6 +15,8 @@ propellor (5.5.0) UNRELEASED; urgency=medium
     the line to /etc/sudoers, but that would override more specific lines
     in the include directory.
   * Borg: Added UsesEnvVar.
+  * Added DiskImage.noBootloader, useful for eg, direct booting with
+    qemu. Thanks, David Bremner.
 
  -- Joey Hess <id@joeyh.name>  Thu, 09 Aug 2018 10:54:41 -0400
 
diff --git a/doc/forum/support_for_non-bootable_disk_images/comment_5_ee60d5bf1cdd1fd0e4319eed99f614c1._comment b/doc/forum/support_for_non-bootable_disk_images/comment_5_ee60d5bf1cdd1fd0e4319eed99f614c1._comment
new file mode 100644
index 00000000..9ebe3062
--- /dev/null
+++ b/doc/forum/support_for_non-bootable_disk_images/comment_5_ee60d5bf1cdd1fd0e4319eed99f614c1._comment
@@ -0,0 +1,13 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 5"""
+ date="2018-10-14T00:39:51Z"
+ content="""
+Ah right, [[todo/support_for_libvirt_KVM_VMs]];
+your patch is kind of a prerequisite for that. Pulling the kernel and
+initrd out of the chroot is a good idea!
+
+"Host" is slightly ambiguous around disk image building because
+a disk image can be built for a Host by `imageBuiltFor`. I've gone ahead
+and merged it in with the NoBootloader name.
+"""]]
diff --git a/propellor.cabal b/propellor.cabal
index 518505a4..0454fc92 100644
--- a/propellor.cabal
+++ b/propellor.cabal
@@ -74,7 +74,6 @@ Library
     Propellor.Property.Cron
     Propellor.Property.DebianMirror
     Propellor.Property.Debootstrap
-    Propellor.Property.DirectBoot
     Propellor.Property.DiskImage
     Propellor.Property.DiskImage.PartSpec
     Propellor.Property.Dns
diff --git a/src/Propellor/Property/DirectBoot.hs b/src/Propellor/Property/DirectBoot.hs
deleted file mode 100644
index 4807471e..00000000
--- a/src/Propellor/Property/DirectBoot.hs
+++ /dev/null
@@ -1,7 +0,0 @@
-module Propellor.Property.DirectBoot(installed) where
-
-import Propellor.Base
-import Propellor.Types.Bootloader
-
-installed :: Property (HasInfo + UnixLike)
-installed = pureInfoProperty "direct boot" [DirectBoot]
diff --git a/src/Propellor/Property/DiskImage.hs b/src/Propellor/Property/DiskImage.hs
index a41af18c..fa41808e 100644
--- a/src/Propellor/Property/DiskImage.hs
+++ b/src/Propellor/Property/DiskImage.hs
@@ -18,6 +18,7 @@ module Propellor.Property.DiskImage (
 	imageBuiltFrom,
 	imageExists,
 	GrubTarget(..),
+	noBootloader,
 ) where
 
 import Propellor.Base
@@ -228,7 +229,7 @@ imageBuilt' rebuild img mkchroot tabletype partspec =
 			ubootFlashKernelFinalized p
 		[FlashKernelInstalled, UbootInstalled p] -> 
 			ubootFlashKernelFinalized p
-                [DirectBoot] -> directBootFinalized
+		[NoBootloader] -> noBootloaderFinalized
 		_ -> unbootable "multiple bootloaders are installed; don't know which to use"
 
 -- | This property is automatically added to the chroot when building a
@@ -470,9 +471,6 @@ grubFinalized grubtarget _img mnt loopdevs =
 ubootFinalized :: (FilePath -> FilePath -> Property Linux) -> Finalization
 ubootFinalized p (RawDiskImage img) mnt _loopdevs = p img mnt
 
-directBootFinalized :: Finalization
-directBootFinalized _img _mnt _loopDevs = doNothing
-
 flashKernelFinalized :: Finalization
 flashKernelFinalized _img mnt _loopdevs = FlashKernel.flashKernelMounted mnt
 
@@ -481,6 +479,15 @@ ubootFlashKernelFinalized p img mnt loopdevs =
 	ubootFinalized p img mnt loopdevs
 		`before` flashKernelFinalized img mnt loopdevs
 
+-- | Normally a boot loader is installed on a disk image. However,
+-- when the disk image will be booted by eg qemu booting the kernel and
+-- initrd, no boot loader is needed, and this property can be used.
+noBootloader :: Property (HasInfo + UnixLike)
+noBootloader = pureInfoProperty "no bootloader" [NoBootloader]
+
+noBootloaderFinalized :: Finalization
+noBootloaderFinalized _img _mnt _loopDevs = doNothing
+
 isChild :: FilePath -> Maybe MountPoint -> Bool
 isChild mntpt (Just d)
 	| d `equalFilePath` mntpt = False
diff --git a/src/Propellor/Types/Bootloader.hs b/src/Propellor/Types/Bootloader.hs
index cdb37a31..52a6da02 100644
--- a/src/Propellor/Types/Bootloader.hs
+++ b/src/Propellor/Types/Bootloader.hs
@@ -10,7 +10,7 @@ data BootloaderInstalled
 	= GrubInstalled GrubTarget
 	| FlashKernelInstalled
 	| UbootInstalled (FilePath -> FilePath -> Property Linux)
-        | DirectBoot
+	| NoBootloader
 	deriving (Typeable)
 
 -- | Platforms that grub can boot.
@@ -20,7 +20,7 @@ instance Show BootloaderInstalled where
 	show (GrubInstalled _) = "GrubInstalled"
 	show FlashKernelInstalled = "FlashKernelInstalled"
 	show (UbootInstalled _) = "UbootInstalled"
-        show DirectBoot = "DirectBoot"
+	show NoBootloader = "NoBootloader"
 
 instance IsInfo [BootloaderInstalled] where
 	propagateInfo _ = PropagateInfo False

comment
diff --git a/doc/todo/support_for_libvirt_KVM_VMs/comment_2_54538a03d7085513538baa2970983ae0._comment b/doc/todo/support_for_libvirt_KVM_VMs/comment_2_54538a03d7085513538baa2970983ae0._comment
new file mode 100644
index 00000000..497e364a
--- /dev/null
+++ b/doc/todo/support_for_libvirt_KVM_VMs/comment_2_54538a03d7085513538baa2970983ae0._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2018-10-14T00:36:55Z"
+ content="""
+@david, but you'd not then want to change the backing raw image, I assume,
+or does qcow somehow deal with that?
+"""]]

Added a comment: qcow and raw imgs
diff --git a/doc/todo/support_for_libvirt_KVM_VMs/comment_2_9aa111329fc476a2b978aabe4cc4c0f0._comment b/doc/todo/support_for_libvirt_KVM_VMs/comment_2_9aa111329fc476a2b978aabe4cc4c0f0._comment
new file mode 100644
index 00000000..db451976
--- /dev/null
+++ b/doc/todo/support_for_libvirt_KVM_VMs/comment_2_9aa111329fc476a2b978aabe4cc4c0f0._comment
@@ -0,0 +1,14 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="qcow and raw imgs"
+ date="2018-10-13T23:48:46Z"
+ content="""
+Maybe this is obvious, but it's cheap to generate a qcow image \"backed\" by an existing raw image
+
+To quote from a script I have lying around to let a non-root user boot a root owned, read-only image
+[[!format txt \"\"\"
+qemu-img create -b /srv/vm/$vm.img -f qcow2 $img
+\"\"\"]]
+
+"""]]

Added a comment: Naming and other hard problems
diff --git a/doc/forum/support_for_non-bootable_disk_images/comment_4_33cf3405000896fb42b9165a206e2417._comment b/doc/forum/support_for_non-bootable_disk_images/comment_4_33cf3405000896fb42b9165a206e2417._comment
new file mode 100644
index 00000000..55e4e20b
--- /dev/null
+++ b/doc/forum/support_for_non-bootable_disk_images/comment_4_33cf3405000896fb42b9165a206e2417._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="Naming and other hard problems"
+ date="2018-10-13T23:16:07Z"
+ content="""
+I'm not too attached to the terminology, \"direct booting\" just what an unscientific survey of sysadmin types came up with. QemuBoot is more descriptive, although I do wonder if it's really specific to Qemu.  As far as I understand (which is just from reading the Xen wiki), Xen dom0 can also (and originally could only) boot this way.  In fact I think the last Xen VPS I had worked like this, which was a pain as a guest admin. Maybe the connecting thread is that the boot is controlled by the host rather than the guest VM.  HostBoot would be one option, although NoBootloader is also fine with me. I think things like QemuBootloader or whatever would likely be layered on top.
+
+I'm less sure about copying kernel and initrd than when I first wrote that. If it's reasonable to depend on the existence of the foo.img.chroot,  then it's quite convenient to boot from the already conveniently present kernel and initramfs.
+
+I'll have to see how hard it is to get basic networking with just qemu. It might make sense to use libvirt to run the VMs, especially since that's what the production deployment uses.  I saw [[spwhitton]] had some ideas about libvirt.
+
+
+
+"""]]

code review
diff --git a/doc/forum/support_for_non-bootable_disk_images/comment_3_8dd7f3dd8c80fda70233e395da2204b2._comment b/doc/forum/support_for_non-bootable_disk_images/comment_3_8dd7f3dd8c80fda70233e395da2204b2._comment
new file mode 100644
index 00000000..d1761e51
--- /dev/null
+++ b/doc/forum/support_for_non-bootable_disk_images/comment_3_8dd7f3dd8c80fda70233e395da2204b2._comment
@@ -0,0 +1,33 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2018-10-13T21:41:25Z"
+ content="""
+Code^Wwhitespace review:
+
+* I noticed some places were using spaces for indentation;
+  please use tabs in propellor.
+* In "module Propellor.Property.DirectBoot(installed)'
+  there should be a space after the name of the module.
+* Needs comments explaining what properties are for.
+
+Naming ideas: Basically this is using qemu as the bootloader, rather than
+going through an (emulated) BIOS to start a bootloader. So I'm thinking
+names like QemuBootloader or NoBootloader, or NoBIOS. Don't want to
+bikeshed this too hard, it would be ok to keep the DirectBoot name, but
+I think Propellor.Property.DirectBoot at least needs a comment explaining what it's
+for, it would be confusing for a propellor user to stumble across that
+module without context.
+
+Your idea to copy the kernel and initrd out of the image so qemu can use
+them seems to point toward having a Property that gets one of these images
+booted up using qemu. And then the QemuBootloader name would make a lot of
+sense, because it would allow for later expansion to other emulators. Not
+that you have to build such a thing, but it's worth considering that someone
+may later want to.
+
+(In fact I could use such a thing, but I don't know how I'd want it to
+work. Should propellor only use the chroot for initial image build, and
+then ssh into the booted VM and run propellor in there when there are
+config updates? Or restart the VM when the image is changed?)
+"""]]

comment
diff --git a/doc/forum/__35__propellor_on_irc.oftc.net/comment_1_6e9595651c19d98353254f0914b685e1._comment b/doc/forum/__35__propellor_on_irc.oftc.net/comment_1_6e9595651c19d98353254f0914b685e1._comment
new file mode 100644
index 00000000..187004c7
--- /dev/null
+++ b/doc/forum/__35__propellor_on_irc.oftc.net/comment_1_6e9595651c19d98353254f0914b685e1._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2018-10-13T21:36:16Z"
+ content="""
++1 user for initiative ;)
+
+Although I will not want to help with any big type errors on irc ;)
+"""]]

diff --git a/doc/forum/__35__propellor_on_irc.oftc.net.mdwn b/doc/forum/__35__propellor_on_irc.oftc.net.mdwn
new file mode 100644
index 00000000..9f644611
--- /dev/null
+++ b/doc/forum/__35__propellor_on_irc.oftc.net.mdwn
@@ -0,0 +1,2 @@
+This might be wildly optimistic, but I registered the IRC channel #propellor on irc.oftc.net. I have no strong opinions on irc networks, but #git-annex is already there. Please join so you can answer my questions ;).
+

Added a comment: As commits
diff --git a/doc/forum/support_for_non-bootable_disk_images/comment_2_cced7ce2491cf440ee1d576b75ab4539._comment b/doc/forum/support_for_non-bootable_disk_images/comment_2_cced7ce2491cf440ee1d576b75ab4539._comment
new file mode 100644
index 00000000..51cad6ff
--- /dev/null
+++ b/doc/forum/support_for_non-bootable_disk_images/comment_2_cced7ce2491cf440ee1d576b75ab4539._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="As commits"
+ date="2018-10-08T13:03:06Z"
+ content="""
+I pushed the changes to
+
+https://salsa.debian.org/bremner/propellor/commits/proposed/direct-boot
+"""]]

Added a comment: Initial attempt at a patch
diff --git a/doc/forum/support_for_non-bootable_disk_images/comment_1_94727e8ddf14f868225b99c83fbf406d._comment b/doc/forum/support_for_non-bootable_disk_images/comment_1_94727e8ddf14f868225b99c83fbf406d._comment
new file mode 100644
index 00000000..b4ade339
--- /dev/null
+++ b/doc/forum/support_for_non-bootable_disk_images/comment_1_94727e8ddf14f868225b99c83fbf406d._comment
@@ -0,0 +1,65 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="Initial attempt at a patch"
+ date="2018-10-08T12:48:38Z"
+ content="""
+Here is a simple approach, that at least allows the image building to complete. I also managed to boot one of the images on AMD64. Probably it needs more testing, and I'm sure there are style and naming issues.
+[[!format text \"\"\"
+diff --git a/src/Propellor/Property/DirectBoot.hs b/src/Propellor/Property/DirectBoot.hs
+new file mode 100644
+index 00000000..4807471e
+--- /dev/null
++++ b/src/Propellor/Property/DirectBoot.hs
+@@ -0,0 +1,7 @@
++module Propellor.Property.DirectBoot(installed) where
++
++import Propellor.Base
++import Propellor.Types.Bootloader
++
++installed :: Property (HasInfo + UnixLike)
++installed = pureInfoProperty \"direct boot\" [DirectBoot]
+diff --git a/src/Propellor/Property/DiskImage.hs b/src/Propellor/Property/DiskImage.hs
+index 289de151..a41af18c 100644
+--- a/src/Propellor/Property/DiskImage.hs
++++ b/src/Propellor/Property/DiskImage.hs
+@@ -228,6 +228,7 @@ imageBuilt' rebuild img mkchroot tabletype partspec =
+                        ubootFlashKernelFinalized p
+                [FlashKernelInstalled, UbootInstalled p] -> 
+                        ubootFlashKernelFinalized p
++                [DirectBoot] -> directBootFinalized
+                _ -> unbootable \"multiple bootloaders are installed; don't know which to use\"
+ 
+ -- | This property is automatically added to the chroot when building a
+@@ -469,6 +470,9 @@ grubFinalized grubtarget _img mnt loopdevs =
+ ubootFinalized :: (FilePath -> FilePath -> Property Linux) -> Finalization
+ ubootFinalized p (RawDiskImage img) mnt _loopdevs = p img mnt
+ 
++directBootFinalized :: Finalization
++directBootFinalized _img _mnt _loopDevs = doNothing
++
+ flashKernelFinalized :: Finalization
+ flashKernelFinalized _img mnt _loopdevs = FlashKernel.flashKernelMounted mnt
+ 
+diff --git a/src/Propellor/Types/Bootloader.hs b/src/Propellor/Types/Bootloader.hs
+index 65117bd2..cdb37a31 100644
+--- a/src/Propellor/Types/Bootloader.hs
++++ b/src/Propellor/Types/Bootloader.hs
+@@ -10,6 +10,7 @@ data BootloaderInstalled
+        = GrubInstalled GrubTarget
+        | FlashKernelInstalled
+        | UbootInstalled (FilePath -> FilePath -> Property Linux)
++        | DirectBoot
+        deriving (Typeable)
+ 
+ -- | Platforms that grub can boot.
+@@ -19,6 +20,7 @@ instance Show BootloaderInstalled where
+        show (GrubInstalled _) = \"GrubInstalled\"
+        show FlashKernelInstalled = \"FlashKernelInstalled\"
+        show (UbootInstalled _) = \"UbootInstalled\"
++        show DirectBoot = \"DirectBoot\"
+ 
+ instance IsInfo [BootloaderInstalled] where
+        propagateInfo _ = PropagateInfo False
+\"\"\"]]
+"""]]

removed
diff --git a/doc/forum/support_for_non-bootable_disk_images/comment_1_4c4a376db9071336011abbf2993022f2._comment b/doc/forum/support_for_non-bootable_disk_images/comment_1_4c4a376db9071336011abbf2993022f2._comment
deleted file mode 100644
index 60cbc9f0..00000000
--- a/doc/forum/support_for_non-bootable_disk_images/comment_1_4c4a376db9071336011abbf2993022f2._comment
+++ /dev/null
@@ -1,68 +0,0 @@
-[[!comment format=mdwn
- username="david"
- avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
- subject="Initial attempt"
- date="2018-10-08T12:43:42Z"
- content="""
-I tried to solve this in the stupidest possible way. I'll paste diff here, as it's small and I'm not really confident it's ready for merging.
-
-
-[[!format \"\"\"
-diff --git a/src/Propellor/Property/DirectBoot.hs b/src/Propellor/Property/DirectBoot.hs
-new file mode 100644
-index 00000000..4807471e
---- /dev/null
-+++ b/src/Propellor/Property/DirectBoot.hs
-@@ -0,0 +1,7 @@
-+module Propellor.Property.DirectBoot(installed) where
-+
-+import Propellor.Base
-+import Propellor.Types.Bootloader
-+
-+installed :: Property (HasInfo + UnixLike)
-+installed = pureInfoProperty \"direct boot\" [DirectBoot]
-diff --git a/src/Propellor/Property/DiskImage.hs b/src/Propellor/Property/DiskImage.hs
-index 289de151..a41af18c 100644
---- a/src/Propellor/Property/DiskImage.hs
-+++ b/src/Propellor/Property/DiskImage.hs
-@@ -228,6 +228,7 @@ imageBuilt' rebuild img mkchroot tabletype partspec =
-                        ubootFlashKernelFinalized p
-                [FlashKernelInstalled, UbootInstalled p] -> 
-                        ubootFlashKernelFinalized p
-+                [DirectBoot] -> directBootFinalized
-                _ -> unbootable \"multiple bootloaders are installed; don't know which to use\"
- 
- -- | This property is automatically added to the chroot when building a
-@@ -469,6 +470,9 @@ grubFinalized grubtarget _img mnt loopdevs =
- ubootFinalized :: (FilePath -> FilePath -> Property Linux) -> Finalization
- ubootFinalized p (RawDiskImage img) mnt _loopdevs = p img mnt
- 
-+directBootFinalized :: Finalization
-+directBootFinalized _img _mnt _loopDevs = doNothing
-+
- flashKernelFinalized :: Finalization
- flashKernelFinalized _img mnt _loopdevs = FlashKernel.flashKernelMounted mnt
- 
-diff --git a/src/Propellor/Types/Bootloader.hs b/src/Propellor/Types/Bootloader.hs
-index 65117bd2..cdb37a31 100644
---- a/src/Propellor/Types/Bootloader.hs
-+++ b/src/Propellor/Types/Bootloader.hs
-@@ -10,6 +10,7 @@ data BootloaderInstalled
-        = GrubInstalled GrubTarget
-        | FlashKernelInstalled
-        | UbootInstalled (FilePath -> FilePath -> Property Linux)
-+        | DirectBoot
-        deriving (Typeable)
- 
- -- | Platforms that grub can boot.
-@@ -19,6 +20,7 @@ instance Show BootloaderInstalled where
-        show (GrubInstalled _) = \"GrubInstalled\"
-        show FlashKernelInstalled = \"FlashKernelInstalled\"
-        show (UbootInstalled _) = \"UbootInstalled\"
-+        show DirectBoot = \"DirectBoot\"
- 
- instance IsInfo [BootloaderInstalled] where
-        propagateInfo _ = PropagateInfo False
-
-\"\"\"]]
-"""]]

Added a comment: Initial attempt
diff --git a/doc/forum/support_for_non-bootable_disk_images/comment_1_4c4a376db9071336011abbf2993022f2._comment b/doc/forum/support_for_non-bootable_disk_images/comment_1_4c4a376db9071336011abbf2993022f2._comment
new file mode 100644
index 00000000..60cbc9f0
--- /dev/null
+++ b/doc/forum/support_for_non-bootable_disk_images/comment_1_4c4a376db9071336011abbf2993022f2._comment
@@ -0,0 +1,68 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="Initial attempt"
+ date="2018-10-08T12:43:42Z"
+ content="""
+I tried to solve this in the stupidest possible way. I'll paste diff here, as it's small and I'm not really confident it's ready for merging.
+
+
+[[!format \"\"\"
+diff --git a/src/Propellor/Property/DirectBoot.hs b/src/Propellor/Property/DirectBoot.hs
+new file mode 100644
+index 00000000..4807471e
+--- /dev/null
++++ b/src/Propellor/Property/DirectBoot.hs
+@@ -0,0 +1,7 @@
++module Propellor.Property.DirectBoot(installed) where
++
++import Propellor.Base
++import Propellor.Types.Bootloader
++
++installed :: Property (HasInfo + UnixLike)
++installed = pureInfoProperty \"direct boot\" [DirectBoot]
+diff --git a/src/Propellor/Property/DiskImage.hs b/src/Propellor/Property/DiskImage.hs
+index 289de151..a41af18c 100644
+--- a/src/Propellor/Property/DiskImage.hs
++++ b/src/Propellor/Property/DiskImage.hs
+@@ -228,6 +228,7 @@ imageBuilt' rebuild img mkchroot tabletype partspec =
+                        ubootFlashKernelFinalized p
+                [FlashKernelInstalled, UbootInstalled p] -> 
+                        ubootFlashKernelFinalized p
++                [DirectBoot] -> directBootFinalized
+                _ -> unbootable \"multiple bootloaders are installed; don't know which to use\"
+ 
+ -- | This property is automatically added to the chroot when building a
+@@ -469,6 +470,9 @@ grubFinalized grubtarget _img mnt loopdevs =
+ ubootFinalized :: (FilePath -> FilePath -> Property Linux) -> Finalization
+ ubootFinalized p (RawDiskImage img) mnt _loopdevs = p img mnt
+ 
++directBootFinalized :: Finalization
++directBootFinalized _img _mnt _loopDevs = doNothing
++
+ flashKernelFinalized :: Finalization
+ flashKernelFinalized _img mnt _loopdevs = FlashKernel.flashKernelMounted mnt
+ 
+diff --git a/src/Propellor/Types/Bootloader.hs b/src/Propellor/Types/Bootloader.hs
+index 65117bd2..cdb37a31 100644
+--- a/src/Propellor/Types/Bootloader.hs
++++ b/src/Propellor/Types/Bootloader.hs
+@@ -10,6 +10,7 @@ data BootloaderInstalled
+        = GrubInstalled GrubTarget
+        | FlashKernelInstalled
+        | UbootInstalled (FilePath -> FilePath -> Property Linux)
++        | DirectBoot
+        deriving (Typeable)
+ 
+ -- | Platforms that grub can boot.
+@@ -19,6 +20,7 @@ instance Show BootloaderInstalled where
+        show (GrubInstalled _) = \"GrubInstalled\"
+        show FlashKernelInstalled = \"FlashKernelInstalled\"
+        show (UbootInstalled _) = \"UbootInstalled\"
++        show DirectBoot = \"DirectBoot\"
+ 
+ instance IsInfo [BootloaderInstalled] where
+        propagateInfo _ = PropagateInfo False
+
+\"\"\"]]
+"""]]

diff --git a/doc/forum/support_for_non-bootable_disk_images.mdwn b/doc/forum/support_for_non-bootable_disk_images.mdwn
new file mode 100644
index 00000000..1c62c599
--- /dev/null
+++ b/doc/forum/support_for_non-bootable_disk_images.mdwn
@@ -0,0 +1,59 @@
+qemu-system-s390x has the apparent quirk that it can only boot via something like
+
+ `qemu-system-s390x -kernel kernel.debian -initrd initrd.debian -m 512 -nographic --drive file=rootimage.img,format=raw,if=none,id=c1`
+
+This means I think what I want to do is something like the following
+
+[[!format haskell """
+  & imageBuilt (RawDiskImage "/srv/vm/bricklin.img") bricklinChroot
+          MSDOS
+          [ partition EXT4 `mountedAt` "/"
+			`addFreeSpace` MegaBytes 100
+			`mountOpt` errorReadonly
+	  , swapPartition (MegaBytes 256)
+	]
+  where
+    bricklinChroot d = debootstrapped mempty d $ props
+      & osDebian (Stable "stretch") S390X
+      & Apt.installed [ "linux-image-s390x" ]
+"""]]
+
+This seems to build the image OK (see end of post), but propellor fails because the image is not bootable (the image contents might need adjustment as well, but first things first).
+I'm not sure what this style of booting is called, but I see people providing "cloud images" meant to be used this way, with separate initrd and and kernel.  Is it sensible to customize imageBuilt for this purpose, or would it be better write my own `nonBootableImageBuilt` or something like that?
+
+
+[[!format text """
+/srv/vm/bricklin.img.chroot apt installed linux-image-s390x ... done
+/srv/vm/bricklin.img.chroot cache cleaned ... ok
+creating /srv/vm/bricklin.img of size 1.02 gigabytes
+Reading package lists...
+Building dependency tree...
+Reading state information...
+The following packages were automatically installed and are no longer required:
+[snip]
+Use 'apt autoremove' to remove them.
+The following NEW packages will be installed:
+  kpartx
+0 upgraded, 1 newly installed, 0 to remove and 5 not upgraded.
+Need to get 33.8 kB of archives.
+After this operation, 76.8 kB of additional disk space will be used.
+Get:1 http://deb.debian.org/debian stretch/main amd64 kpartx amd64 0.6.4-5 [33.8 kB]
+Fetched 33.8 kB in 0s (118 kB/s)
+                                Selecting previously unselected package kpartx.
+(Reading database ... 238863 files and directories currently installed.)
+Preparing to unpack .../kpartx_0.6.4-5_amd64.deb ...
+Unpacking kpartx (0.6.4-5) ...
+Setting up kpartx (0.6.4-5) ...
+Processing triggers for man-db (2.7.6.1-2) ...
+Setting up swapspace version 1, size = 248 MiB (260042752 bytes)
+no label, UUID=65c5b131-98bf-4b8c-afad-9c75405c6391
+loop deleted : /dev/loop0
+    433,093,140  99%  220.62MB/s    0:00:01 (xfr#11289, to-chk=0/14615)   
+** warning: image is not bootable: no bootloader is installed
+loop deleted : /dev/loop0
+concave.cs.unb.ca built disk image /srv/vm/bricklin.img ... failed
+concave.cs.unb.ca s390x server image (bricklin) ... failed
+concave.cs.unb.ca overall ... failed
+"""]]
+
+

Added a comment: In this case I really should make a package
diff --git a/doc/forum/installing_small_binary_files/comment_1_7537a56c67658ad47460a3b80690ecfd._comment b/doc/forum/installing_small_binary_files/comment_1_7537a56c67658ad47460a3b80690ecfd._comment
new file mode 100644
index 00000000..95a11dae
--- /dev/null
+++ b/doc/forum/installing_small_binary_files/comment_1_7537a56c67658ad47460a3b80690ecfd._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="In this case I really should make a package"
+ date="2018-10-04T10:19:35Z"
+ content="""
+After some reflection I realized that have propellor drop things in /usr/share/qemu is just going to make me sad in the long run. I still think the general question is potentially useful, but I guess it's a bit hypothetical at this point.
+"""]]

diff --git a/doc/forum/installing_small_binary_files.mdwn b/doc/forum/installing_small_binary_files.mdwn
new file mode 100644
index 00000000..080f49a1
--- /dev/null
+++ b/doc/forum/installing_small_binary_files.mdwn
@@ -0,0 +1 @@
+I need to install a small firmware file (it's actually free software, but I need it to boot the emulator I could build it with). I could of course make a debian package and put that package in a repo, but that seems like a lot of fuss for a 32k file. OTOH, I'm a bit loathe to use PrivData for this. Anyone care to either suggest a better way, or convince me it's fine to store firmware in PrivData?

Added a comment
diff --git a/doc/forum/configuring_texlive_papersize/comment_1_e4c1bd36c3739d4dd9bf7316c9021a14._comment b/doc/forum/configuring_texlive_papersize/comment_1_e4c1bd36c3739d4dd9bf7316c9021a14._comment
new file mode 100644
index 00000000..ac85d2b3
--- /dev/null
+++ b/doc/forum/configuring_texlive_papersize/comment_1_e4c1bd36c3739d4dd9bf7316c9021a14._comment
@@ -0,0 +1,20 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="comment 1"
+ date="2018-09-18T22:17:07Z"
+ content="""
+I have this (the laptop is otherwise en_GB):
+
+    -- iris is in the US
+    & \"en_US.UTF-8\" `Locale.selectedFor`
+    	[ \"LC_PAPER\"
+    	, \"LC_ADDRESS\"
+    	, \"LC_MONETARY\"
+    	, \"LC_TELEPHONE\"
+    	, \"LC_TIME\"
+    	]
+    & \"/etc/papersize\" `File.hasContent` [\"letter\"]
+    	`onChange` Apt.reConfigure \"libpaper1\" []
+
+"""]]

Added a comment
diff --git a/doc/forum/Adding_support_for_a_SQL_server/comment_7_054a8fa511b28ba6a299e3dfd9ed4dd6._comment b/doc/forum/Adding_support_for_a_SQL_server/comment_7_054a8fa511b28ba6a299e3dfd9ed4dd6._comment
new file mode 100644
index 00000000..ca5cf43d
--- /dev/null
+++ b/doc/forum/Adding_support_for_a_SQL_server/comment_7_054a8fa511b28ba6a299e3dfd9ed4dd6._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="Nicolas.Schodet"
+ avatar="http://cdn.libravatar.org/avatar/0d7ec808ec329d04ee9a93c0da3c0089"
+ subject="comment 7"
+ date="2018-09-17T21:57:48Z"
+ content="""
+Database is a database name.
+
+I will make the change as soon as I have some time, thanks for the review!
+"""]]

diff --git a/doc/forum/configuring_texlive_papersize.mdwn b/doc/forum/configuring_texlive_papersize.mdwn
new file mode 100644
index 00000000..1890887d
--- /dev/null
+++ b/doc/forum/configuring_texlive_papersize.mdwn
@@ -0,0 +1 @@
+I just observed that installing texlive via propellor means I have A4 paper chose as a default. Which is all very good from an ideological point of view, but it means I can't submit this grant application ;).  Is it worth having a propellor property that runs paperconfig?

comment
diff --git a/doc/todo/Apt.trustsKey_should_not_invoke_apt-key/comment_1_49003d4fdd0e75d477415cb0bb6bbd3c._comment b/doc/todo/Apt.trustsKey_should_not_invoke_apt-key/comment_1_49003d4fdd0e75d477415cb0bb6bbd3c._comment
new file mode 100644
index 00000000..67ad5260
--- /dev/null
+++ b/doc/todo/Apt.trustsKey_should_not_invoke_apt-key/comment_1_49003d4fdd0e75d477415cb0bb6bbd3c._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2018-09-17T18:16:56Z"
+ content="""
+Fine by me as long as it cleans up or overwrites the file that apt-key
+installed earlier.
+"""]]

review
diff --git a/doc/forum/Adding_support_for_a_SQL_server/comment_6_8ebb3d150b06c086d8ad45b9d994877f._comment b/doc/forum/Adding_support_for_a_SQL_server/comment_6_8ebb3d150b06c086d8ad45b9d994877f._comment
new file mode 100644
index 00000000..bd924fed
--- /dev/null
+++ b/doc/forum/Adding_support_for_a_SQL_server/comment_6_8ebb3d150b06c086d8ad45b9d994877f._comment
@@ -0,0 +1,41 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 6"""
+ date="2018-09-17T17:21:52Z"
+ content="""
+Some review, sorry it took me so long to take a look at it..
+
+It's not clear to me how to construct a `Database`;
+what is the `String` inside it? The path? A database name?
+What makes for a legal or illegal database name?
+(May be more obvious to people who use mysql than to me.)
+
+Looks like `Show Privilege` is being used to generate configuration.
+I dislike using `Show` for that, because it precludes it being used with
+Read, and is generally unclear that the strings in show need to be
+formatted exactly as they are.
+
+You could simplify allPrivileges using `Enum`,
+with `[minBound..maxBound]`.
+
+Reverting `databaseExists` and also reverting `installed`
+leads to the package being installed and then removed repeatedly.
+Perhaps `databaseExists` could avoid doing anything when the
+server has already been removed.
+
+Some of the SQL construction doesn't seem entirely safe with quoting.
+While there's no security problem with it, it may have a correctness
+problem..
+
+... In `userGrantedOnDatabase` when it creates the privLevel
+it looks like it doesn't escape the dbname at all,
+and I guess this means it doesn't need to be escaped, or
+can't contain back quotes.
+
+... In `userGranted'` the quser is delimited by single quotes,
+but it's actually valid to have a `User` with a single quote in their name,
+and many of the Klingons out there probably depend on that.
+
+... In `hashPassword` it looks like the password is also assumed to not
+contain single quotes.
+"""]]

todo
diff --git a/doc/todo/apt_mark_support.mdwn b/doc/todo/apt_mark_support.mdwn
new file mode 100644
index 00000000..50591222
--- /dev/null
+++ b/doc/todo/apt_mark_support.mdwn
@@ -0,0 +1,27 @@
+I'd like a property that removes all packages that were not installed by
+the current set of propellor properties. For systems that are fully
+specified by propellor, this would keep the cruft from piling up.
+
+This could be done using apt-mark. Before propellor installs anything with
+apt, go through the apt-mark list and set all packages to auto. When apt is
+run to install a package, it will mark it as manually installed. Since
+Apt.installed skips running apt when packages are already installed, it
+would need to either be changed to run apt anyway, or to run apt-mark
+manual. And then after all other properties, run apt-get autoremove.
+
+Running the autoremove at the end is supported by the propellor monad,
+but there's currently no way to run something before all properties.
+The first Apt.install to run could handle the apt-mark-list-to-auto part,
+although there's also not currently any state for the property to keep
+track of if it's run before.
+
+It would also be possible to not do the apt-mark at the beginning. Instead,
+make the Propellor monad a Writer (polymorphized somehow perhaps like Info
+is) and have Apt.install track the packages that are installed. (Or it
+could be changed to a HasInfo property, and then the list of packages would
+accumulate in Info, but there are likely things that use Apt.installed
+inside ensureProperty which that would cause problems for.) 
+
+Either way, an action run at the end can then update the apt-mark data to
+reflect the gathered list of packages, and run apt-get autoremove.
+--[[Joey]]

Added a comment
diff --git a/doc/forum/bind_mounting_in_Sbuild_chroots/comment_1_0f41fc776bb0d595af239f087e5a1d35._comment b/doc/forum/bind_mounting_in_Sbuild_chroots/comment_1_0f41fc776bb0d595af239f087e5a1d35._comment
new file mode 100644
index 00000000..71927311
--- /dev/null
+++ b/doc/forum/bind_mounting_in_Sbuild_chroots/comment_1_0f41fc776bb0d595af239f087e5a1d35._comment
@@ -0,0 +1,12 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="comment 1"
+ date="2018-09-08T16:54:24Z"
+ content="""
+You could use
+
+    & File.containsLine \"/etc/schroot/sbuild/fstab\" \"...\"
+
+but yes, I think it's cleaner to use the sbuild chroots only for building, and for interactive use some other chroot.
+"""]]

diff --git a/doc/forum/bind_mounting_in_Sbuild_chroots.mdwn b/doc/forum/bind_mounting_in_Sbuild_chroots.mdwn
new file mode 100644
index 00000000..f2fb8e11
--- /dev/null
+++ b/doc/forum/bind_mounting_in_Sbuild_chroots.mdwn
@@ -0,0 +1,2 @@
+I typically bind mount some user writable directory into an Sbuild chroot, so that I can e.g. access in a git repo or package to install.
+Is there a clean way to do this with propellor's Sbuild module, or is the intent maintain a seperate container / chroot of some kind for interactive debugging?

create new bug
diff --git a/doc/todo/Apt.trustsKey_should_not_invoke_apt-key.mdwn b/doc/todo/Apt.trustsKey_should_not_invoke_apt-key.mdwn
new file mode 100644
index 00000000..d2f9e6db
--- /dev/null
+++ b/doc/todo/Apt.trustsKey_should_not_invoke_apt-key.mdwn
@@ -0,0 +1,9 @@
+[Over at the Debian BTS](https://bugs.debian.org/907290), David Bremner points out that the apt-key manpage, on Debian stable, says
+
+> Instead of using this [add] [sub]command a keyring should be placed
+> directly in the /etc/apt/trusted.gpg.d/ directory with a
+> descriptive name and either "gpg" or "asc" as file extension.
+
+So ISTM that `Apt.trustsKey` should be implemented simply with `File.hasContents`, i.e., the property should delete any old `.gpg` file and then create a `.asc` file with the text  string content of the `AptKey`.
+
+--spwhitton

Added a comment
diff --git a/doc/forum/Adding_support_for_a_SQL_server/comment_5_10eb776b64b213ca8f8166aacfba9a4d._comment b/doc/forum/Adding_support_for_a_SQL_server/comment_5_10eb776b64b213ca8f8166aacfba9a4d._comment
new file mode 100644
index 00000000..df119fe7
--- /dev/null
+++ b/doc/forum/Adding_support_for_a_SQL_server/comment_5_10eb776b64b213ca8f8166aacfba9a4d._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="Nicolas.Schodet"
+ avatar="http://cdn.libravatar.org/avatar/0d7ec808ec329d04ee9a93c0da3c0089"
+ subject="comment 5"
+ date="2018-08-31T20:53:01Z"
+ content="""
+Also added a function to grant global privileges, useful for a backup user.
+"""]]

Added a comment
diff --git a/doc/forum/Adding_support_for_a_SQL_server/comment_4_22895a34904df9023fcdac0b3937a7c5._comment b/doc/forum/Adding_support_for_a_SQL_server/comment_4_22895a34904df9023fcdac0b3937a7c5._comment
new file mode 100644
index 00000000..786da77a
--- /dev/null
+++ b/doc/forum/Adding_support_for_a_SQL_server/comment_4_22895a34904df9023fcdac0b3937a7c5._comment
@@ -0,0 +1,16 @@
+[[!comment format=mdwn
+ username="Nicolas.Schodet"
+ avatar="http://cdn.libravatar.org/avatar/0d7ec808ec329d04ee9a93c0da3c0089"
+ subject="comment 4"
+ date="2018-08-30T21:14:32Z"
+ content="""
+Hello,
+
+I have made a first version to support MySQL databases and users for classic web applications.
+
+You can pull the mysql branch at http://git.ni.fr.eu.org/nicolas/propellor.git
+
+Can you have a look? I find userGrantedOnDatabase.setup' a little hard to read. Is it OK, or do you see a clearer way to write it?
+
+Thanks!
+"""]]

Added a comment: OIC
diff --git a/doc/forum/integration_with_gitolite/comment_6_232d8ab023d060d7d9c000e4c6783ef8._comment b/doc/forum/integration_with_gitolite/comment_6_232d8ab023d060d7d9c000e4c6783ef8._comment
new file mode 100644
index 00000000..80130d5b
--- /dev/null
+++ b/doc/forum/integration_with_gitolite/comment_6_232d8ab023d060d7d9c000e4c6783ef8._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="OIC"
+ date="2018-08-27T14:14:09Z"
+ content="""
+Oh, I see now we are doing essentially the same thing. For those of you following along at home, mine is using that cryptic path because for the key because I am using both gitolite's native key handling and propellor to install keys.
+"""]]

Added a comment
diff --git a/doc/forum/integration_with_gitolite/comment_5_1e71a38b32148228b94c7429e721685f._comment b/doc/forum/integration_with_gitolite/comment_5_1e71a38b32148228b94c7429e721685f._comment
new file mode 100644
index 00000000..8a1e6473
--- /dev/null
+++ b/doc/forum/integration_with_gitolite/comment_5_1e71a38b32148228b94c7429e721685f._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="comment 5"
+ date="2018-08-26T17:14:20Z"
+ content="""
+It's these lines:
+
+	-- make my SSH key available to gitolite
+	& File.hasContent \"/srv/git/.gitolite/keydir/spwhitton.pub\"
+		[SPW.mySSHKey]
+	`onChange` (userScriptProperty (User \"git\")
+		[\"gitolite compile\", \"gitolite trigger POST_COMPILE\"]
+		`assume` MadeChange)
+"""]]

comment
diff --git a/doc/forum/making_sure_a_package_is_at_the_latest_version/comment_3_48fe0419c259c9555b6349c3221a80a0._comment b/doc/forum/making_sure_a_package_is_at_the_latest_version/comment_3_48fe0419c259c9555b6349c3221a80a0._comment
new file mode 100644
index 00000000..ae45baec
--- /dev/null
+++ b/doc/forum/making_sure_a_package_is_at_the_latest_version/comment_3_48fe0419c259c9555b6349c3221a80a0._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2018-08-26T15:14:50Z"
+ content="""
+One approach would be to have a property like spwhitton suggests,
+and use it with the `Apt.robustly` combinator. That way, when you update
+the config to specify a new package version, and apt fails to install it,
+propellor will run apt update and then retry the install.
+"""]]

comment
diff --git a/doc/todo/spin_failure_HEAD/comment_4_684adfe4d134b4e27ed00db62f8e3372._comment b/doc/todo/spin_failure_HEAD/comment_4_684adfe4d134b4e27ed00db62f8e3372._comment
new file mode 100644
index 00000000..3f6aebcb
--- /dev/null
+++ b/doc/todo/spin_failure_HEAD/comment_4_684adfe4d134b4e27ed00db62f8e3372._comment
@@ -0,0 +1,43 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 4"""
+ date="2018-08-26T14:50:22Z"
+ content="""
+As far as I know, this was fixed in a series of commits,
+[[!commit 01fc1375cece096ab2dec480b843ecdbc4f0d94e]]
+[[!commit 1555c6f88a0446d3e29149eff8315817696731e1]]
+[[!commit 53fe5ffaac4a243bb9fd3cf0e757128150a6a199]]
+
+The problem was intermittent for me, I think based on network timing and
+different buffering behavior with different timings,
+which made it hard to debug, but I've not seen it since and I was seeing it
+frequently enough to be fairly sure I fixed it.
+
+So I wonder if you might have some sort of version skew issue on the host
+being spun (eg, it could have an old version of propellor installed and be
+failing before spin can update it to the fixed version). The easy way to
+verify you have the fixed version is to run `git config propellor.debug 1`
+in /usr/local/propellor/ on the host being spun, and look for
+"--upload-pack ./propellor --gitpush" in a debug message.
+
+If you're confident the remote propellor has the above commits in it,
+you're going to need to do some debugging.
+Setting `GIT_TRACE_PACKET=1` on the remote system was very helpful in
+understanding the problem, and should probably be your first step.
+Setting that environment inside Propellor.Spin.gitPullFromUpdateServer
+should work, of course you'll have to get the remote host to build
+propellor with that change somehow despite --spin to it not working.
+
+	diff --git a/src/Propellor/Spin.hs b/src/Propellor/Spin.hs
+	index 4a945e82..aa73e3b7 100644
+	--- a/src/Propellor/Spin.hs
+	+++ b/src/Propellor/Spin.hs
+	@@ -359,6 +359,7 @@ spinCommitMessage = "propellor spin"
+	 -- to receive the data.
+	 gitPullFromUpdateServer :: IO ()
+	 gitPullFromUpdateServer = req NeedGitPush gitPushMarker $ \_ -> do
+	+	setEnv "GIT_TRACE_PACKET" "1" True
+	 	-- IO involving stdin can cause data to be buffered in the Handle
+ 		-- (even when it's set NoBuffering), but we need to pass a FD to
+	 	-- git fetch containing all of stdin after the gitPushMarker,
+"""]]

fix html
diff --git a/doc/todo/spin_failure_HEAD.mdwn b/doc/todo/spin_failure_HEAD.mdwn
index 1a591b35..e49df633 100644
--- a/doc/todo/spin_failure_HEAD.mdwn
+++ b/doc/todo/spin_failure_HEAD.mdwn
@@ -81,7 +81,7 @@ Sending privdata (73139 bytes) to kite.kitenet.net ... done
 [2017-06-18 16:31:16 EDT] received marked GITPUSH
 [2017-06-18 16:31:16 EDT] command line:  GitPush 11 12
 16:31:16.361717 pkt-line.c:80           packet:        fetch< 17abde8439d17d49676f549f357f45eb2adce868 refs/remotes/db48x/master
-<pre>
+</pre>
 
 > > So there's an actual protocol error here; the first 13 lines
 > > of git protocol were not sent.

response
diff --git a/doc/forum/can__39__t_get_Apt.trustsKey_to_work/comment_3_1aa2a2c87eab63305143768575c2f0d9._comment b/doc/forum/can__39__t_get_Apt.trustsKey_to_work/comment_3_1aa2a2c87eab63305143768575c2f0d9._comment
new file mode 100644
index 00000000..f76ac16c
--- /dev/null
+++ b/doc/forum/can__39__t_get_Apt.trustsKey_to_work/comment_3_1aa2a2c87eab63305143768575c2f0d9._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 3"""
+ date="2018-08-26T14:34:18Z"
+ content="""
+@david, you might need to edit your config.cabal and specify a newer
+propellor version, although cabal usually picks the most recent version of
+a dependency. Propellor got the patch from this page in version 5.3.4.
+
+Anyway, I don't think the version of propellor matters, the error message
+you quote is related to
+<https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=844724>.
+I think that the apt key you're using has been generated on a newer system
+and won't work with older gpg.
+"""]]

Added a comment: pulling from a central repo via ssh
diff --git a/doc/forum/--spin_tries_to_pull_from_central_repository__63__/comment_4_75a0a229527a7c0c1633b4bd8e461607._comment b/doc/forum/--spin_tries_to_pull_from_central_repository__63__/comment_4_75a0a229527a7c0c1633b4bd8e461607._comment
new file mode 100644
index 00000000..e60cd5bb
--- /dev/null
+++ b/doc/forum/--spin_tries_to_pull_from_central_repository__63__/comment_4_75a0a229527a7c0c1633b4bd8e461607._comment
@@ -0,0 +1,27 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="pulling from a central repo via ssh"
+ date="2018-08-25T18:50:39Z"
+ content="""
+I ended up updating to a more recent propellor for other reasons, but here's my hack to have propellor fetch over ssh:
+[[!format haskell \"\"\"
+rootSsh :: Property (HasInfo + UnixLike)
+rootSsh = propertyList \"ssh setup for root\" $ props
+  & Ssh.userKeyAt (Just keypath) (User \"root\") (Context \"propellor\") (SshRsa, Tethera.Keys.propellor_deploy_ssh)
+  & Ssh.knownHost hosts \"gitolite.tethera.net\" (User \"root\")
+  & File.containsBlock configpath [ \"Host propellor-deploy\"
+                               , \"     Hostname gitolite.tethera.net\"
+                               , \"     User git\"
+                               , \"     IdentityFile ~/.ssh/propellor_deploy\"
+                               ]
+  where
+    keypath = \"/root/.ssh/propellor_deploy\"
+    configpath = \"/root/.ssh/config\"
+\"\"\"]]
+
+Propellor is used to initially deply a passwordless role key that can be used to pull from the central repo.
+One thing that surprised me a bit is that Ssh.userKeyAt expects an absolute path, or a path relative to /usr/local/propellor.
+
+
+"""]]

Added a comment: version 2
diff --git a/doc/forum/integration_with_gitolite/comment_4_448d79859b2b35e1731adfaa460aa844._comment b/doc/forum/integration_with_gitolite/comment_4_448d79859b2b35e1731adfaa460aa844._comment
new file mode 100644
index 00000000..2aaacf0b
--- /dev/null
+++ b/doc/forum/integration_with_gitolite/comment_4_448d79859b2b35e1731adfaa460aa844._comment
@@ -0,0 +1,33 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="version 2"
+ date="2018-08-25T17:25:03Z"
+ content="""
+I didn't see how you were handling keys, Sean. Did I miss something obvious or are you handling them outside propellor?
+
+Anyway, here's my second version
+[[!format haskell \"\"\"
+gitoliteKeys :: User -> [(FilePath, String)] -> Property UnixLike
+gitoliteKeys user@(User username) keys = property' (\"set up gitolite keys for \" ++ username) $ \w -> do
+      home <- liftIO (User.homedir user)
+      ensureProperty w $ go home
+  where
+    go :: FilePath -> Property UnixLike
+    go home = installKeys keys
+                `onChange` recompile
+                `requires` File.dirExists keydir
+        where
+          keydir = home </> \".gitolite/keydir/zzz/propellor\"
+          recompile = Cmd.userScriptProperty user [ \"gitolite trigger POST_COMPILE\" ]
+                      `changesFile` (home </> \"gitolite/.ssh/authorized_keys\")
+          installKeys :: [(FilePath, String)] -> Property UnixLike
+          installKeys [] = doNothing
+          installKeys ((path, content):rest) = File.hasContent (keydir </> path ++ \".pub\") [content]
+                                               `before` installKeys rest
+\"\"\"]]
+
+I spent a while talking to the gitolite author, and managed to write something more optimal than \"gitolite trigger POST_COMPILE\", but then I realized that
+had my username hardcoded into it. So it takes about 1s longer to run, but is more robust this way.
+
+"""]]

removed
diff --git a/doc/forum/integration_with_gitolite/comment_4_acaa1d125ea406c2a5617a4effc4b115._comment b/doc/forum/integration_with_gitolite/comment_4_acaa1d125ea406c2a5617a4effc4b115._comment
deleted file mode 100644
index 3a02b96e..00000000
--- a/doc/forum/integration_with_gitolite/comment_4_acaa1d125ea406c2a5617a4effc4b115._comment
+++ /dev/null
@@ -1,33 +0,0 @@
-[[!comment format=mdwn
- username="david"
- avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
- subject="getting closer"
- date="2018-08-25T17:16:48Z"
- content="""
-maybe I suffer from Haskell blindness, but I didn't see how you handled keys
-
-here's my latest revision
-[[!format haskell \"\"\"
-gitoliteKeys :: User -> [(FilePath, String)] -> Property UnixLike
-gitoliteKeys user@(User username) keys = property' (\"set up gitolite keys for \" ++ username) $ \w -> do
-      home <- liftIO (User.homedir user)
-      ensureProperty w $ go home
-  where
-    go :: FilePath -> Property UnixLike
-    go home = installKeys keys
-                `onChange` recompile
-                `requires` File.dirExists keydir
-        where
-          keydir = home </> \".gitolite/keydir/zzz/propellor\"
-          recompile = Cmd.userScriptProperty user [ \"gitolite ../triggers/post-compile/ssh-authkeys\"
-                                                  , \"gitolite ../triggers/post-compile/ssh-authkeys-shell-users bremner\"
-                                                  ]
-                      `changesFile` (home </> \"gitolite/.ssh/authorized_keys\")
-          installKeys :: [(FilePath, String)] -> Property UnixLike
-          installKeys [] = doNothing
-          installKeys ((path, content):rest) = File.hasContent (keydir </> path ++ \".pub\") [content]
-                                               `before` installKeys rest
-\"\"\"]]
-
-It still has one piece of hardcoding in it (the shell user bremner)
-"""]]

Added a comment: getting closer
diff --git a/doc/forum/integration_with_gitolite/comment_4_acaa1d125ea406c2a5617a4effc4b115._comment b/doc/forum/integration_with_gitolite/comment_4_acaa1d125ea406c2a5617a4effc4b115._comment
new file mode 100644
index 00000000..3a02b96e
--- /dev/null
+++ b/doc/forum/integration_with_gitolite/comment_4_acaa1d125ea406c2a5617a4effc4b115._comment
@@ -0,0 +1,33 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="getting closer"
+ date="2018-08-25T17:16:48Z"
+ content="""
+maybe I suffer from Haskell blindness, but I didn't see how you handled keys
+
+here's my latest revision
+[[!format haskell \"\"\"
+gitoliteKeys :: User -> [(FilePath, String)] -> Property UnixLike
+gitoliteKeys user@(User username) keys = property' (\"set up gitolite keys for \" ++ username) $ \w -> do
+      home <- liftIO (User.homedir user)
+      ensureProperty w $ go home
+  where
+    go :: FilePath -> Property UnixLike
+    go home = installKeys keys
+                `onChange` recompile
+                `requires` File.dirExists keydir
+        where
+          keydir = home </> \".gitolite/keydir/zzz/propellor\"
+          recompile = Cmd.userScriptProperty user [ \"gitolite ../triggers/post-compile/ssh-authkeys\"
+                                                  , \"gitolite ../triggers/post-compile/ssh-authkeys-shell-users bremner\"
+                                                  ]
+                      `changesFile` (home </> \"gitolite/.ssh/authorized_keys\")
+          installKeys :: [(FilePath, String)] -> Property UnixLike
+          installKeys [] = doNothing
+          installKeys ((path, content):rest) = File.hasContent (keydir </> path ++ \".pub\") [content]
+                                               `before` installKeys rest
+\"\"\"]]
+
+It still has one piece of hardcoding in it (the shell user bremner)
+"""]]

Added a comment: just needs Apt.update?
diff --git a/doc/forum/making_sure_a_package_is_at_the_latest_version/comment_2_7a911c68e4c81031c98dbefce730ade8._comment b/doc/forum/making_sure_a_package_is_at_the_latest_version/comment_2_7a911c68e4c81031c98dbefce730ade8._comment
new file mode 100644
index 00000000..8e74d21f
--- /dev/null
+++ b/doc/forum/making_sure_a_package_is_at_the_latest_version/comment_2_7a911c68e4c81031c98dbefce730ade8._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="just needs Apt.update?"
+ date="2018-08-25T13:04:50Z"
+ content="""
+Thinking about this a bit more, it should be enough to require Apt.update once per host, then rely on Apt.installed to do the right thing. I'll have to test this next time I roll out a new version. In theory I could run apt.update for a single source, but that seems to be tricky on the apt level.
+"""]]

Added a comment
diff --git a/doc/forum/making_sure_a_package_is_at_the_latest_version/comment_1_6a73c8b0de1999f05af184bf63ad014a._comment b/doc/forum/making_sure_a_package_is_at_the_latest_version/comment_1_6a73c8b0de1999f05af184bf63ad014a._comment
new file mode 100644
index 00000000..98fb61eb
--- /dev/null
+++ b/doc/forum/making_sure_a_package_is_at_the_latest_version/comment_1_6a73c8b0de1999f05af184bf63ad014a._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="comment 1"
+ date="2018-08-24T23:12:17Z"
+ content="""
+The existing properties cannot do what you want.  You are going to need to write a new one.  Simplest implementation would be something that calls `apt-get install foo=1.2.3`.
+"""]]

Added a comment: definitely network related
diff --git a/doc/todo/spin_failure_HEAD/comment_3_952939a1333d6fc24ed288a80b76f168._comment b/doc/todo/spin_failure_HEAD/comment_3_952939a1333d6fc24ed288a80b76f168._comment
new file mode 100644
index 00000000..98d7f18b
--- /dev/null
+++ b/doc/todo/spin_failure_HEAD/comment_3_952939a1333d6fc24ed288a80b76f168._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="definitely network related"
+ date="2018-08-24T13:58:49Z"
+ content="""
+I can spin the same host from a different host on the office LAN (in fact they are connected to a cheapo hub, so that might not be much of a test), and from itself. So I guess it definitely has to do with networking. Does propellor need anything other than port 22 open?
+"""]]

Added a comment: still in 5.4.1, but only on one machine
diff --git a/doc/todo/spin_failure_HEAD/comment_2_a9b7013305a7f8d58175510b57bbadd2._comment b/doc/todo/spin_failure_HEAD/comment_2_a9b7013305a7f8d58175510b57bbadd2._comment
new file mode 100644
index 00000000..a8866294
--- /dev/null
+++ b/doc/todo/spin_failure_HEAD/comment_2_a9b7013305a7f8d58175510b57bbadd2._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="still in 5.4.1, but only on one machine"
+ date="2018-08-24T10:11:16Z"
+ content="""
+I updated to 5.4.1, and I still consistenly see this trying to spin my office computer from home. Weirdly a VM running Debian stretch on the same network does not repropduce. I'll have to try from a different machine on the office network to see if that makes a difference.
+"""]]

Added a comment: still in 5.3.6
diff --git a/doc/todo/spin_failure_HEAD/comment_1_9c7d9ae7860d9cfc28e7d015b015dc2e._comment b/doc/todo/spin_failure_HEAD/comment_1_9c7d9ae7860d9cfc28e7d015b015dc2e._comment
new file mode 100644
index 00000000..8fb8a027
--- /dev/null
+++ b/doc/todo/spin_failure_HEAD/comment_1_9c7d9ae7860d9cfc28e7d015b015dc2e._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="david@1439a1cab13195a56248b6a8fd98a62028bcba8a"
+ nickname="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="still in 5.3.6"
+ date="2018-08-24T02:12:44Z"
+ content="""
+I'm seeing this problem in 5.3.6, but only when the remote is Debian stable. Both ends are running 5.3.6 built from source.
+"""]]

Added a comment: GPG keybox database version 1
diff --git a/doc/forum/can__39__t_get_Apt.trustsKey_to_work/comment_2_d5d1611896fa72bda22e5406285ade2e._comment b/doc/forum/can__39__t_get_Apt.trustsKey_to_work/comment_2_d5d1611896fa72bda22e5406285ade2e._comment
new file mode 100644
index 00000000..90151369
--- /dev/null
+++ b/doc/forum/can__39__t_get_Apt.trustsKey_to_work/comment_2_d5d1611896fa72bda22e5406285ade2e._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject=" GPG keybox database version 1"
+ date="2018-08-24T00:29:50Z"
+ content="""
+I have propellor 5.3.6 running on debian testing. If I spin to the testing host, trustsKey works fine. On stretch I get at 'GPG keybox database version 1' installed. I guess on stretch it's still building propellor from the old sources? In any case, gpg doesn't know what do do with that keybox file (i.e. gpg < file craps out). Weird but true. In any case this breaks apt-key on that host, which is unfortunate. I guess I'll try overriding the trustsKey function in my config.hs
+
+"""]]

Added a comment: Still biting me
diff --git a/doc/forum/--spin_tries_to_pull_from_central_repository__63__/comment_3_6f6485b10beb3e371c6f5371a9a9c2c4._comment b/doc/forum/--spin_tries_to_pull_from_central_repository__63__/comment_3_6f6485b10beb3e371c6f5371a9a9c2c4._comment
new file mode 100644
index 00000000..6b32f1bb
--- /dev/null
+++ b/doc/forum/--spin_tries_to_pull_from_central_repository__63__/comment_3_6f6485b10beb3e371c6f5371a9a9c2c4._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="david@1439a1cab13195a56248b6a8fd98a62028bcba8a"
+ nickname="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="Still biting me"
+ date="2018-08-23T20:32:18Z"
+ content="""
+I have a similar problem with inaccessible central repo. This crash is still biting me when spinning from a Debian stable (stretch) host to itself.
+I could potentially make the central repo accessible via adding a key, but I think the pull is too early in the process for that work out. Any other ideas? Can I just turn off this pull for some hosts?
+"""]]

Added a comment
diff --git a/doc/forum/integration_with_gitolite/comment_3_394a42544ad97e30a8e28ed10de7cd3c._comment b/doc/forum/integration_with_gitolite/comment_3_394a42544ad97e30a8e28ed10de7cd3c._comment
new file mode 100644
index 00000000..1cab310c
--- /dev/null
+++ b/doc/forum/integration_with_gitolite/comment_3_394a42544ad97e30a8e28ed10de7cd3c._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="comment 3"
+ date="2018-08-23T19:59:13Z"
+ content="""
+It's not a proper module, but my gitolite setup is here: https://git.spwhitton.name/propellor/tree/src/Propellor/Property/SiteSpecific/SPW/Sites.hs#n200
+"""]]

Added a comment: first attempt
diff --git a/doc/forum/integration_with_gitolite/comment_2_42d3e861e2044479523609ff7b339f6b._comment b/doc/forum/integration_with_gitolite/comment_2_42d3e861e2044479523609ff7b339f6b._comment
new file mode 100644
index 00000000..ab7cc893
--- /dev/null
+++ b/doc/forum/integration_with_gitolite/comment_2_42d3e861e2044479523609ff7b339f6b._comment
@@ -0,0 +1,29 @@
+[[!comment format=mdwn
+ username="david@1439a1cab13195a56248b6a8fd98a62028bcba8a"
+ nickname="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="first attempt"
+ date="2018-08-23T13:36:52Z"
+ content="""
+Here's my first attempt, so you can snicker at my clumsy Haskell.
+
+<pre>
+gitoliteKeys :: User -> Property UnixLike
+gitoliteKeys user@(User username) = property' (\"set up gitolite keys for \" ++ username) $ \w -> do
+      home <- liftIO (User.homedir user)
+      ensureProperty w $ go home
+  where
+    go :: FilePath -> Property UnixLike
+    go home = File.hasContent (home </> \".gitolite/keydir/zzz/propellor\" </> \"bremner@propellor.pub\")
+                        [ Tethera.Keys.bremner_ssh ]
+              `before`
+              (Cmd.userScriptProperty user [ \"gitolite compile\", \"gitolite trigger POST_COMPILE\" ]
+                           `changesFile` (home </> \"gitolite/.ssh/authorized_keys\"))
+</pre>
+
+
+I think the next step is something like 
+<pre>
+Directory.hasContent :: FilePath -> [ (FilePath, [Line]) ] -> Property UnixLike
+</pre>
+"""]]

Added a comment: "For people who use puppet and similar systems"
diff --git a/doc/forum/integration_with_gitolite/comment_1_b2989bbf9e980ceebf2f4cccd4d379e1._comment b/doc/forum/integration_with_gitolite/comment_1_b2989bbf9e980ceebf2f4cccd4d379e1._comment
new file mode 100644
index 00000000..2432b063
--- /dev/null
+++ b/doc/forum/integration_with_gitolite/comment_1_b2989bbf9e980ceebf2f4cccd4d379e1._comment
@@ -0,0 +1,11 @@
+[[!comment format=mdwn
+ username="david@1439a1cab13195a56248b6a8fd98a62028bcba8a"
+ nickname="david"
+ avatar="http://cdn.libravatar.org/avatar/22c2d800db6a7699139df604a67cb221"
+ subject="&quot;For people who use puppet and similar systems&quot;"
+ date="2018-08-23T01:46:30Z"
+ content="""
+Probably the sane way is to [not use the gitolite-admin repo](http://gitolite.com/gitolite/odds-and-ends/#administering-gitolite-directly-on-the-server). Aside from being unfamiliar, that means I have to deal with a bunch small config files (say 50 - 100) in propellor. So far I'm not loving the idea of converting them all to Haskell, even with a script. But maybe I'll come around to it.
+
+
+"""]]

diff --git a/doc/forum/integration_with_gitolite.mdwn b/doc/forum/integration_with_gitolite.mdwn
new file mode 100644
index 00000000..956d35c3
--- /dev/null
+++ b/doc/forum/integration_with_gitolite.mdwn
@@ -0,0 +1,2 @@
+Does anyone have any experience with integrating propellor and gitolite? I'd be happy with just ssh pubkey management.
+There seem to be two main options. The typical way of managing a gitolite site is by pushing a special git repository "gitolite-admin". There are also a script called [ukm](http://gitolite.com/gitolite/ukm.html). I'm not sure what will be the least hassle. Currently I have to manually commit and push various keys (including the keys needed for access to the propellor repos). Part of the problem could be solved by making the propellor repos available anonymously, but I still have my own ssh key(s) to manage.

removed
diff --git a/doc/forum/spinning_localhost.mdwn b/doc/forum/spinning_localhost.mdwn
deleted file mode 100644
index ac8b4d50..00000000
--- a/doc/forum/spinning_localhost.mdwn
+++ /dev/null
@@ -1 +0,0 @@
-I have several machines that don't have internet facing domain-names / IP addresses. They can pull, but they (easily) can't be pushed to. I guess I can manually spin them (or run cron jobs). I guess I need to manually add a unique hostname to each /etc/hosts, which sounds like a job for propellor, not for a human. Does anyone have any good setups to share for this kind of scenario? 

diff --git a/doc/forum/spinning_localhost.mdwn b/doc/forum/spinning_localhost.mdwn
new file mode 100644
index 00000000..ac8b4d50
--- /dev/null
+++ b/doc/forum/spinning_localhost.mdwn
@@ -0,0 +1 @@
+I have several machines that don't have internet facing domain-names / IP addresses. They can pull, but they (easily) can't be pushed to. I guess I can manually spin them (or run cron jobs). I guess I need to manually add a unique hostname to each /etc/hosts, which sounds like a job for propellor, not for a human. Does anyone have any good setups to share for this kind of scenario? 

rename forum/versioned_depends.mdwn to forum/making_sure_a_package_is_at_the_latest_version.mdwn
diff --git a/doc/forum/versioned_depends.mdwn b/doc/forum/making_sure_a_package_is_at_the_latest_version.mdwn
similarity index 100%
rename from doc/forum/versioned_depends.mdwn
rename to doc/forum/making_sure_a_package_is_at_the_latest_version.mdwn

diff --git a/doc/forum/versioned_depends.mdwn b/doc/forum/versioned_depends.mdwn
new file mode 100644
index 00000000..5eff9424
--- /dev/null
+++ b/doc/forum/versioned_depends.mdwn
@@ -0,0 +1,13 @@
+The following property sets up my wacky outbound mail setup.
+<pre>
+smtpLeaf :: Property (HasInfo + DebianLike)
+smtpLeaf = propertyList "smtp leaf node" $ props
+         & Apt.installed["nullmailer", "bsd-mailx"]
+         & File.hasPrivContent "/etc/nullmailer/remotes" anyContext
+         & tetheraApt
+         & Apt.installed ["nullmailer-extras"] & Apt.update & Apt.upgrade
+         & Ssh.userKeys (User "mail") anyContext [ (SshRsa, Tethera.Keys.mail_ssh) ]
+         & Ssh.knownHost hosts "smtp.tethera.net" (User "mail")
+</pre>
+
+The "Apt.update & Apt.upgrade" is there because nullmailer-extras is kindof a work in progress and I need to make sure that when I add a new version to the private apt repo it's drawing from, that get's installed. It works but it seems a bit slow, and more importantly upgrading everything is kindof a heavy side effect (which might even break things), in order to update this one package. Is there a better way to do this? Don't assume I know anything, I started using propellor 2 days ago...

Split mailname property out of Hostname.sane
Since bad mailname guesses can lead to ugly surprises. (API change)
Kept it in the Hostname module for easy discoverability, and similar to
Hostname.searchDomain it sets a value based on the hostname so makes sense
to keep it in that module.
Didn't implement the mailname equivilant of Hostname.setTo, because it's
trivial to write the mailname file with a custom value if desired.
This commit was sponsored by John Pellman on Patreon.
diff --git a/debian/changelog b/debian/changelog
index 1da97c15..080884ab 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,6 +1,8 @@
-propellor (5.4.2) UNRELEASED; urgency=medium
+propellor (5.5.0) UNRELEASED; urgency=medium
 
   * letsencrypt': Pass --expand to support expanding the list of domains
+  * Split mailname property out of Hostname.sane, since bad mailname
+    guesses can lead to ugly surprises. (API change)
 
  -- Joey Hess <id@joeyh.name>  Thu, 09 Aug 2018 10:54:41 -0400
 
diff --git a/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_6_3c962f6aeff10726ae469ca7f48ab34c._comment b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_6_3c962f6aeff10726ae469ca7f48ab34c._comment
new file mode 100644
index 00000000..f9666ca1
--- /dev/null
+++ b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_6_3c962f6aeff10726ae469ca7f48ab34c._comment
@@ -0,0 +1,7 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 6"""
+ date="2018-08-19T17:22:18Z"
+ content="""
+Ok, did that.
+"""]]
diff --git a/joeyconfig.hs b/joeyconfig.hs
index 4b9fb785..05c93346 100644
--- a/joeyconfig.hs
+++ b/joeyconfig.hs
@@ -66,6 +66,7 @@ darkstar = host "darkstar.kitenet.net" $ props
 	& osDebian Unstable X86_64
 	& ipv6 "2001:4830:1600:187::2"
 	& Hostname.sane
+	& Hostname.mailname
 	& Apt.serviceInstalledRunning "swapspace"
 	& Laptop.powertopAutoTuneOnBoot
 	& Laptop.trimSSD
@@ -461,6 +462,7 @@ keysafe :: Host
 keysafe = host "keysafe.joeyh.name" $ props
 	& ipv4 "139.59.17.168"
 	& Hostname.sane
+	& Hostname.mailname
 	& osDebian (Stable "stretch") X86_64
 	& Apt.stdSourcesList `onChange` Apt.upgrade
 	& Apt.unattendedUpgrades
@@ -565,6 +567,7 @@ standardSystemUnhardened :: DebianSuite -> Architecture -> Motd -> Property (Has
 standardSystemUnhardened suite arch motd = propertyList "standard system" $ props
 	& osDebian suite arch
 	& Hostname.sane
+	& Hostname.mailname
 	& Hostname.searchDomain
 	& Locale.available "en_US.UTF-8"
 	& File.hasContent "/etc/motd" ("":motd++[""])
diff --git a/propellor.cabal b/propellor.cabal
index 26c05a1d..904a8f64 100644
--- a/propellor.cabal
+++ b/propellor.cabal
@@ -1,5 +1,5 @@
 Name: propellor
-Version: 5.4.1
+Version: 5.5.0
 Cabal-Version: 1.20
 License: BSD2
 Maintainer: Joey Hess <id@joeyh.name>
diff --git a/src/Propellor/Property/HostingProvider/CloudAtCost.hs b/src/Propellor/Property/HostingProvider/CloudAtCost.hs
index 48c19572..839aa14e 100644
--- a/src/Propellor/Property/HostingProvider/CloudAtCost.hs
+++ b/src/Propellor/Property/HostingProvider/CloudAtCost.hs
@@ -13,6 +13,7 @@ import qualified Propellor.Property.User as User
 decruft :: Property DebianLike
 decruft = propertyList "cloudatcost cleanup" $ props
 	& Hostname.sane
+	& Hostname.mailname
 	& grubbugfix
 	& nukecruft
   where
diff --git a/src/Propellor/Property/Hostname.hs b/src/Propellor/Property/Hostname.hs
index 1eb9d690..0ece92a8 100644
--- a/src/Propellor/Property/Hostname.hs
+++ b/src/Propellor/Property/Hostname.hs
@@ -14,8 +14,6 @@ import Data.List
 -- (However, when used inside a chroot, avoids setting the current hostname
 -- as that would impact the system outside the chroot.)
 --
--- Configures </etc/mailname> with the domain part of the hostname.
---
 -- </etc/hosts> is also configured, with an entry for 127.0.1.1, which is
 -- standard at least on Debian to set the FDQN.
 --
@@ -46,8 +44,6 @@ setTo' extractdomain hn = combineProperties desc $ toProps
 	, check (not <$> inChroot) $
 		cmdProperty "hostname" [basehost]
 			`assume` NoChange
-	, "/etc/mailname" `File.hasContent`
-		[if null domain then hn else domain]
 	]
   where
 	desc = "hostname " ++ hn
@@ -85,6 +81,19 @@ searchDomain' extractdomain = property' desc $ \w ->
 			| "search " `isPrefixOf` l = False
 			| otherwise = True
 
+-- Configures </etc/mailname> with the domain part of the hostname of the
+-- `Host` it's used in.
+mailname :: Property UnixLike
+mailname = mailname' extractDomain
+
+mailname' :: ExtractDomain -> Property UnixLike
+mailname' extractdomain = property' ("mailname set from hostname") $ \w ->
+	ensureProperty w . go =<< asks hostName
+  where
+	go mn = "/etc/mailname" `File.hasContent` [if null mn' then mn else mn']
+	  where
+	 	mn' = extractdomain mn
+
 -- | Function to extract the domain name from a HostName.
 type ExtractDomain = HostName -> String
 
diff --git a/src/Propellor/Property/Installer/Target.hs b/src/Propellor/Property/Installer/Target.hs
index 8c865143..c6889dc5 100644
--- a/src/Propellor/Property/Installer/Target.hs
+++ b/src/Propellor/Property/Installer/Target.hs
@@ -24,6 +24,7 @@
 -- > seed ver = host "debian.local" $ props
 -- > 	& osDebian Unstable X86_64
 -- > 	& Hostname.sane
+-- >	& Hostname.mailname
 -- > 	& Apt.stdSourcesList
 -- > 	& Apt.installed ["linux-image-amd64"]
 -- > 	& Grub.installed PC
diff --git a/src/Propellor/Property/OS.hs b/src/Propellor/Property/OS.hs
index c31bef7b..503f303d 100644
--- a/src/Propellor/Property/OS.hs
+++ b/src/Propellor/Property/OS.hs
@@ -58,6 +58,7 @@ import Control.Exception (throw)
 -- >        -- , oldOsRemoved (Confirmed "foo.example.com")
 -- >        ]
 -- > & Hostname.sane
+-- > & Hostname.mailname
 -- > & Apt.installed ["linux-image-amd64"]
 -- > & Apt.installed ["ssh"]
 -- > & User.hasSomePassword "root"

Added a comment
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_8_39bead6f61bd8e458bf8eaf992757e62._comment b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_8_39bead6f61bd8e458bf8eaf992757e62._comment
new file mode 100644
index 00000000..776e3fba
--- /dev/null
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_8_39bead6f61bd8e458bf8eaf992757e62._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="mithrandi"
+ avatar="http://cdn.libravatar.org/avatar/869963bdf99b541c9f0bbfb04b0320f1"
+ subject="comment 8"
+ date="2018-08-18T14:19:42Z"
+ content="""
+I tested printing out the encoding after changing it to make sure it was UTF-8, and it is, but the privdata is somehow still corrupt. Could the problem have something to do with writing out the privdata instead?
+"""]]

Added a comment
diff --git a/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_5_b4c1265f881e96d999528d8a433176cc._comment b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_5_b4c1265f881e96d999528d8a433176cc._comment
new file mode 100644
index 00000000..0f1ba25c
--- /dev/null
+++ b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_5_b4c1265f881e96d999528d8a433176cc._comment
@@ -0,0 +1,24 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="comment 5"
+ date="2018-08-17T14:36:19Z"
+ content="""
+I worked around the problem in the following way:
+
+    module Propellor.Property.SiteSpecific.SPW.Hostname (sane) where
+
+    import Propellor.Base
+    import qualified Propellor.Property.Hostname as Hostname
+
+    sane :: Property UnixLike
+    sane = Hostname.sane' id
+
+> How about we add a separate mailname property and make Hostname.sane not touch the mailname. mailname could take a Maybe and guess based on the hostname when Nothing is specified.
+
+This seems reasonable.  `Hostname.sane` is often wanted but `Mailname.sane` will be wanted only occasionally, so it makes sense for them to be separate properties.
+
+> Or, the mailname property could only set Info, and Hostname.sane use that info when set and guess when not. But, I suspect that would not have avoided your email-losing misconfiguration from happening in the first place.
+
+This wouldn't be much different from my workaround, indeed.
+"""]]

followup
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_7_959c8da37727c46436c5905bc6fabd88._comment b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_7_959c8da37727c46436c5905bc6fabd88._comment
new file mode 100644
index 00000000..a0fefc17
--- /dev/null
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_7_959c8da37727c46436c5905bc6fabd88._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 7"""
+ date="2018-08-16T15:37:48Z"
+ content="""
+Since `update` receives the changes to propellor's source code,
+it would have been running the old code at that point. You
+probably need to spin a second time to test your changes to that function.
+"""]]

followup
diff --git a/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_4_2c90ee4cd4fe54299ce9742c28730b9a._comment b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_4_2c90ee4cd4fe54299ce9742c28730b9a._comment
new file mode 100644
index 00000000..b67a80d8
--- /dev/null
+++ b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_4_2c90ee4cd4fe54299ce9742c28730b9a._comment
@@ -0,0 +1,18 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 4"""
+ date="2018-08-16T15:23:09Z"
+ content="""
+I notice that the property is certianly wrong for domains such as
+"foo.org.uk". And I don't want to build in the list of exceptions needed to
+properly deal with those.
+
+How about we add a separate mailname property and make Hostname.sane not
+touch the mailname. mailname could take a Maybe and guess based on the
+hostname when Nothing is specified.
+
+Or, the mailname property could only set Info, and Hostname.sane
+use that info when set and guess when not. But, I suspect that would not
+have avoided your email-losing misconfiguration from happening in the first
+place.
+"""]]

Added a comment
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_6_ce746457c2a7654a090885ad960eb983._comment b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_6_ce746457c2a7654a090885ad960eb983._comment
new file mode 100644
index 00000000..01748242
--- /dev/null
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_6_ce746457c2a7654a090885ad960eb983._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="mithrandi"
+ avatar="http://cdn.libravatar.org/avatar/869963bdf99b541c9f0bbfb04b0320f1"
+ subject="comment 6"
+ date="2018-08-16T15:35:27Z"
+ content="""
+The `hSetEncoding stdin utf8` in `update` doesn't seem to work unfortunately, not sure why not.
+"""]]

response
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_5_f12c57263372437edbcdfe89cd69b95d._comment b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_5_f12c57263372437edbcdfe89cd69b95d._comment
new file mode 100644
index 00000000..51f25ecc
--- /dev/null
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_5_f12c57263372437edbcdfe89cd69b95d._comment
@@ -0,0 +1,17 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 5"""
+ date="2018-08-16T15:12:58Z"
+ content="""
+Ah, good debugging!
+
+The code that runs on the remote side is Propellor.Spin.update,
+and it uses Propellor.Protocol.req which reads from stdin. So,
+I think that putting `hSetEncoding stdin utf8` in the update function
+may fix it for you.
+
+If so, the real fix will involve making propellor force utf8 on both sides
+of its protocol, because the spin might be run in some other locale too.
+(Or chainging to a binary protocol that doesn't suffer 
+from encoding mismatch problems, if someone is ambitious!)
+"""]]

Added a comment
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_4_7f6773e21b9bb62961b0c291d0f8b7d0._comment b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_4_7f6773e21b9bb62961b0c291d0f8b7d0._comment
new file mode 100644
index 00000000..733f7d33
--- /dev/null
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_4_7f6773e21b9bb62961b0c291d0f8b7d0._comment
@@ -0,0 +1,20 @@
+[[!comment format=mdwn
+ username="mithrandi"
+ avatar="http://cdn.libravatar.org/avatar/869963bdf99b541c9f0bbfb04b0320f1"
+ subject="comment 4"
+ date="2018-08-16T13:12:35Z"
+ content="""
+Err, this patch:
+
+    --- a/src/Propellor/Spin.hs
+    +++ b/src/Propellor/Spin.hs
+    @@ -181,6 +181,8 @@
+     -- running the updateServer
+     update :: Maybe HostName -> IO ()
+     update forhost = do
+    +       hPrint stderr =<< hGetEncoding stdin
+    +       hSetEncoding stdin utf8
+            whenM hasGitRepo $
+                    req NeedRepoUrl repoUrlMarker setRepoUrl
+
+"""]]

Added a comment
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_3_c51e4ae44dc6401af54f109f2cb70995._comment b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_3_c51e4ae44dc6401af54f109f2cb70995._comment
new file mode 100644
index 00000000..05b5956b
--- /dev/null
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_3_c51e4ae44dc6401af54f109f2cb70995._comment
@@ -0,0 +1,23 @@
+[[!comment format=mdwn
+ username="mithrandi"
+ avatar="http://cdn.libravatar.org/avatar/869963bdf99b541c9f0bbfb04b0320f1"
+ subject="comment 3"
+ date="2018-08-15T19:15:21Z"
+ content="""
+I tried this patch:
+
+```
+--- a/src/Propellor/Spin.hs
++++ b/src/Propellor/Spin.hs
+@@ -181,6 +181,8 @@ getSshTarget target hst
+ -- running the updateServer
+ update :: Maybe HostName -> IO ()
+ update forhost = do
++       hPrint stderr =<< hGetEncoding stdin
++       hSetEncoding stdin utf8
+        whenM hasGitRepo $
+                req NeedRepoUrl repoUrlMarker setRepoUrl
+```
+
+I get `Just ANSI_X3.4-1968` from the remote side but unfortunately the corruption persists.
+"""]]

Added a comment
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_2_2a4f3ddcc92f0cf8be2472d2a45e69cc._comment b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_2_2a4f3ddcc92f0cf8be2472d2a45e69cc._comment
new file mode 100644
index 00000000..d4d596d8
--- /dev/null
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_2_2a4f3ddcc92f0cf8be2472d2a45e69cc._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="mithrandi"
+ avatar="http://cdn.libravatar.org/avatar/869963bdf99b541c9f0bbfb04b0320f1"
+ subject="comment 2"
+ date="2018-08-15T18:53:03Z"
+ content="""
+I get `Just UTF-8` in both cases and the corruption is not fixed. I think the problem may be on the _receiving_ side? On macOS my `$LC_CTYPE` is set to `\"UTF-8\"` which is passed through by SSH but is an invalid locale on Linux. Running `env LC_CTYPE=C.UTF-8 ./propellor --spin blah` fixes the corruption.
+"""]]

response
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_1_0443c1dc8f7a74864c2a981740992ee4._comment b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_1_0443c1dc8f7a74864c2a981740992ee4._comment
new file mode 100644
index 00000000..3b047d9d
--- /dev/null
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS/comment_1_0443c1dc8f7a74864c2a981740992ee4._comment
@@ -0,0 +1,27 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2018-08-14T21:33:55Z"
+ content="""
+Sounds like a problem with sendPrivData, which writes it to a Handle that's 
+connected to propellor on the host being spun.
+
+Handles have an associated encoding, which comes from the locale settings.
+The char8 TextEncoding sounds like what you describe (code point modulo
+256). hSetEncoding can change it.
+
+Here's a patch you could try that prints out the encoding in use and tries
+to force utf8.
+
+	--- a/src/Propellor/Spin.hs
+	+++ b/src/Propellor/Spin.hs
+	@@ -252,6 +252,8 @@ sendRepoUrl hst toh = sendMarked toh repoUrlMarker =<< geturl
+	
+	 sendPrivData :: HostName -> Handle -> PrivMap -> IO ()
+	 sendPrivData hn toh privdata = void $ actionMessage msg $ do
+	+	hPutStrLn stderr . show =<< hGetEncoding toh
+	+	hSetEncoding toh utf8
+ 		sendMarked toh privDataMarker d
+	 	return True
+	   where
+"""]]

Fix another typo
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn b/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn
index 2cc827b1..d4df4bac 100644
--- a/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn
@@ -1 +1 @@
-I recently added a binary file as privdata (installed with `File.hasPrivContent`). When I `propellor --dump` the property on either Linux or macOS, the contents is correct. Spinning from Linux also works, but spinning from macOS installs a corrupt version of the file. The corruption looks like every valid UTF-8 sequence has been replaced with a single byte which is the lowest byte of the Unicode codepoint encoded by the sequence, so this must have something to do with encodings, but from staring at the source code I can't figure out what. The data from `--dump` is not corrupted which seems especially strange.
+I recently added a binary file as privdata (installed with `File.hasPrivContent`). When I `propellor --dump` the privdata on either Linux or macOS, the contents is correct. Spinning from Linux also works, but spinning from macOS installs a corrupt version of the file. The corruption looks like every valid UTF-8 sequence has been replaced with a single byte which is the lowest byte of the Unicode codepoint encoded by the sequence, so this must have something to do with encodings, but from staring at the source code I can't figure out what. The data from `--dump` is not corrupted which seems especially strange.

Fix typo
diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn b/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn
index e3e6e0f9..2cc827b1 100644
--- a/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn
@@ -1 +1 @@
-I recently added a binary file as privdata (installed with `File.hasPrivContents`). When I `propellor --dump` the property on either Linux or macOS, the contents is correct. Spinning from Linux also works, but spinning from macOS installs a corrupt version of the file. The corruption looks like every valid UTF-8 sequence has been replaced with a single byte which is the lowest byte of the Unicode codepoint encoded by the sequence, so this must have something to do with encodings, but from staring at the source code I can't figure out what. The data from `--dump` is not corrupted which seems especially strange.
+I recently added a binary file as privdata (installed with `File.hasPrivContent`). When I `propellor --dump` the property on either Linux or macOS, the contents is correct. Spinning from Linux also works, but spinning from macOS installs a corrupt version of the file. The corruption looks like every valid UTF-8 sequence has been replaced with a single byte which is the lowest byte of the Unicode codepoint encoded by the sequence, so this must have something to do with encodings, but from staring at the source code I can't figure out what. The data from `--dump` is not corrupted which seems especially strange.

diff --git a/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn b/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn
new file mode 100644
index 00000000..e3e6e0f9
--- /dev/null
+++ b/doc/forum/Privdata_corrupted_when_spinning_from_macOS.mdwn
@@ -0,0 +1 @@
+I recently added a binary file as privdata (installed with `File.hasPrivContents`). When I `propellor --dump` the property on either Linux or macOS, the contents is correct. Spinning from Linux also works, but spinning from macOS installs a corrupt version of the file. The corruption looks like every valid UTF-8 sequence has been replaced with a single byte which is the lowest byte of the Unicode codepoint encoded by the sequence, so this must have something to do with encodings, but from staring at the source code I can't figure out what. The data from `--dump` is not corrupted which seems especially strange.

fix sequence
diff --git a/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_2_d82e10087205a4b2896e4fd07032643d._comment b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_3_d82e10087205a4b2896e4fd07032643d._comment
similarity index 91%
rename from doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_2_d82e10087205a4b2896e4fd07032643d._comment
rename to doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_3_d82e10087205a4b2896e4fd07032643d._comment
index 24c0efcf..df002711 100644
--- a/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_2_d82e10087205a4b2896e4fd07032643d._comment
+++ b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_3_d82e10087205a4b2896e4fd07032643d._comment
@@ -1,6 +1,6 @@
 [[!comment format=mdwn
  username="joey"
- subject="""comment 2"""
+ subject="""comment 3"""
  date="2018-08-10T14:56:07Z"
  content="""
 I have probably generalized too much from my own use case then, where

followup
diff --git a/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_2_d82e10087205a4b2896e4fd07032643d._comment b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_2_d82e10087205a4b2896e4fd07032643d._comment
new file mode 100644
index 00000000..24c0efcf
--- /dev/null
+++ b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_2_d82e10087205a4b2896e4fd07032643d._comment
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2018-08-10T14:56:07Z"
+ content="""
+I have probably generalized too much from my own use case then, where
+I always have foo.example.com as the full hostname, but want mail to be
+sent with example.com as the name.
+"""]]

Added a comment
diff --git a/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_2_ac8e2bdd7bd16058f46ef8352df09700._comment b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_2_ac8e2bdd7bd16058f46ef8352df09700._comment
new file mode 100644
index 00000000..3cdfaeaa
--- /dev/null
+++ b/doc/forum/mailname_set_by_Propellor.Property.Hostname.sane/comment_2_ac8e2bdd7bd16058f46ef8352df09700._comment
@@ -0,0 +1,10 @@
+[[!comment format=mdwn
+ username="spwhitton"
+ avatar="http://cdn.libravatar.org/avatar/9c3f08f80e67733fd506c353239569eb"
+ subject="comment 2"
+ date="2018-08-10T10:36:35Z"
+ content="""
+Could you explain why it's right to not use the full hostname, please?
+
+Careless use of `Hostname.sane` on my part recently broke my mail sending setup.  I discovered that I am relying on /etc/mailname containing the full hostname, but maybe I should not be doing that.
+"""]]

letsencrypt': Pass --expand to support expanding the list of domains
diff --git a/debian/changelog b/debian/changelog
index 171cd8fe..1da97c15 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+propellor (5.4.2) UNRELEASED; urgency=medium
+
+  * letsencrypt': Pass --expand to support expanding the list of domains
+
+ -- Joey Hess <id@joeyh.name>  Thu, 09 Aug 2018 10:54:41 -0400
+
 propellor (5.4.1) unstable; urgency=medium
 
   * Modernized and simplified the MetaTypes implementation now that
diff --git a/doc/forum/Certbot_cert_expanding/comment_2_2a16c69729cff4262c9a37b264c60ae0._comment b/doc/forum/Certbot_cert_expanding/comment_2_2a16c69729cff4262c9a37b264c60ae0._comment
new file mode 100644
index 00000000..8aba068a
--- /dev/null
+++ b/doc/forum/Certbot_cert_expanding/comment_2_2a16c69729cff4262c9a37b264c60ae0._comment
@@ -0,0 +1,7 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2018-08-09T14:55:33Z"
+ content="""
+Ok, patched it in.
+"""]]
diff --git a/src/Propellor/Property/LetsEncrypt.hs b/src/Propellor/Property/LetsEncrypt.hs
index 9e4898dd..99c23715 100644
--- a/src/Propellor/Property/LetsEncrypt.hs
+++ b/src/Propellor/Property/LetsEncrypt.hs
@@ -77,6 +77,9 @@ letsEncrypt' (AgreeTOS memail) domain domains webroot =
 		, "--text"
 		, "--noninteractive"
 		, "--keep-until-expiring"
+		-- The list of domains may be changed, adding more, so
+		-- always request expansion.
+		, "--expand"
 		] ++ map (\d -> "--domain="++d) alldomains
 
 	getstats = mapM statcertfiles alldomains

Added a comment
diff --git a/doc/forum/Certbot_cert_expanding/comment_2_a4ca6b57c77651936c7f74f730f832e7._comment b/doc/forum/Certbot_cert_expanding/comment_2_a4ca6b57c77651936c7f74f730f832e7._comment
new file mode 100644
index 00000000..f1af3dca
--- /dev/null
+++ b/doc/forum/Certbot_cert_expanding/comment_2_a4ca6b57c77651936c7f74f730f832e7._comment
@@ -0,0 +1,8 @@
+[[!comment format=mdwn
+ username="mithrandi"
+ avatar="http://cdn.libravatar.org/avatar/869963bdf99b541c9f0bbfb04b0320f1"
+ subject="comment 2"
+ date="2018-08-09T13:18:37Z"
+ content="""
+I have now tested this and it works fine.
+"""]]

add news item for propellor 5.4.1
diff --git a/doc/news/version_5.3.3.mdwn b/doc/news/version_5.3.3.mdwn
deleted file mode 100644
index 18f80d5f..00000000
--- a/doc/news/version_5.3.3.mdwn
+++ /dev/null
@@ -1,8 +0,0 @@
-propellor 5.3.3 released with [[!toggle text="these changes"]]
-[[!toggleable text="""
-   * Warn again about new upstream version when ~/.propellor was cloned from the
-     Debian git bundle using an older version of propellor that set up an
-     upstream remote.
-   * Avoid crashing if initial fetch from origin fails when spinning a host.
-   * Added Propllor.Property.Openssl module contributed by contributed by
-     Félix Sipma."""]]
\ No newline at end of file
diff --git a/doc/news/version_5.4.1.mdwn b/doc/news/version_5.4.1.mdwn
new file mode 100644
index 00000000..ebb0e261
--- /dev/null
+++ b/doc/news/version_5.4.1.mdwn
@@ -0,0 +1,14 @@
+propellor 5.4.1 released with [[!toggle text="these changes"]]
+[[!toggleable text="""
+   * Modernized and simplified the MetaTypes implementation now that
+     compatability with ghc 7 is no longer needed.
+   * Use git verify-commit to verify gpg signatures, rather than the old
+     method of parsing git log output. Needs git 2.0.
+   * Added ConfFile.containsShellSetting, ConfFile.lacksShellSetting,
+     and EtcDefault.set properties. Thanks, Sean Whitton
+   * Dns: Support TXT values longer than bind's maximum string length
+     of 255 bytes. Thanks, rsiddharth.
+   * Docker and HostingProvider.CloudAtCost modules are not being
+     maintained, so marked them as such.
+     Seeking a maintainer for the Docker module; I anticipate
+     removing the CloudAtCost module in the next API bump."""]]
\ No newline at end of file

response
diff --git a/doc/forum/Certbot_cert_expanding/comment_1_1f6b33d757294b69172a9b59b2c0ea4f._comment b/doc/forum/Certbot_cert_expanding/comment_1_1f6b33d757294b69172a9b59b2c0ea4f._comment
new file mode 100644
index 00000000..fb7354d1
--- /dev/null
+++ b/doc/forum/Certbot_cert_expanding/comment_1_1f6b33d757294b69172a9b59b2c0ea4f._comment
@@ -0,0 +1,15 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2018-07-31T14:25:34Z"
+ content="""
+Makes sense. The man page says:
+
+            --expand              If an existing certificate is a strict subset of the
+                                  requested names, always expand and replace it with the
+                                  additional names. (default: Ask)
+
+Which reads like it will not change behavior in other cases. 
+Still, it would be good for someone to test it before the change is
+made to propellor..
+"""]]

diff --git a/doc/forum/Certbot_cert_expanding.mdwn b/doc/forum/Certbot_cert_expanding.mdwn
index db67cbf3..90be60d6 100644
--- a/doc/forum/Certbot_cert_expanding.mdwn
+++ b/doc/forum/Certbot_cert_expanding.mdwn
@@ -1,14 +1,16 @@
 When adding a name to the list for a `letsEncrypt` property, certbot fails thusly:
 
-Saving debug log to /var/log/letsencrypt/letsencrypt.log
-Plugins selected: Authenticator webroot, Installer None
-Missing command line flag or config entry for this setting:
-You have an existing certificate that contains a portion of the domains you requested (ref: /etc/letsencrypt/renewal/fusionapp.com.conf)
+    Saving debug log to /var/log/letsencrypt/letsencrypt.log
+    Plugins selected: Authenticator webroot, Installer None
+    Missing command line flag or config entry for this setting:
+    You have an existing certificate that contains a portion of the domains you requested (ref: /etc/letsencrypt/renewal/…)
 
-It contains these names: fusionapp.com, bn.fusionapp.com, bz-entropy.fusionapp.com, bz-ext.fusionapp.com, bz.fusionapp.com, entropy.fusionapp.com, prod.fusionapp.com
+    It contains these names: …
 
-You requested these names for the new certificate: fusionapp.com, entropy.fusionapp.com, bz-entropy.fusionapp.com, bz-ext.fusionapp.com, prod.fusionapp.com, bz.fusionapp.com, bn.fusionapp.com, entropy.fusiontest.net.
+    You requested these names for the new certificate: …
 
-Do you want to expand and replace this existing certificate with the new certificate?
+    Do you want to expand and replace this existing certificate with the new certificate?
 
-(You can set this with the --expand flag)
+    (You can set this with the --expand flag)
+
+I think maybe Propellor should always pass --expand? I haven't tested if that works correctly when not changing the names.

diff --git a/doc/forum/Certbot_cert_expanding.mdwn b/doc/forum/Certbot_cert_expanding.mdwn
new file mode 100644
index 00000000..db67cbf3
--- /dev/null
+++ b/doc/forum/Certbot_cert_expanding.mdwn
@@ -0,0 +1,14 @@
+When adding a name to the list for a `letsEncrypt` property, certbot fails thusly:
+
+Saving debug log to /var/log/letsencrypt/letsencrypt.log
+Plugins selected: Authenticator webroot, Installer None
+Missing command line flag or config entry for this setting:
+You have an existing certificate that contains a portion of the domains you requested (ref: /etc/letsencrypt/renewal/fusionapp.com.conf)
+
+It contains these names: fusionapp.com, bn.fusionapp.com, bz-entropy.fusionapp.com, bz-ext.fusionapp.com, bz.fusionapp.com, entropy.fusionapp.com, prod.fusionapp.com
+
+You requested these names for the new certificate: fusionapp.com, entropy.fusionapp.com, bz-entropy.fusionapp.com, bz-ext.fusionapp.com, prod.fusionapp.com, bz.fusionapp.com, bn.fusionapp.com, entropy.fusiontest.net.
+
+Do you want to expand and replace this existing certificate with the new certificate?
+
+(You can set this with the --expand flag)