summaryrefslogtreecommitdiff
path: root/src/Propellor/Property/OS.hs
blob: c96e20b3dd560b9dd69b80cfc8fff0d0fd628b35 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
module Propellor.Property.OS (
	cleanInstallOnce,
	Confirmation
	confirm,
	fixupNetworkAddresses,
	fixupRootSsh,
	oldOSRemoved,
) where

import Propellor
import qualified Propellor.Property.Chroot as Chroot
import qualified Propellor.Property.Debootstrap as Debootstrap

-- | Replaces whatever OS was installed before with a clean installation
-- of the OS that the Host is configured to have.
--
-- This can replace one Linux distribution with different one.
-- But, it can also fail and leave the system in an unbootable state.
--
-- To avoid this property being accidentially used, you have to provide
-- a Context containing the name of the host that you intend to apply the
-- property to.
--
-- This property only runs once. The cleanly installed system will have
-- a file /etc/propellor-cleaninstall, which indicates it was cleanly
-- installed.
--
-- You will typically want to run some more properties after the clean
-- install, to bootstrap from the cleanly installed system to a fully
-- working system. For example:
--
-- > & os (System (Debian Unstable) "amd64")
-- > & cleanInstall (Context "foo.example.com") (BackupOldOS <> UseOldKernel)
-- >    `onChange` propertyList "fixing up after clean install"
-- >        [ fixupNetworkInterfaces
-- >        , fixupRootSsh
-- >        -- , installDistroKernel
-- >        -- , installGrub
-- >        ]
-- > & Apt.installed ["ssh"]
-- > & User.hasSomePassword "root"
-- > & User.accountFor "joey"
-- > & User.hasSomePassword "joey"
-- > -- rest of system properties here
cleanInstallOnce :: Context -> Exceptions -> Property
cleanInstallOnce (Context c) = check (not <$> doesFileExist flagfile) $
	Property "OS cleanly installed" $ do
		hostname <- asks hostName
		when (hostname /= c) $
			error "Run with bad context, not matching hostname. Not running cleanInstalOnce!"
		error "TODO"
		-- debootstrap /new-os chroot, but don't run propellor
		--   inside the chroot.
		-- unmount all mounts
		-- move all directories to /old-os,
		--   except for /boot and /lib/modules
		-- move /new-os to /
		-- touch flagfile
		-- re-bootstrap propellor in /usr/local/propellor,
		--   (using git repo bundle, privdata file, and possibly
		--   git repo url, which all need to be arranged to
		--   be present in /old-os's /usr/local/propellor)
		-- enable shadow passwords (to avoid foot-shooting)
		-- return MadeChange
  where
	flagfile = "/etc/propellor-cleaninstall"

-- | Sometimes you want an almost clean install, but with some exceptions.
data Exceptions
	= UseOldKernel -- ^ Leave /boot and /lib/modules from old OS, so the system can boot using them as before
	| BackupOldOS -- ^ Back up old OS to /old-os, to avoid losing any important files
	| NoExceptions
	| CombinedExceptions Exceptions Exceptions

instance Monoid Exceptions where
	mempty = NoExceptions
	mappend = CombinedExceptions

-- /etc/network/interfaces is configured to bring up all interfaces that
-- are currently up, using the same IP addresses.
--
-- This property only does anything if it comes after cleanInstall,
-- in the same propellor run where cleanInstall has made a change.
fixupNetworkInterfaces :: Property
fixupNetworkInterfaces = undefined

-- /root/.ssh/authorized_keys is copied from the old os
fixupRootSsh :: Property
fixupRootSsh = undefined

-- Installs an appropriate kernel from the distribution.
installDistroKernel :: Property
installDistroKernel = undefined

-- Installs grub to boot the system.
installGrub :: Property
installGrub = undefined

-- Removes the old OS's backup from /old-os
oldOSRemoved :: Property
oldOSRemoved = check (doesDirectoryExist oldOsDir) $
	Property "old OS backup removed" $ liftIO $ do
		removeDirectoryRecursive oldOsDir
		return MadeChange

oldOsDir :: FilePath
oldOsDir = "/old-os"