module Propellor.Property.Cron (
Times(..),
job,
niceJob,
jobDropped,
Propellor.Property.Cron.runPropellor
) where
import Propellor.Base
import qualified Propellor.Property.File as File
import qualified Propellor.Property.Apt as Apt
import Propellor.Bootstrap
import Data.Char
data Times
= Times String
| Daily
| Weekly
| Monthly
job :: Desc -> Times -> User -> FilePath -> String -> Property DebianLike
job :: Desc -> Times -> User -> Desc -> Desc -> Property DebianLike
job Desc
desc Times
times (User Desc
u) Desc
cddir Desc
command = Desc -> Props DebianLike -> Property DebianLike
forall k (metatypes :: k).
SingI metatypes =>
Desc
-> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes)
combineProperties (Desc
"cronned " Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc
desc) (Props DebianLike -> Property DebianLike)
-> Props DebianLike -> Property DebianLike
forall a b. (a -> b) -> a -> b
$ Props UnixLike
props
Props UnixLike
-> Property DebianLike
-> Props
(MetaTypes
(Combine
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
forall a p (y :: [a]) (x :: [a]).
(IsProp p, MetaTypes y ~ GetMetaTypes p,
CheckCombinableNote x y (NoteFor ('Text "&"))) =>
Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
& Desc -> Property DebianLike
Apt.serviceInstalledRunning Desc
"cron"
Props DebianLike
-> Property DebianLike
-> Props
(MetaTypes
(Combine
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]))
forall a p (y :: [a]) (x :: [a]).
(IsProp p, MetaTypes y ~ GetMetaTypes p,
CheckCombinableNote x y (NoteFor ('Text "&"))) =>
Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
& [Desc] -> Property DebianLike
Apt.installed [Desc
"util-linux", Desc
"moreutils"]
Props DebianLike
-> Property UnixLike
-> Props
(MetaTypes
(Combine
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
forall a p (y :: [a]) (x :: [a]).
(IsProp p, MetaTypes y ~ GetMetaTypes p,
CheckCombinableNote x y (NoteFor ('Text "&"))) =>
Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
& Desc -> Times -> Desc
cronjobfile Desc
desc Times
times Desc -> [Desc] -> Property UnixLike
`File.hasContent`
[ case Times
times of
Times Desc
_ -> Desc
""
Times
_ -> Desc
"#!/bin/sh\nset -e"
, Desc
"# Generated by propellor"
, Desc
""
, Desc
"SHELL=/bin/sh"
, Desc
"PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"
, Desc
""
, case Times
times of
Times Desc
t -> Desc
t Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc
"\t" Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc
u Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc
"\tchronic "
Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc -> Desc
shellEscape (Desc -> Desc
scriptfile Desc
desc)
Times
_ -> case Desc
u of
Desc
"root" -> Desc
"chronic " Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc -> Desc
shellEscape (Desc -> Desc
scriptfile Desc
desc)
Desc
_ -> Desc
"chronic su " Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc
u Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc
" -c "
Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc -> Desc
shellEscape (Desc -> Desc
scriptfile Desc
desc)
]
Props DebianLike
-> Property UnixLike
-> Props
(MetaTypes
(Combine
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
forall a p (y :: [a]) (x :: [a]).
(IsProp p, MetaTypes y ~ GetMetaTypes p,
CheckCombinableNote x y (NoteFor ('Text "&"))) =>
Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
& case Times
times of
Times Desc
_ -> Property UnixLike
forall k (t :: k). SingI t => Property (MetaTypes t)
doNothing
Times
_ -> (Desc -> Times -> Desc
cronjobfile Desc
desc Times
times)
Desc -> FileMode -> Property UnixLike
`File.mode` [FileMode] -> FileMode
combineModes ([FileMode]
readModes [FileMode] -> [FileMode] -> [FileMode]
forall a. [a] -> [a] -> [a]
++ [FileMode]
executeModes)
Props DebianLike
-> Property UnixLike
-> Props
(MetaTypes
(Combine
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
forall a p (y :: [a]) (x :: [a]).
(IsProp p, MetaTypes y ~ GetMetaTypes p,
CheckCombinableNote x y (NoteFor ('Text "&"))) =>
Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
& Desc -> Desc
scriptfile Desc
desc Desc -> [Desc] -> Property UnixLike
`File.hasContent`
[ Desc
"#!/bin/sh"
, Desc
"# Generated by propellor"
, Desc
"set -e"
, Desc
"flock -n " Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc -> Desc
shellEscape (Desc -> Times -> Desc
cronjobfile Desc
desc Times
times)
Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc
" sh -c " Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc -> Desc
shellEscape Desc
cmdline
]
Props DebianLike
-> Property UnixLike
-> Props
(MetaTypes
(Combine
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
forall a p (y :: [a]) (x :: [a]).
(IsProp p, MetaTypes y ~ GetMetaTypes p,
CheckCombinableNote x y (NoteFor ('Text "&"))) =>
Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
& Desc -> Desc
scriptfile Desc
desc Desc -> FileMode -> Property UnixLike
`File.mode` [FileMode] -> FileMode
combineModes ([FileMode]
readModes [FileMode] -> [FileMode] -> [FileMode]
forall a. [a] -> [a] -> [a]
++ [FileMode]
executeModes)
where
cmdline :: Desc
cmdline = Desc
"cd " Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc
cddir Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc
" && ( " Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc
command Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc
" )"
jobDropped :: Desc -> Times -> Property UnixLike
jobDropped :: Desc -> Times -> Property UnixLike
jobDropped Desc
desc Times
times = Desc -> Props UnixLike -> Property UnixLike
forall k (metatypes :: k).
SingI metatypes =>
Desc
-> Props (MetaTypes metatypes) -> Property (MetaTypes metatypes)
combineProperties (Desc
"uncronned " Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc
desc) (Props UnixLike -> Property UnixLike)
-> Props UnixLike -> Property UnixLike
forall a b. (a -> b) -> a -> b
$ Props UnixLike
props
Props UnixLike
-> Property UnixLike
-> Props
(MetaTypes
(Combine
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
forall a p (y :: [a]) (x :: [a]).
(IsProp p, MetaTypes y ~ GetMetaTypes p,
CheckCombinableNote x y (NoteFor ('Text "&"))) =>
Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
& Desc -> Property UnixLike
File.notPresent (Desc -> Desc
scriptfile Desc
desc)
Props UnixLike
-> Property UnixLike
-> Props
(MetaTypes
(Combine
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish,
'Targeting 'OSArchLinux, 'Targeting 'OSFreeBSD]))
forall a p (y :: [a]) (x :: [a]).
(IsProp p, MetaTypes y ~ GetMetaTypes p,
CheckCombinableNote x y (NoteFor ('Text "&"))) =>
Props (MetaTypes x) -> p -> Props (MetaTypes (Combine x y))
& Desc -> Property UnixLike
File.notPresent (Desc -> Times -> Desc
cronjobfile Desc
desc Times
times)
niceJob :: Desc -> Times -> User -> FilePath -> String -> Property DebianLike
niceJob :: Desc -> Times -> User -> Desc -> Desc -> Property DebianLike
niceJob Desc
desc Times
times User
user Desc
cddir Desc
command = Desc -> Times -> User -> Desc -> Desc -> Property DebianLike
job Desc
desc Times
times User
user Desc
cddir
(Desc
"nice ionice -c 3 sh -c " Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc -> Desc
shellEscape Desc
command)
runPropellor :: Times -> RevertableProperty DebianLike UnixLike
runPropellor :: Times -> RevertableProperty DebianLike UnixLike
runPropellor Times
times = Property DebianLike
cronned Property DebianLike
-> Property UnixLike -> RevertableProperty DebianLike UnixLike
forall setupmetatypes undometatypes.
Property setupmetatypes
-> Property undometatypes
-> RevertableProperty setupmetatypes undometatypes
<!> Property UnixLike
uncronned
where
cronned :: Property DebianLike
cronned = Desc
-> (OuterMetaTypesWitness
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
-> Maybe System -> Propellor Result)
-> Property DebianLike
forall k (metatypes :: k).
SingI metatypes =>
Desc
-> (OuterMetaTypesWitness metatypes
-> Maybe System -> Propellor Result)
-> Property (MetaTypes metatypes)
withOS Desc
"propellor cron job" ((OuterMetaTypesWitness
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
-> Maybe System -> Propellor Result)
-> Property DebianLike)
-> (OuterMetaTypesWitness
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
-> Maybe System -> Propellor Result)
-> Property DebianLike
forall a b. (a -> b) -> a -> b
$ \OuterMetaTypesWitness
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
w Maybe System
o -> do
Bootstrapper
bootstrapper <- Propellor Bootstrapper
getBootstrapper
OuterMetaTypesWitness
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
-> Property DebianLike -> Propellor Result
forall (inner :: [MetaType]) (outer :: [MetaType]).
EnsurePropertyAllowed inner outer =>
OuterMetaTypesWitness outer
-> Property (MetaTypes inner) -> Propellor Result
ensureProperty OuterMetaTypesWitness
'[ 'Targeting 'OSDebian, 'Targeting 'OSBuntish]
w (Property DebianLike -> Propellor Result)
-> Property DebianLike -> Propellor Result
forall a b. (a -> b) -> a -> b
$
Desc -> Times -> User -> Desc -> Desc -> Property DebianLike
niceJob Desc
"propellor" Times
times (Desc -> User
User Desc
"root") Desc
localdir
(Bootstrapper -> Maybe System -> Desc
bootstrapPropellorCommand Bootstrapper
bootstrapper Maybe System
o Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc
"; ./propellor")
uncronned :: Property UnixLike
uncronned = Desc -> Times -> Property UnixLike
jobDropped Desc
"propellor" Times
times
cronjobname :: Desc -> String
cronjobname :: Desc -> Desc
cronjobname Desc
d = (Char -> Char) -> Desc -> Desc
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
sanitize Desc
d
where
sanitize :: Char -> Char
sanitize Char
c
| Char -> Bool
isAlphaNum Char
c = Char
c
| Bool
otherwise = Char
'_'
scriptfile :: Desc -> FilePath
scriptfile :: Desc -> Desc
scriptfile Desc
d = Desc
"/usr/local/bin/" Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ (Desc -> Desc
cronjobname Desc
d) Desc -> Desc -> Desc
forall a. [a] -> [a] -> [a]
++ Desc
"_cronjob"
cronjobfile :: Desc -> Times -> FilePath
cronjobfile :: Desc -> Times -> Desc
cronjobfile Desc
d Times
times = Desc
"/etc" Desc -> Desc -> Desc
</> Desc
cronjobdir Desc -> Desc -> Desc
</> (Desc -> Desc
cronjobname Desc
d)
where
cronjobdir :: Desc
cronjobdir = case Times
times of
Times Desc
_ -> Desc
"cron.d"
Times
Daily -> Desc
"cron.daily"
Times
Weekly -> Desc
"cron.weekly"
Times
Monthly -> Desc
"cron.monthly"