summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoey Hess2017-07-05 17:29:19 -0400
committerJoey Hess2017-07-05 17:29:19 -0400
commit9648e1797f7f08b3465f6c301404ee0555c20881 (patch)
tree9273d7a1b1e6ae2223aac05bbb6f8afc162845ba
parent9d6c50fff28ed5ba7da7fdd2989c7773e357a3c3 (diff)
parent3451ca8beeb58a3bdd864cd1009ba9f0e314b442 (diff)
Merge branch 'joeyconfig'
-rw-r--r--debian/changelog10
-rw-r--r--joeyconfig.hs21
-rw-r--r--propellor.cabal3
-rw-r--r--src/Propellor/Property.hs1
-rw-r--r--src/Propellor/Property/DiskImage.hs6
-rw-r--r--src/Propellor/Property/File.hs50
-rw-r--r--src/Propellor/Property/LightDM.hs3
-rw-r--r--src/Propellor/Property/XFCE.hs41
8 files changed, 114 insertions, 21 deletions
diff --git a/debian/changelog b/debian/changelog
index 34ea28f4..ea9f43bf 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-propellor (4.0.7) UNRELEASED; urgency=medium
+propellor (4.1.0) UNRELEASED; urgency=medium
* User.hasInsecurePassword makes sure shadow passwords are enabled,
so if the insecure password is later changed, the new password won't be
@@ -16,6 +16,14 @@ propellor (4.0.7) UNRELEASED; urgency=medium
chroot.
* When provisioning a container, output was buffered until the whole
process was done; now output will be displayed immediately.
+ * LightDM.autoLogin: Make it require LightDM.installed.
+ (minor API change as the type changed)
+ * Propellor.Property.XFCE added with some useful properties for the
+ desktop environment.
+ * Added File.applyPath property.
+ * Added File.checkOverwrite.
+ * File.isCopyOf: Fix bug that prevented this property from working
+ when the destination file did not yet exist.
-- Joey Hess <id@joeyh.name> Tue, 20 Jun 2017 10:55:37 -0400
diff --git a/joeyconfig.hs b/joeyconfig.hs
index 1befeb1a..1be4ff14 100644
--- a/joeyconfig.hs
+++ b/joeyconfig.hs
@@ -21,6 +21,8 @@ import qualified Propellor.Property.Git as Git
import qualified Propellor.Property.Postfix as Postfix
import qualified Propellor.Property.Apache as Apache
import qualified Propellor.Property.LetsEncrypt as LetsEncrypt
+import qualified Propellor.Property.LightDM as LightDM
+import qualified Propellor.Property.XFCE as XFCE
import qualified Propellor.Property.Grub as Grub
import qualified Propellor.Property.Obnam as Obnam
import qualified Propellor.Property.Gpg as Gpg
@@ -102,18 +104,27 @@ darkstar = host "darkstar.kitenet.net" $ props
`setFlag` BootFlag
, partition EXT4 `mountedAt` "/"
`mountOpt` errorReadonly
+ `addFreeSpace` MegaBytes 256
, swapPartition (MegaBytes 256)
]
+ `before` File.ownerGroup "/srv/propellor-disk.img" (User "joey") (Group "joey")
demo :: Host
-demo = host "demo.kitenet.net" $ props
+demo = host "demo" $ props
& osDebian Unstable X86_64
- & Hostname.setTo "demo"
& Apt.installed ["linux-image-amd64"]
- & User "root" `User.hasInsecurePassword` "root"
& bootstrappedFrom GitRepoOutsideChroot
- & Apt.installedMin ["task-desktop"]
- & Apt.installed ["xfce4", "lightdm", "xfce4-terminal", "firefox"]
+ & User.accountFor user
+ & root `User.hasInsecurePassword` "debian"
+ & user `User.hasInsecurePassword` "debian"
+ & XFCE.installedMin
+ & XFCE.networkManager
+ & XFCE.defaultPanelFor user File.OverwriteExisting
+ & LightDM.autoLogin user
+ & Apt.installed ["firefox"]
+ where
+ user = User "user"
+ root = User "root"
gnu :: Host
gnu = host "gnu.kitenet.net" $ props
diff --git a/propellor.cabal b/propellor.cabal
index 09548f90..76646fb4 100644
--- a/propellor.cabal
+++ b/propellor.cabal
@@ -1,5 +1,5 @@
Name: propellor
-Version: 4.0.6
+Version: 4.1.0
Cabal-Version: >= 1.20
License: BSD2
Maintainer: Joey Hess <id@joeyh.name>
@@ -153,6 +153,7 @@ Library
Propellor.Property.Unbound
Propellor.Property.User
Propellor.Property.Uwsgi
+ Propellor.Property.XFCE
Propellor.Property.ZFS
Propellor.Property.ZFS.Process
Propellor.Property.ZFS.Properties
diff --git a/src/Propellor/Property.hs b/src/Propellor/Property.hs
index 8b2a4e3d..55e688ab 100644
--- a/src/Propellor/Property.hs
+++ b/src/Propellor/Property.hs
@@ -50,6 +50,7 @@ import Data.Monoid
import Control.Monad.IfElse
import "mtl" Control.Monad.RWS.Strict
import System.Posix.Files
+import Data.Maybe
import Data.List
import Data.Hashable
import Control.Applicative
diff --git a/src/Propellor/Property/DiskImage.hs b/src/Propellor/Property/DiskImage.hs
index d5898d7c..89a8d0c6 100644
--- a/src/Propellor/Property/DiskImage.hs
+++ b/src/Propellor/Property/DiskImage.hs
@@ -49,7 +49,11 @@ type DiskImage = FilePath
-- First the specified Chroot is set up, and its properties are satisfied.
--
-- Then, the disk image is set up, and the chroot is copied into the
--- appropriate partition(s) of it.
+-- appropriate partition(s) of it.
+--
+-- The partitions default to being sized just large enough to fit the files
+-- from the chroot. You can use `addFreeSpace` to make them a bit larger
+-- than that, or `setSize` to use a fixed size.
--
-- Note that the disk image file is reused if it already exists,
-- to avoid expensive IO to generate a new one. And, it's updated in-place,
diff --git a/src/Propellor/Property/File.hs b/src/Propellor/Property/File.hs
index 459fe2c7..3293599a 100644
--- a/src/Propellor/Property/File.hs
+++ b/src/Propellor/Property/File.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FlexibleInstances, FlexibleContexts #-}
module Propellor.Property.File where
@@ -105,11 +105,11 @@ hasPrivContent' writemode source f context =
-- | Replaces the content of a file with the transformed content of another file
basedOn :: FilePath -> (FilePath, [Line] -> [Line]) -> Property UnixLike
-f `basedOn` (f', a) = property' desc $ \o -> do
- tmpl <- liftIO $ readFile f'
+f `basedOn` (src, a) = property' desc $ \o -> do
+ tmpl <- liftIO $ readFile src
ensureProperty o $ fileProperty desc (\_ -> a $ lines $ tmpl) f
where
- desc = f ++ " is based on " ++ f'
+ desc = f ++ " is based on " ++ src
-- | Removes a file. Does not remove symlinks or non-plain-files.
notPresent :: FilePath -> Property UnixLike
@@ -150,23 +150,26 @@ link `isSymlinkedTo` (LinkTarget target) = property desc $
-- | Ensures that a file is a copy of another (regular) file.
isCopyOf :: FilePath -> FilePath -> Property UnixLike
-f `isCopyOf` f' = property desc $ go =<< (liftIO $ tryIO $ getFileStatus f')
+f `isCopyOf` src = property desc $ go =<< (liftIO $ tryIO $ getFileStatus src)
where
- desc = f ++ " is copy of " ++ f'
+ desc = f ++ " is copy of " ++ src
go (Right stat) = if isRegularFile stat
- then gocmp =<< (liftIO $ cmp)
- else warningMessage (f' ++ " is not a regular file") >>
+ then ifM (liftIO $ doesFileExist f)
+ ( gocmp =<< (liftIO $ cmp)
+ , doit
+ )
+ else warningMessage (src ++ " is not a regular file") >>
return FailedChange
go (Left e) = warningMessage (show e) >> return FailedChange
- cmp = safeSystem "cmp" [Param "-s", Param "--", File f, File f']
+ cmp = safeSystem "cmp" [Param "-s", Param "--", File f, File src]
gocmp ExitSuccess = noChange
gocmp (ExitFailure 1) = doit
gocmp _ = warningMessage "cmp failed" >> return FailedChange
- doit = makeChange $ copy f' `viaStableTmp` f
- copy src dest = unlessM (runcp src dest) $ errorMessage "cp failed"
- runcp src dest = boolSystem "cp"
+ doit = makeChange $ copy `viaStableTmp` f
+ copy dest = unlessM (runcp dest) $ errorMessage "cp failed"
+ runcp dest = boolSystem "cp"
[Param "--preserve=all", Param "--", File src, File dest]
-- | Ensures that a file/dir has the specified owner and group.
@@ -177,6 +180,20 @@ ownerGroup f (User owner) (Group group) = p `describe` (f ++ " owner " ++ og)
`changesFile` f
og = owner ++ ":" ++ group
+-- | Given a base directory, and a relative path under that
+-- directory, applies a property to each component of the path in turn,
+-- starting with the base directory.
+--
+-- For example, to make a file owned by a user, making sure their home
+-- directory and the subdirectories to it are also owned by them:
+--
+-- > "/home/user/program/file" `hasContent` ["foo"]
+-- > `before` applyPath "/home/user" ".config/program/file"
+-- > (\f -> ownerGroup f (User "user") (Group "user"))
+applyPath :: Monoid (Property metatypes) => FilePath -> FilePath -> (FilePath -> Property metatypes) -> Property metatypes
+applyPath basedir relpath mkp = mconcat $
+ map mkp (scanl (</>) basedir (splitPath relpath))
+
-- | Ensures that a file/dir has the specfied mode.
mode :: FilePath -> FileMode -> Property UnixLike
mode f v = p `changesFile` f
@@ -290,3 +307,12 @@ readConfigFileName = readish . unescape
Nothing -> '_' : ns ++ unescape cs'
Just n -> chr n : unescape cs'
unescape (c:cs) = c : unescape cs
+
+data Overwrite = OverwriteExisting | PreserveExisting
+
+-- | When passed PreserveExisting, only ensures the property when the file
+-- does not exist.
+checkOverwrite :: Overwrite -> FilePath -> (FilePath -> Property i) -> Property i
+checkOverwrite OverwriteExisting f mkp = mkp f
+checkOverwrite PreserveExisting f mkp =
+ check (not <$> doesFileExist f) (mkp f)
diff --git a/src/Propellor/Property/LightDM.hs b/src/Propellor/Property/LightDM.hs
index 339fa9a3..69538d89 100644
--- a/src/Propellor/Property/LightDM.hs
+++ b/src/Propellor/Property/LightDM.hs
@@ -10,7 +10,8 @@ installed :: Property DebianLike
installed = Apt.installed ["lightdm"]
-- | Configures LightDM to skip the login screen and autologin as a user.
-autoLogin :: User -> Property UnixLike
+autoLogin :: User -> Property DebianLike
autoLogin (User u) = "/etc/lightdm/lightdm.conf" `ConfFile.containsIniSetting`
("SeatDefaults", "autologin-user", u)
`describe` "lightdm autologin"
+ `requires` installed
diff --git a/src/Propellor/Property/XFCE.hs b/src/Propellor/Property/XFCE.hs
new file mode 100644
index 00000000..dc57660f
--- /dev/null
+++ b/src/Propellor/Property/XFCE.hs
@@ -0,0 +1,41 @@
+module Propellor.Property.XFCE where
+
+import Propellor.Base
+import qualified Propellor.Property.Apt as Apt
+import qualified Propellor.Property.File as File
+import qualified Propellor.Property.User as User
+
+installed :: Property DebianLike
+installed = Apt.installed ["task-xfce-desktop"]
+ `describe` "XFCE desktop installed"
+
+-- | Minimal install of XFCE, with a terminal emulator and panel,
+-- and X and network-manager, but not any of the extra apps.
+installedMin :: Property DebianLike
+installedMin = Apt.installedMin ["xfce4", "xfce4-terminal", "task-desktop"]
+ `describe` "minimal XFCE desktop installed"
+
+-- | Installs network-manager-gnome, which is the way to get
+-- network-manager to manage networking in XFCE too.
+networkManager :: Property DebianLike
+networkManager = Apt.installedMin ["network-manager-gnome"]
+
+-- | Normally at first login, XFCE asks what kind of panel the user wants.
+-- This enables the default configuration noninteractively.
+defaultPanelFor :: User -> File.Overwrite -> Property DebianLike
+defaultPanelFor u@(User username) overwrite = property' desc $ \w -> do
+ home <- liftIO $ User.homedir u
+ ensureProperty w (go home)
+ where
+ desc = "default XFCE panel for " ++ username
+ basecf = ".config" </> "xfce4" </> "xfconf"
+ </> "xfce-perchannel-xml" </> "xfce4-panel.xml"
+ -- This location is probably Debian-specific.
+ defcf = "/etc/xdg/xfce4/panel/default.xml"
+ go :: FilePath -> Property DebianLike
+ go home = tightenTargets $
+ File.checkOverwrite overwrite (home </> basecf) $ \cf ->
+ cf `File.isCopyOf` defcf
+ `before` File.applyPath home basecf
+ (\f -> File.ownerGroup f u (userGroup u))
+ `requires` Apt.installed ["xfce4-panel"]