From a2537ce16c55871907bce64be108b10c2ee6283b Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 16:14:01 -0400 Subject: [PATCH 01/19] propellor spin --- config-joey.hs | 10 ++--- src/Propellor/Property/OS.hs | 78 +++++++++++++++++++++++----------- src/Propellor/Property/User.hs | 12 ++++++ 3 files changed, 70 insertions(+), 30 deletions(-) diff --git a/config-joey.hs b/config-joey.hs index b617ccf..03f2133 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -54,11 +54,11 @@ hosts = -- (o) ` testvm :: Host testvm = host "testvm.kitenet.net" - & Chroot.provisioned (Chroot.debootstrapped (System (Debian Unstable) "amd64") Debootstrap.DefaultConfig "/new-os") - -- & OS.cleanInstall (OS.Confirmed "foo.example.com") [] - -- `onChange` propertyList "fixing up after clean install" - -- [ - -- ] + & os (System (Debian Unstable) "amd64") + & OS.cleanInstallOnce (OS.Confirmed "testvm.kitenet.netno") + `onChange` propertyList "fixing up after clean install" + [ OS.preserveRootSshAuthorized + ] darkstar :: Host darkstar = host "darkstar.kitenet.net" diff --git a/src/Propellor/Property/OS.hs b/src/Propellor/Property/OS.hs index 5dddff2..ce8f44f 100644 --- a/src/Propellor/Property/OS.hs +++ b/src/Propellor/Property/OS.hs @@ -1,20 +1,19 @@ module Propellor.Property.OS ( cleanInstallOnce, - Confirmed(..), + Confirmation(..), preserveNetworkInterfaces, preserveRootSshAuthorized, grubBoots, GrubDev(..), + oldOSKernelPreserved, kernelInstalled, oldOSRemoved, ) where import Propellor -import qualified Propellor.Property.Chroot as Chroot import qualified Propellor.Property.Debootstrap as Debootstrap -import qualified Propellor.Property.File as File import qualified Propellor.Property.Ssh as Ssh -import Utility.FileMode +import qualified Propellor.Property.User as User -- | Replaces whatever OS was installed before with a clean installation -- of the OS that the Host is configured to have. @@ -22,8 +21,10 @@ import Utility.FileMode -- This can replace one Linux distribution with different one. -- But, it can also fail and leave the system in an unbootable state. -- +-- The files from the old os will be left in /old-os +-- -- To avoid this property being accidentially used, you have to provide --- a Confirmed containing the name of the host that you intend to apply the +-- a Confirmation 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 @@ -35,53 +36,73 @@ import Utility.FileMode -- working system. For example: -- -- > & os (System (Debian Unstable) "amd64") --- > & cleanInstall (Confirmed "foo.example.com") [BackupOldOS, UseOldKernel] +-- > & cleanInstall (Confirmed "foo.example.com") -- > `onChange` propertyList "fixing up after clean install" -- > [ preserveNetworkInterfaces -- > , preserverRootSshAuthorized +-- > , oldOSKernelPreserved -- > -- , kernelInstalled -- > -- , grubBoots "hd0" +-- > -- , oldOsRemoved -- > ] -- > & Apt.installed ["ssh"] -- > & User.hasSomePassword "root" -- > & User.accountFor "joey" -- > & User.hasSomePassword "joey" -- > -- rest of system properties here -cleanInstallOnce :: Confirmed -> [Tweak] -> Property -cleanInstallOnce confirmed tweaks = check (not <$> doesFileExist flagfile) $ - property "OS cleanly installed" $ do - checkConfirmed confirmed +cleanInstallOnce :: Confirmation -> Property +cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ + confirmed + `before` + osbootstrapped + `before` + transitioned + `before` + User.shadowConfig True + `before` + propellorbootstrapped + `before` + finalized + where + confirmed = property "clean install confirmed" $ do + checkConfirmed confirmation + return NoChange + + osbootstrapped = withOS "/new-os bootstrapped" $ \o -> case o of + (Just d@(System (Debian _) _)) -> debootstrap d + (Just u@(System (Ubuntu _) _)) -> debootstrap u + _ -> error "os is not declared to be Debian or Ubuntu" + debootstrap targetos = ensureProperty $ toProp $ + Debootstrap.built "/new-os" targetos Debootstrap.DefaultConfig + + transitioned = property "/new-os moved into place" $ 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 when UseOldKernel - -- (or, delete when not BackupOldOS) -- move /new-os to / -- touch flagfile + + propellorbootstrapped = property "propellor re-debootstrapped in new os" $ + error "TODO" -- 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 + + finalized = property "clean install finalized" $ do + liftIO $ writeFile flagfile "" + return MadeChange + flagfile = "/etc/propellor-cleaninstall" -data Confirmed = Confirmed HostName +data Confirmation = Confirmed HostName -checkConfirmed :: Confirmed -> Propellor () +checkConfirmed :: Confirmation -> Propellor () checkConfirmed (Confirmed c) = do hostname <- asks hostName when (hostname /= c) $ errorMessage "Run with a bad confirmation, not matching hostname." --- | Sometimes you want an almost clean install, but with some tweaks. -data Tweak - = 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 - -- /etc/network/interfaces is configured to bring up all interfaces that -- are currently up, using the same IP addresses. preserveNetworkInterfaces :: Property @@ -103,6 +124,13 @@ preserveRootSshAuthorized = check (doesDirectoryExist oldloc) $ kernelInstalled :: Property kernelInstalled = undefined +-- Copies kernel images, initrds, and modules from /old-os +-- into the new system. +-- +-- TODO: grub config? +oldOSKernelPreserved :: Property +oldOSKernelPreserved = undefined + -- Installs grub onto a device to boot the system. -- -- You may want to install grub to multiple devices; eg for a system @@ -113,7 +141,7 @@ grubBoots = undefined type GrubDev = String -- Removes the old OS's backup from /old-os -oldOSRemoved :: Confirmed -> Property +oldOSRemoved :: Confirmation -> Property oldOSRemoved confirmed = check (doesDirectoryExist oldOsDir) $ property "old OS backup removed" $ do checkConfirmed confirmed diff --git a/src/Propellor/Property/User.hs b/src/Propellor/Property/User.hs index 434a92a..ccb69b2 100644 --- a/src/Propellor/Property/User.hs +++ b/src/Propellor/Property/User.hs @@ -84,3 +84,15 @@ hasGroup user group' = check test $ cmdProperty "adduser" `describe` unwords ["user", user, "in group", group'] where test = not . elem group' . words <$> readProcess "groups" [user] + +-- | Controls whether shadow passwords are enabled or not. +shadowConfig :: Bool -> Property +shadowConfig True = check (not <$> shadowExists) $ + cmdProperty "shadowconfig" ["on"] + `describe` "shadow passwords enabled" +shadowConfig False = check shadowExists $ + cmdProperty "shadowconfig" ["off"] + `describe` "shadow passwords disabled" + +shadowExists :: IO Bool +shadowExists = doesFileExist "/etc/shadow" From 748e6329c770ad8b39b4aaf37e9e7d4d12cd3432 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 16:14:34 -0400 Subject: [PATCH 02/19] propellor spin From ef5ee9416cfde03824d18c0832d311f571614fb8 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 16:16:11 -0400 Subject: [PATCH 03/19] propellor spin From b5af98d744cd2a615eaa47cb8e55c673fa5289d0 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 16:16:50 -0400 Subject: [PATCH 04/19] propellor spin From 0aa635dbd2412b02e38385376f27adfb7962c974 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 16:21:09 -0400 Subject: [PATCH 05/19] propellor spin --- src/Propellor/Property/OS.hs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Propellor/Property/OS.hs b/src/Propellor/Property/OS.hs index ce8f44f..8f852bb 100644 --- a/src/Propellor/Property/OS.hs +++ b/src/Propellor/Property/OS.hs @@ -52,7 +52,7 @@ import qualified Propellor.Property.User as User -- > -- rest of system properties here cleanInstallOnce :: Confirmation -> Property cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ - confirmed + confirmed "clean install confirmed" confirmation `before` osbootstrapped `before` @@ -64,10 +64,6 @@ cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ `before` finalized where - confirmed = property "clean install confirmed" $ do - checkConfirmed confirmation - return NoChange - osbootstrapped = withOS "/new-os bootstrapped" $ \o -> case o of (Just d@(System (Debian _) _)) -> debootstrap d (Just u@(System (Ubuntu _) _)) -> debootstrap u @@ -97,11 +93,14 @@ cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ data Confirmation = Confirmed HostName -checkConfirmed :: Confirmation -> Propellor () -checkConfirmed (Confirmed c) = do +confirmed :: Desc -> Confirmation -> Property +confirmed desc (Confirmed c) = property desc $ do hostname <- asks hostName - when (hostname /= c) $ - errorMessage "Run with a bad confirmation, not matching hostname." + if hostname /= c + then do + warningMessage "Run with a bad confirmation, not matching hostname." + return FailedChange + else return NoChange -- /etc/network/interfaces is configured to bring up all interfaces that -- are currently up, using the same IP addresses. @@ -142,9 +141,10 @@ type GrubDev = String -- Removes the old OS's backup from /old-os oldOSRemoved :: Confirmation -> Property -oldOSRemoved confirmed = check (doesDirectoryExist oldOsDir) $ - property "old OS backup removed" $ do - checkConfirmed confirmed +oldOSRemoved confirmation = check (doesDirectoryExist oldOsDir) $ + go `requires` confirmed "old OS backup removal confirmed" confirmation + where + go = property "old OS backup removed" $ do liftIO $ removeDirectoryRecursive oldOsDir return MadeChange From cf8583aa05a421beb7adbebfc3b1fd1301e23596 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 16:21:15 -0400 Subject: [PATCH 06/19] propellor spin From c99e367c3bb1da193c2d8f756b5fe3ec9c490b53 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 16:22:29 -0400 Subject: [PATCH 07/19] propellor spin --- src/Propellor/Property/OS.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Propellor/Property/OS.hs b/src/Propellor/Property/OS.hs index 8f852bb..0138be9 100644 --- a/src/Propellor/Property/OS.hs +++ b/src/Propellor/Property/OS.hs @@ -52,9 +52,9 @@ import qualified Propellor.Property.User as User -- > -- rest of system properties here cleanInstallOnce :: Confirmation -> Property cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ - confirmed "clean install confirmed" confirmation - `before` osbootstrapped + `requires` + confirmed "clean install confirmed" confirmation `before` transitioned `before` From 1106c305d05f910795b4b549ef0348ce6ba15b85 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 16:23:00 -0400 Subject: [PATCH 08/19] propellor spin --- config-joey.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config-joey.hs b/config-joey.hs index 03f2133..a1ea21d 100644 --- a/config-joey.hs +++ b/config-joey.hs @@ -55,7 +55,7 @@ hosts = -- (o) ` testvm :: Host testvm = host "testvm.kitenet.net" & os (System (Debian Unstable) "amd64") - & OS.cleanInstallOnce (OS.Confirmed "testvm.kitenet.netno") + & OS.cleanInstallOnce (OS.Confirmed "testvm.kitenet.net") `onChange` propertyList "fixing up after clean install" [ OS.preserveRootSshAuthorized ] From 5eb980d04851e26ed5cff47d98374de9688b349d Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 16:24:35 -0400 Subject: [PATCH 09/19] propellor spin --- src/Propellor/Property/OS.hs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/Propellor/Property/OS.hs b/src/Propellor/Property/OS.hs index 0138be9..f06e1b7 100644 --- a/src/Propellor/Property/OS.hs +++ b/src/Propellor/Property/OS.hs @@ -52,18 +52,19 @@ import qualified Propellor.Property.User as User -- > -- rest of system properties here cleanInstallOnce :: Confirmation -> Property cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ - osbootstrapped - `requires` - confirmed "clean install confirmed" confirmation - `before` - transitioned - `before` - User.shadowConfig True - `before` - propellorbootstrapped - `before` - finalized + go `requires` confirmed "clean install confirmed" confirmation where + go = + osbootstrapped + `before` + transitioned + `before` + User.shadowConfig True + `before` + propellorbootstrapped + `before` + finalized + osbootstrapped = withOS "/new-os bootstrapped" $ \o -> case o of (Just d@(System (Debian _) _)) -> debootstrap d (Just u@(System (Ubuntu _) _)) -> debootstrap u From 05ad6ad130139333e6029f4ea7cc05e3c7ed1bf0 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 16:25:12 -0400 Subject: [PATCH 10/19] propellor spin --- src/Propellor/Property/OS.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Propellor/Property/OS.hs b/src/Propellor/Property/OS.hs index f06e1b7..02d5f47 100644 --- a/src/Propellor/Property/OS.hs +++ b/src/Propellor/Property/OS.hs @@ -73,21 +73,21 @@ cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ Debootstrap.built "/new-os" targetos Debootstrap.DefaultConfig transitioned = property "/new-os moved into place" $ - error "TODO" + return NoChange -- unmount all mounts -- move all directories to /old-os, -- move /new-os to / -- touch flagfile propellorbootstrapped = property "propellor re-debootstrapped in new os" $ - error "TODO" + return NoChange -- 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) finalized = property "clean install finalized" $ do - liftIO $ writeFile flagfile "" + --liftIO $ writeFile flagfile "" return MadeChange flagfile = "/etc/propellor-cleaninstall" From 228154cf1f1c9c28f933a7e073f421ba0b876275 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 16:27:54 -0400 Subject: [PATCH 11/19] propellor spin --- src/Propellor/Property/OS.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Propellor/Property/OS.hs b/src/Propellor/Property/OS.hs index 02d5f47..e09b3d8 100644 --- a/src/Propellor/Property/OS.hs +++ b/src/Propellor/Property/OS.hs @@ -73,21 +73,21 @@ cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ Debootstrap.built "/new-os" targetos Debootstrap.DefaultConfig transitioned = property "/new-os moved into place" $ - return NoChange + return FailedChange -- unmount all mounts -- move all directories to /old-os, -- move /new-os to / -- touch flagfile propellorbootstrapped = property "propellor re-debootstrapped in new os" $ - return NoChange + return FailedChange -- 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) finalized = property "clean install finalized" $ do - --liftIO $ writeFile flagfile "" + liftIO $ writeFile flagfile "" return MadeChange flagfile = "/etc/propellor-cleaninstall" From c00219f5934a1aa73e7526a6d073c6c1e7b30a50 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 16:28:06 -0400 Subject: [PATCH 12/19] propellor spin From e47fbd9b39708e3488e047a5c22565ff23e79d46 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 16:29:33 -0400 Subject: [PATCH 13/19] propellor spin --- src/Propellor/Property/OS.hs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Propellor/Property/OS.hs b/src/Propellor/Property/OS.hs index e09b3d8..20e6e47 100644 --- a/src/Propellor/Property/OS.hs +++ b/src/Propellor/Property/OS.hs @@ -55,15 +55,15 @@ cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ go `requires` confirmed "clean install confirmed" confirmation where go = - osbootstrapped - `before` - transitioned - `before` - User.shadowConfig True - `before` - propellorbootstrapped - `before` finalized + `requires` + propellorbootstrapped + `requires` + User.shadowConfig True + `requires` + flipped + `requires` + osbootstrapped osbootstrapped = withOS "/new-os bootstrapped" $ \o -> case o of (Just d@(System (Debian _) _)) -> debootstrap d @@ -72,7 +72,7 @@ cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ debootstrap targetos = ensureProperty $ toProp $ Debootstrap.built "/new-os" targetos Debootstrap.DefaultConfig - transitioned = property "/new-os moved into place" $ + flipped = property "/new-os moved into place" $ return FailedChange -- unmount all mounts -- move all directories to /old-os, From bf4840f341c83f28a53cf80fd7750a661e734d65 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 16:50:00 -0400 Subject: [PATCH 14/19] propellor spin --- propellor.cabal | 1 + src/Propellor/Property/Debootstrap.hs | 8 ++--- src/Propellor/Property/Mount.hs | 12 +++++++ src/Propellor/Property/OS.hs | 46 ++++++++++++++++++--------- 4 files changed, 46 insertions(+), 21 deletions(-) create mode 100644 src/Propellor/Property/Mount.hs diff --git a/propellor.cabal b/propellor.cabal index 617a1fc..91d08bd 100644 --- a/propellor.cabal +++ b/propellor.cabal @@ -85,6 +85,7 @@ Library Propellor.Property.Gpg Propellor.Property.Group Propellor.Property.Grub + Propellor.Property.Mount Propellor.Property.Network Propellor.Property.Nginx Propellor.Property.Obnam diff --git a/src/Propellor/Property/Debootstrap.hs b/src/Propellor/Property/Debootstrap.hs index ab5bddf..35d9e47 100644 --- a/src/Propellor/Property/Debootstrap.hs +++ b/src/Propellor/Property/Debootstrap.hs @@ -9,6 +9,7 @@ module Propellor.Property.Debootstrap ( import Propellor import qualified Propellor.Property.Apt as Apt import Propellor.Property.Chroot.Util +import Propellor.Property.Mount import Utility.Path import Utility.SafeCommand import Utility.FileMode @@ -95,9 +96,7 @@ built target system@(System _ arch) config = submnts <- filter (\p -> simplifyPath p /= simplifyPath target) . filter (dirContains target) <$> mountPoints - forM_ submnts $ \mnt -> - unlessM (boolSystem "umount" [ Param "-l", Param mnt ]) $ do - errorMessage $ "failed unmounting " ++ mnt + forM_ submnts umountLazy removeDirectoryRecursive target -- A failed debootstrap run will leave a debootstrap directory; @@ -109,9 +108,6 @@ built target system@(System _ arch) config = , return False ) -mountPoints :: IO [FilePath] -mountPoints = lines <$> readProcess "findmnt" ["-rn", "--output", "target"] - extractSuite :: System -> Maybe String extractSuite (System (Debian s) _) = Just $ Apt.showSuite s extractSuite (System (Ubuntu r) _) = Just r diff --git a/src/Propellor/Property/Mount.hs b/src/Propellor/Property/Mount.hs new file mode 100644 index 0000000..804407e --- /dev/null +++ b/src/Propellor/Property/Mount.hs @@ -0,0 +1,12 @@ +module Propellor.Property.Mount where + +import Propellor +import Utility.SafeCommand + +mountPoints :: IO [FilePath] +mountPoints = lines <$> readProcess "findmnt" ["-rn", "--output", "target"] + +umountLazy :: FilePath -> IO () +umountLazy mnt = + unlessM (boolSystem "umount" [ Param "-l", Param mnt ]) $ + errorMessage $ "failed unmounting " ++ mnt diff --git a/src/Propellor/Property/OS.hs b/src/Propellor/Property/OS.hs index 20e6e47..aa304f6 100644 --- a/src/Propellor/Property/OS.hs +++ b/src/Propellor/Property/OS.hs @@ -14,6 +14,7 @@ import Propellor import qualified Propellor.Property.Debootstrap as Debootstrap import qualified Propellor.Property.Ssh as Ssh import qualified Propellor.Property.User as User +import Propellor.Property.Mount -- | Replaces whatever OS was installed before with a clean installation -- of the OS that the Host is configured to have. @@ -63,30 +64,42 @@ cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ `requires` flipped `requires` + umountall + `requires` osbootstrapped - osbootstrapped = withOS "/new-os bootstrapped" $ \o -> case o of + osbootstrapped = withOS (newOSDir ++ " bootstrapped") $ \o -> case o of (Just d@(System (Debian _) _)) -> debootstrap d (Just u@(System (Ubuntu _) _)) -> debootstrap u _ -> error "os is not declared to be Debian or Ubuntu" debootstrap targetos = ensureProperty $ toProp $ - Debootstrap.built "/new-os" targetos Debootstrap.DefaultConfig + Debootstrap.built newOSDir targetos Debootstrap.DefaultConfig - flipped = property "/new-os moved into place" $ - return FailedChange - -- unmount all mounts - -- move all directories to /old-os, - -- move /new-os to / - -- touch flagfile + umountall = property "all mount points unmounted" $ liftIO $ do + mnts <- filter (/= "/") <$> mountPoints + forM_ mnts umountLazy + return $ if null mnts then NoChange else MadeChange + + flipped = property (newOSDir ++ " moved into place") $ liftIO $ do + createDirectoryIfMissing True oldOSDir + rootcontents <- dirContents "/" + forM_ rootcontents $ \d -> + when (d /= oldOSDir && d /= newOSDir) $ + renameDirectory d (oldOSDir ++ d) + newrootcontents <- dirContents newOSDir + forM_ newrootcontents $ \d -> + renameDirectory d ("/" ++ takeFileName d) + removeDirectory newOSDir + return MadeChange propellorbootstrapped = property "propellor re-debootstrapped in new os" $ - return FailedChange + return NoChange -- 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) - finalized = property "clean install finalized" $ do + finalized = property "clean OS installed" $ do liftIO $ writeFile flagfile "" return MadeChange @@ -118,7 +131,7 @@ preserveRootSshAuthorized = check (doesDirectoryExist oldloc) $ ensureProperties (map (Ssh.authorizedKey "root") ks) where newloc = "/root/.ssh/authorized_keys" - oldloc = oldOsDir ++ newloc + oldloc = oldOSDir ++ newloc -- Installs an appropriate kernel from the OS distribution. kernelInstalled :: Property @@ -142,12 +155,15 @@ type GrubDev = String -- Removes the old OS's backup from /old-os oldOSRemoved :: Confirmation -> Property -oldOSRemoved confirmation = check (doesDirectoryExist oldOsDir) $ +oldOSRemoved confirmation = check (doesDirectoryExist oldOSDir) $ go `requires` confirmed "old OS backup removal confirmed" confirmation where go = property "old OS backup removed" $ do - liftIO $ removeDirectoryRecursive oldOsDir + liftIO $ removeDirectoryRecursive oldOSDir return MadeChange -oldOsDir :: FilePath -oldOsDir = "/old-os" +oldOSDir :: FilePath +oldOSDir = "/old-os" + +newOSDir :: FilePath +newOSDir = "/new-os" From 31cf8e0c24ff25a14ce750bbb1491436c55f07e0 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 16:54:04 -0400 Subject: [PATCH 15/19] propellor spin --- src/Propellor/Property/OS.hs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Propellor/Property/OS.hs b/src/Propellor/Property/OS.hs index aa304f6..2888800 100644 --- a/src/Propellor/Property/OS.hs +++ b/src/Propellor/Property/OS.hs @@ -75,8 +75,8 @@ cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ debootstrap targetos = ensureProperty $ toProp $ Debootstrap.built newOSDir targetos Debootstrap.DefaultConfig - umountall = property "all mount points unmounted" $ liftIO $ do - mnts <- filter (/= "/") <$> mountPoints + umountall = property "mount points unmounted" $ liftIO $ do + mnts <- filter (`notElem` ["/", "/proc"]) <$> mountPoints forM_ mnts umountLazy return $ if null mnts then NoChange else MadeChange @@ -84,11 +84,13 @@ cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ createDirectoryIfMissing True oldOSDir rootcontents <- dirContents "/" forM_ rootcontents $ \d -> - when (d /= oldOSDir && d /= newOSDir) $ + when (d `notElem` [oldOSDir, newOSDir, "/proc"]) $ renameDirectory d (oldOSDir ++ d) newrootcontents <- dirContents newOSDir - forM_ newrootcontents $ \d -> - renameDirectory d ("/" ++ takeFileName d) + forM_ newrootcontents $ \d -> do + let dest = "/" ++ takeFileName d + whenM (not <$> doesDirectoryExist dest) $ + renameDirectory d dest removeDirectory newOSDir return MadeChange From 61766ff027ffaad3e816c7cda20284f87e16478b Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 16:55:33 -0400 Subject: [PATCH 16/19] propellor spin --- src/Propellor/Property/OS.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Propellor/Property/OS.hs b/src/Propellor/Property/OS.hs index 2888800..8b221b9 100644 --- a/src/Propellor/Property/OS.hs +++ b/src/Propellor/Property/OS.hs @@ -77,7 +77,8 @@ cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ umountall = property "mount points unmounted" $ liftIO $ do mnts <- filter (`notElem` ["/", "/proc"]) <$> mountPoints - forM_ mnts umountLazy + -- reverse so that deeper mount points come first + forM_ (reverse mnts) umountLazy return $ if null mnts then NoChange else MadeChange flipped = property (newOSDir ++ " moved into place") $ liftIO $ do From c57a42388366f4e0bb6195ec4d957f8bc8ebad6e Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 17:01:43 -0400 Subject: [PATCH 17/19] propellor spin --- src/Propellor/Property/OS.hs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Propellor/Property/OS.hs b/src/Propellor/Property/OS.hs index 8b221b9..603e459 100644 --- a/src/Propellor/Property/OS.hs +++ b/src/Propellor/Property/OS.hs @@ -76,7 +76,7 @@ cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ Debootstrap.built newOSDir targetos Debootstrap.DefaultConfig umountall = property "mount points unmounted" $ liftIO $ do - mnts <- filter (`notElem` ["/", "/proc"]) <$> mountPoints + mnts <- filter (`notElem` ("/": trickydirs)) <$> mountPoints -- reverse so that deeper mount points come first forM_ (reverse mnts) umountLazy return $ if null mnts then NoChange else MadeChange @@ -85,7 +85,7 @@ cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ createDirectoryIfMissing True oldOSDir rootcontents <- dirContents "/" forM_ rootcontents $ \d -> - when (d `notElem` [oldOSDir, newOSDir, "/proc"]) $ + when (d `notElem` (oldOSDir:newOSDir:trickydirs)) $ renameDirectory d (oldOSDir ++ d) newrootcontents <- dirContents newOSDir forM_ newrootcontents $ \d -> do @@ -95,6 +95,14 @@ cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ removeDirectory newOSDir return MadeChange + trickydirs = + -- /tmp can contain X's sockets, which prevent moving it + -- so it's left as-is. + [ "/tmp" + -- /proc is left mounted + , "/proc" + ] + propellorbootstrapped = property "propellor re-debootstrapped in new os" $ return NoChange -- re-bootstrap propellor in /usr/local/propellor, From 014af4a5b4a21185e16f7564be00859b3bc4c060 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 17:05:03 -0400 Subject: [PATCH 18/19] propellor spin --- src/Propellor/Property/OS.hs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Propellor/Property/OS.hs b/src/Propellor/Property/OS.hs index 603e459..14e5d85 100644 --- a/src/Propellor/Property/OS.hs +++ b/src/Propellor/Property/OS.hs @@ -16,6 +16,8 @@ import qualified Propellor.Property.Ssh as Ssh import qualified Propellor.Property.User as User import Propellor.Property.Mount +import System.Posix.Files (rename, fileExist) + -- | Replaces whatever OS was installed before with a clean installation -- of the OS that the Host is configured to have. -- @@ -86,12 +88,12 @@ cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ rootcontents <- dirContents "/" forM_ rootcontents $ \d -> when (d `notElem` (oldOSDir:newOSDir:trickydirs)) $ - renameDirectory d (oldOSDir ++ d) + rename d (oldOSDir ++ d) newrootcontents <- dirContents newOSDir forM_ newrootcontents $ \d -> do let dest = "/" ++ takeFileName d - whenM (not <$> doesDirectoryExist dest) $ - renameDirectory d dest + whenM (not <$> fileExist dest) $ + rename d dest removeDirectory newOSDir return MadeChange From cdf763b8b8deeb9c7e572afe268869e441ef30aa Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 4 Dec 2014 17:11:08 -0400 Subject: [PATCH 19/19] propellor spin --- src/Propellor/Property/Chroot/Util.hs | 7 ++++--- src/Propellor/Property/OS.hs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Propellor/Property/Chroot/Util.hs b/src/Propellor/Property/Chroot/Util.hs index feb71d0..382fbab 100644 --- a/src/Propellor/Property/Chroot/Util.hs +++ b/src/Propellor/Property/Chroot/Util.hs @@ -9,7 +9,8 @@ import Control.Applicative standardPathEnv :: IO [(String, String)] standardPathEnv = do path <- getEnvDefault "PATH" "/bin" - addEntry "PATH" (path ++ std) + addEntry "PATH" (path ++ stdPATH) <$> getEnvironment - where - std = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + +stdPATH :: String +stdPATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" diff --git a/src/Propellor/Property/OS.hs b/src/Propellor/Property/OS.hs index 14e5d85..cbdb4d9 100644 --- a/src/Propellor/Property/OS.hs +++ b/src/Propellor/Property/OS.hs @@ -94,7 +94,7 @@ cleanInstallOnce confirmation = check (not <$> doesFileExist flagfile) $ let dest = "/" ++ takeFileName d whenM (not <$> fileExist dest) $ rename d dest - removeDirectory newOSDir + removeDirectoryRecursive newOSDir return MadeChange trickydirs =