Merge branch 'joeyconfig'

This commit is contained in:
Joey Hess 2014-06-05 16:52:45 -04:00
commit f8bad27267
15 changed files with 620 additions and 423 deletions

View File

@ -37,8 +37,9 @@ hosts = -- (o) `
-- My laptop
[ host "darkstar.kitenet.net"
& ipv6 "2001:4830:1600:187::2" -- sixxs tunnel
& Docker.configured
& Apt.buildDep ["git-annex"] `period` Daily
& Docker.configured
& Docker.docked hosts "android-git-annex"
-- Nothing super-important lives here and mostly it's docker containers.
@ -162,6 +163,24 @@ hosts = -- (o) `
& Dns.secondaryFor ["animx"] hosts "animx.eu.org"
-- storage and backup server
, standardSystem "elephant.kitenet.net" Unstable "amd64"
& ipv4 "193.234.225.114"
& Hostname.sane
& Postfix.satellite
& Apt.unattendedUpgrades
& alias "eubackup.kitenet.net"
& Apt.installed ["obnam", "sshfs", "rsync"]
& JoeySites.githubBackup
& alias "podcatcher.kitenet.net"
& Apt.installed ["git-annex"]
& Docker.configured
! Docker.docked hosts "voltagex"
& Docker.garbageCollected `period` (Weekly (Just 1))
--' __|II| ,.
---- __|II|II|__ ( \_,/\
@ -210,6 +229,17 @@ hosts = -- (o) `
, let gitannexdir = GitAnnexBuilder.homedir </> "git-annex"
in GitAnnexBuilder.androidContainer dockerImage "android-git-annex" doNothing gitannexdir
& Docker.volume ("/home/joey/src/git-annex:" ++ gitannexdir)
-- temp for an acquantance
, standardContainer "voltagex" Stable "amd64"
& Docker.publish "22022:22"
& Docker.memory "500m"
& Docker.cpuShares 1
& Apt.serviceInstalledRunning "ssh"
& Ssh.permitRootLogin True
& Ssh.passwordAuthentication True
& User.hasSomePassword "root"
] ++ monsters
-- This is my standard system setup.
@ -218,6 +248,7 @@ standardSystem hn suite arch = host hn
& os (System (Debian suite) arch)
& Apt.stdSourcesList suite
`onChange` Apt.upgrade
& Apt.cacheCleaned
& Apt.installed ["etckeeper"]
& Apt.installed ["ssh"]
& GitHome.installedFor "root"
@ -241,7 +272,9 @@ standardContainer :: Docker.ContainerName -> DebianSuite -> Architecture -> Host
standardContainer name suite arch = Docker.container name (dockerImage system)
& os (System (Debian suite) arch)
& Apt.stdSourcesList suite
& Apt.installed ["systemd"]
& Apt.unattendedUpgrades
& Apt.cacheCleaned
where
system = System (Debian suite) arch

4
debian/changelog vendored
View File

@ -2,10 +2,12 @@ propellor (0.6.0) UNRELEASED; urgency=medium
* Docker containers now propigate DNS attributes out to the host they're
docked in. So if a docker container sets a DNS alias, every container
it's docked in will automatically become part of a round-robin DNS,
it's docked in will automatically be added to a DNS round-robin,
if propellor is used to manage DNS for the domain.
* Propellor's output now includes the hostname being provisioned, or
when provisioning a docker container, the container name.
* Added --dump to dump out a field of a host's privdata. Useful for editing
it.
-- Joey Hess <joeyh@debian.org> Sat, 31 May 2014 16:41:56 -0400

View File

@ -1,366 +1,372 @@
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
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
=RrAw
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
uHj0ZyJrX3IzUToU+/qSYA53iBg6mX7EsHM=
=IsJI
-----END PGP MESSAGE-----

View File

@ -0,0 +1,22 @@
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
hQIMA7ODiaEXBlRZAQ//SW/xJB2ymi3hEqTbJRCtmU2cbMW/mk/Mb/ZW3P0DaARv
beC10xd1fgFUCNt40JrQ5HGeq5ckG/GWEjT2J1IP3oDTPPoK40qqLYZfHYLyAFok
N59z2rh2FDwsnd7ordI6SAfuyd5Z5v+SF800tIjOuy5Byjw8n3QkrpnLdXhBZU7k
8EP94+/z1vWOkumVqiFRarqbgBwoAbVv0dnp5/CHqGPl83P/JSGrjMMxbcaZ/gfA
ACbX/jq7nHwhYRRkDAsHKZ2IqD48r14ddtoLdXhATUDJBFUEEGoAVOvbCigLzjQE
yXeQ7H3kZ7yVy6iWhaRyKtsCy3rfApzbjleYTisT9cLlVUC0z+kitgcIpcWKF286
ezWaM8qcyuXXsDmr0e0QLAN2gbJMNrM2D2mgULMKnYT2h72/raQOiUOxgWJgyo1U
ybzEVRmF9YWQXrzZI66FEK7e94IPK68JMNEFVc3brrhNi6zNfpTck5Ut5R9pa41L
u8oIqOZ11GTFhZ2COhlAV+Ud5ihXoGKa4HtqsJFrOsonNz9i1J2kw+2vhsZ2lG7X
ILVeFmDnWNfOv1ONe/eO4ZfRO7BdA3EovYCr8CF5zN9WI5y09DWnHg+3Qm90rHMo
ytZoevIpNpkHN+g0u+rNs2qIm4F2E2oI9IwjrI2oo/0tZbwfclICu4ed6e5oqu3S
wFcBmuO0P9zst5bmgozQaMUKgTKidKDtg8G33AqICRttwDr++JR0mCTKB8fW7KBu
R07VTpxd5RcXww8OFZYjf7UBNO1z98prBiJC+gUP4jccZD8zeahxqZ908CHMx5sf
Pb2VGT7X/wZExy6Ek9GRSpA0gGGCWDc9ITmRVHvXWvbxP0F/zzuYhggxJFGoSgw/
7fWq05dfI8pKaOeBlzF/XsrtrLJO3yZVEw17eodxa/KEkAbP+Ze3Qfmurg0UMbut
2y0GsYzpSpzWGoBtYigXtVYDveeohzPu8jL01NbfmkNDp6FSjkm31E4sV7ipe5M7
cvzDXh7in4RBO1znFwzGccDeNT2d8t9Pf+up9wxs7+EvsKwA2hRBLfg=
=AdUG
-----END PGP MESSAGE-----

View File

@ -15,12 +15,15 @@ import Control.Applicative
pureAttrProperty :: Desc -> Attr -> Property
pureAttrProperty desc = Property ("has " ++ desc) (return NoChange)
askAttr :: (Attr -> Val a) -> Propellor (Maybe a)
askAttr f = asks (fromVal . f . hostAttr)
os :: System -> Property
os system = pureAttrProperty ("Operating " ++ show system) $
mempty { _os = Just system }
mempty { _os = Val system }
getOS :: Propellor (Maybe System)
getOS = asks (_os . hostAttr)
getOS = askAttr _os
-- | Indidate that a host has an A record in the DNS.
--
@ -34,6 +37,11 @@ ipv6 :: String -> Property
ipv6 = addDNS . Address . IPv6
-- | Indicates another name for the host in the DNS.
--
-- When the host's ipv4/ipv6 addresses are known, the alias is set up
-- to use their address, rather than using a CNAME. This avoids various
-- problems with CNAMEs, and also means that when multiple hosts have the
-- same alias, a DNS round-robin is automatically set up.
alias :: Domain -> Property
alias = addDNS . CNAME . AbsDomain
@ -55,10 +63,10 @@ addDNS r = pureAttrProperty (rdesc r) $
sshPubKey :: String -> Property
sshPubKey k = pureAttrProperty ("ssh pubkey known") $
mempty { _sshPubKey = Just k }
mempty { _sshPubKey = Val k }
getSshPubKey :: Propellor (Maybe String)
getSshPubKey = asks (_sshPubKey . hostAttr)
getSshPubKey = askAttr _sshPubKey
hostMap :: [Host] -> M.Map HostName Host
hostMap l = M.fromList $ zip (map hostName l) l

View File

@ -27,6 +27,7 @@ usage = do
, " propellor hostname"
, " propellor --spin hostname"
, " propellor --set hostname field"
, " propellor --dump hostname field"
, " propellor --add-key keyid"
]
exitFailure
@ -38,9 +39,8 @@ processCmdLine = go =<< getArgs
go ("--spin":h:[]) = return $ Spin h
go ("--boot":h:[]) = return $ Boot h
go ("--add-key":k:[]) = return $ AddKey k
go ("--set":h:f:[]) = case readish f of
Just pf -> return $ Set h pf
Nothing -> errorMessage $ "Unknown privdata field " ++ f
go ("--set":h:f:[]) = withprivfield f (return . Set h)
go ("--dump":h:f:[]) = withprivfield f (return . Dump h)
go ("--continue":s:[]) = case readish s of
Just cmdline -> return $ Continue cmdline
Nothing -> errorMessage "--continue serialization failure"
@ -56,6 +56,10 @@ processCmdLine = go =<< getArgs
else return $ Run s
go _ = usage
withprivfield s f = case readish s of
Just pf -> f pf
Nothing -> errorMessage $ "Unknown privdata field " ++ s
defaultMain :: [Host] -> IO ()
defaultMain hostlist = do
DockerShim.cleanEnv
@ -66,6 +70,7 @@ defaultMain hostlist = do
where
go _ (Continue cmdline) = go False cmdline
go _ (Set hn field) = setPrivData hn field
go _ (Dump hn field) = dumpPrivData hn field
go _ (AddKey keyid) = addKey keyid
go _ (Chain hn) = withhost hn $ \h -> do
r <- runPropellor h $ ensureProperties $ hostProperties h

View File

@ -49,7 +49,7 @@ setPrivData host field = do
value <- chomp <$> hGetContentsStrict stdin
makePrivDataDir
let f = privDataFile host
m <- fromMaybe M.empty . readish <$> gpgDecrypt f
m <- decryptPrivData host
let m' = M.insert field value m
gpgEncrypt f (show m')
putStrLn "Private data set."
@ -59,6 +59,16 @@ setPrivData host field = do
| end s == "\n" = chomp (beginning s)
| otherwise = s
dumpPrivData :: HostName -> PrivDataField -> IO ()
dumpPrivData host field = go . M.lookup field =<< decryptPrivData host
where
go Nothing = error "Requested privdata is not set."
go (Just s) = putStrLn s
decryptPrivData :: HostName -> IO (M.Map PrivDataField String)
decryptPrivData host = fromMaybe M.empty . readish
<$> gpgDecrypt (privDataFile host)
makePrivDataDir :: IO ()
makePrivDataDir = createDirectoryIfMissing False privDataDir

View File

@ -254,3 +254,9 @@ trustsKey k = RevertableProperty trust untrust
hPutStr h (pubkey k)
hClose h
nukeFile $ f ++ "~" -- gpg dropping
-- | Cleans apt's cache of downloaded packages to avoid using up disk
-- space.
cacheCleaned :: Property
cacheCleaned = cmdProperty "apt-get" ["clean"]
`describe` "apt cache cleaned"

View File

@ -339,7 +339,7 @@ genZone hosts zdomain soa =
, map hostrecords inzdomain
, map addcnames (M.elems m)
]
in (Zone zdomain soa (nub zhosts), warnings)
in (Zone zdomain soa (simplify zhosts), warnings)
where
m = hostMap hosts
-- Known hosts with hostname located in the zone's domain.
@ -390,6 +390,17 @@ genZone hosts zdomain soa =
l = zip (repeat $ AbsDomain $ hostName h)
(S.toList $ S.filter (\r -> isNothing (getIPAddr r) && isNothing (getCNAME r)) (_dns attr))
-- Simplifies the list of hosts. Remove duplicate entries.
-- Also, filter out any CHAMES where the same domain has an
-- IP address, since that's not legal.
simplify :: [(BindDomain, Record)] -> [(BindDomain, Record)]
simplify l = nub $ filter (not . dupcname ) l
where
dupcname (d, CNAME _) | any (matchingaddr d) l = True
dupcname _ = False
matchingaddr d (d', (Address _)) | d == d' = True
matchingaddr _ _ = False
inDomain :: Domain -> BindDomain -> Bool
inDomain domain (AbsDomain d) = domain == d || ('.':domain) `isSuffixOf` d
inDomain _ _ = False -- can't tell, so assume not

View File

@ -5,7 +5,33 @@
-- The existance of a docker container is just another Property of a system,
-- which propellor can set up. See config.hs for an example.
module Propellor.Property.Docker where
module Propellor.Property.Docker (
-- * Host properties
installed,
configured,
container,
docked,
memoryLimited,
garbageCollected,
Image,
ContainerName,
-- * Container configuration
dns,
hostname,
name,
publish,
expose,
user,
volume,
volumes_from,
workdir,
memory,
cpuShares,
link,
ContainerAlias,
-- * Internal use
chain,
) where
import Propellor
import Propellor.SimpleSh
@ -16,24 +42,24 @@ import qualified Propellor.Property.Docker.Shim as Shim
import Utility.SafeCommand
import Utility.Path
import Control.Concurrent.Async
import Control.Concurrent.Async hiding (link)
import System.Posix.Directory
import System.Posix.Process
import Data.List
import Data.List.Utils
import qualified Data.Set as S
installed :: Property
installed = Apt.installed ["docker.io"]
-- | Configures docker with an authentication file, so that images can be
-- pushed to index.docker.io.
-- pushed to index.docker.io. Optional.
configured :: Property
configured = property "docker configured" go `requires` installed
where
go = withPrivData DockerAuthentication $ \cfg -> ensureProperty $
"/root/.dockercfg" `File.hasContent` (lines cfg)
installed :: Property
installed = Apt.installed ["docker.io"]
-- | A short descriptive name for a container.
-- Should not contain whitespace or other unusual characters,
-- only [a-zA-Z0-9_-] are allowed
@ -48,15 +74,17 @@ type ContainerName = String
container :: ContainerName -> Image -> Host
container cn image = Host hn [] attr
where
attr = mempty { _dockerImage = Just image }
attr = dockerAttr $ mempty { _dockerImage = Val image }
hn = cn2hn cn
cn2hn :: ContainerName -> HostName
cn2hn cn = cn ++ ".docker"
-- | Ensures that a docker container is set up and running. The container
-- has its own Properties which are handled by running propellor
-- inside the container.
-- | Ensures that a docker container is set up and running, finding
-- its configuration in the passed list of hosts.
--
-- The container has its own Properties which are handled by running
-- propellor inside the container.
--
-- Additionally, the container can have DNS attributes, such as a CNAME.
-- These become attributes of the host(s) it's docked in.
@ -116,10 +144,10 @@ findContainer mhost cid cn mk = case mhost of
mkContainer :: ContainerId -> Host -> Maybe Container
mkContainer cid@(ContainerId hn _cn) h = Container
<$> _dockerImage attr
<$> fromVal (_dockerImage attr)
<*> pure (map (\a -> a hn) (_dockerRunParams attr))
where
attr = hostAttr h'
attr = _dockerattr $ hostAttr h'
h' = h
-- expose propellor directory inside the container
& volume (localdir++":"++localdir)
@ -144,6 +172,20 @@ garbageCollected = propertyList "docker garbage collected"
gcimages = property "docker images garbage collected" $ do
liftIO $ report <$> (mapM removeImage =<< listImages)
-- | Configures the kernel to respect docker memory limits.
--
-- This assumes the system boots using grub 2. And that you don't need any
-- other GRUB_CMDLINE_LINUX_DEFAULT settings.
--
-- Only takes effect after reboot. (Not automated.)
memoryLimited :: Property
memoryLimited = "/etc/default/grub" `File.containsLine` cfg
`describe` "docker memory limited"
`onChange` cmdProperty "update-grub" []
where
cmdline = "cgroup_enable=memory swapaccount=1"
cfg = "GRUB_CMDLINE_LINUX_DEFAULT=\""++cmdline++"\""
data Container = Container Image [RunParam]
-- | Parameters to pass to `docker run` when creating a container.
@ -194,10 +236,20 @@ workdir :: String -> Property
workdir = runProp "workdir"
-- | Memory limit for container.
--Format: <number><optional unit>, where unit = b, k, m or g
-- Format: <number><optional unit>, where unit = b, k, m or g
--
-- Note: Only takes effect when the host has the memoryLimited property
-- enabled.
memory :: String -> Property
memory = runProp "memory"
-- | CPU shares (relative weight).
--
-- By default, all containers run at the same priority, but you can tell
-- the kernel to give more CPU time to a container using this property.
cpuShares :: Int -> Property
cpuShares = runProp "cpu-shares" . show
-- | Link with another container on the same host.
link :: ContainerName -> ContainerAlias -> Property
link linkwith calias = genProp "link" $ \hn ->
@ -218,9 +270,6 @@ data ContainerId = ContainerId HostName ContainerName
data ContainerIdent = ContainerIdent Image HostName ContainerName [RunParam]
deriving (Read, Show, Eq)
ident2id :: ContainerIdent -> ContainerId
ident2id (ContainerIdent _ hn cn _) = ContainerId hn cn
toContainerId :: String -> Maybe ContainerId
toContainerId s
| myContainerSuffix `isSuffixOf` s = case separate (== '.') (desuffix s) of
@ -420,15 +469,18 @@ listImages :: IO [Image]
listImages = lines <$> readProcess dockercmd ["images", "--all", "--quiet"]
runProp :: String -> RunParam -> Property
runProp field val = pureAttrProperty (param) $
runProp field val = pureAttrProperty (param) $ dockerAttr $
mempty { _dockerRunParams = [\_ -> "--"++param] }
where
param = field++"="++val
genProp :: String -> (HostName -> RunParam) -> Property
genProp field mkval = pureAttrProperty field $
genProp field mkval = pureAttrProperty field $ dockerAttr $
mempty { _dockerRunParams = [\hn -> "--"++field++"=" ++ mkval hn] }
dockerAttr :: DockerAttr -> Attr
dockerAttr a = mempty { _dockerattr = a }
-- | The ContainerIdent of a container is written to
-- /.propellor-ident inside it. This can be checked to see if
-- the container has the same ident later.

View File

@ -38,8 +38,12 @@ data NumClients = OnlyClient | MultipleClients
--
-- How awesome is that?
backup :: FilePath -> Cron.CronTimes -> [ObnamParam] -> NumClients -> Property
backup dir crontimes params numclients = cronjob `describe` desc
backup dir crontimes params numclients = backup' dir crontimes params numclients
`requires` restored dir params
-- | Does a backup, but does not automatically restore.
backup' :: FilePath -> Cron.CronTimes -> [ObnamParam] -> NumClients -> Property
backup' dir crontimes params numclients = cronjob `describe` desc
where
desc = dir ++ " backed up by obnam"
cronjob = Cron.niceJob ("obnam_backup" ++ dir) crontimes "root" "/" $

View File

@ -99,7 +99,9 @@ cabalDeps = flagFile go cabalupdated
standardAutoBuilderContainer :: (System -> Docker.Image) -> Architecture -> Int -> TimeOut -> Host
standardAutoBuilderContainer dockerImage arch buildminute timeout = Docker.container (arch ++ "-git-annex-builder")
(dockerImage $ System (Debian Unstable) arch)
& os (System (Debian Unstable) arch)
& Apt.stdSourcesList Unstable
& Apt.installed ["systemd"]
& Apt.unattendedUpgrades
& buildDepsApt
& autobuilder (show buildminute ++ " * * * *") timeout True
@ -115,7 +117,9 @@ androidAutoBuilderContainer dockerImage crontimes timeout =
androidContainer :: (System -> Docker.Image) -> Docker.ContainerName -> Property -> FilePath -> Host
androidContainer dockerImage name setupgitannexdir gitannexdir = Docker.container name
(dockerImage $ System (Debian Stable) "i386")
& os (System (Debian Stable) "i386")
& Apt.stdSourcesList Stable
& Apt.installed ["systemd"]
& User.accountFor builduser
& File.dirExists gitbuilderdir
& File.ownerGroup homedir builduser builduser
@ -140,7 +144,9 @@ androidContainer dockerImage name setupgitannexdir gitannexdir = Docker.containe
armelCompanionContainer :: (System -> Docker.Image) -> Host
armelCompanionContainer dockerImage = Docker.container "armel-git-annex-builder-companion"
(dockerImage $ System (Debian Unstable) "amd64")
& os (System (Debian Unstable) "amd64")
& Apt.stdSourcesList Unstable
& Apt.installed ["systemd"]
& Apt.unattendedUpgrades
-- This volume is shared with the armel builder.
& Docker.volume gitbuilderdir
@ -156,8 +162,10 @@ armelCompanionContainer dockerImage = Docker.container "armel-git-annex-builder-
armelAutoBuilderContainer :: (System -> Docker.Image) -> Cron.CronTimes -> TimeOut -> Host
armelAutoBuilderContainer dockerImage crontimes timeout = Docker.container "armel-git-annex-builder"
(dockerImage $ System (Debian Unstable) "armel")
& os (System (Debian Unstable) "armel")
& Apt.stdSourcesList Unstable
& Apt.unattendedUpgrades
& Apt.installed ["systemd"]
& Apt.installed ["openssh-client"]
& Docker.link "armel-git-annex-builder-companion" "companion"
& Docker.volumes_from "armel-git-annex-builder-companion"

View File

@ -330,3 +330,11 @@ kiteShellBox = propertyList "kitenet.net shellinabox"
`onChange` Service.restarted "shellinabox"
, Service.running "shellinabox"
]
githubBackup :: Property
githubBackup = propertyList "github-backup box"
[ Apt.installed ["github-backup", "moreutils"]
, let f = "/home/joey/.github-keys"
in File.hasPrivContent f
`onChange` File.ownerGroup f "joey" "joey"
]

View File

@ -40,6 +40,7 @@ data Host = Host
, hostProperties :: [Property]
, hostAttr :: Attr
}
deriving (Show)
-- | Propellor's monad provides read-only access to the host it's running
-- on, including its attributes.
@ -64,6 +65,9 @@ data Property = Property
-- ^ a property can set an attribute of the host that has the property.
}
instance Show Property where
show = propertyDesc
-- | A property that can be reverted.
data RevertableProperty = RevertableProperty Property Property
@ -132,6 +136,7 @@ data CmdLine
| Spin HostName
| Boot HostName
| Set HostName PrivDataField
| Dump HostName PrivDataField
| AddKey String
| Continue CmdLine
| Chain HostName

View File

@ -8,42 +8,22 @@ import Data.Monoid
-- | The attributes of a host.
data Attr = Attr
{ _os :: Maybe System
, _sshPubKey :: Maybe String
{ _os :: Val System
, _sshPubKey :: Val String
, _dns :: S.Set Dns.Record
, _namedconf :: Dns.NamedConfMap
, _dockerImage :: Maybe String
, _dockerRunParams :: [HostName -> String]
, _dockerattr :: DockerAttr
}
instance Eq Attr where
x == y = and
[ _os x == _os y
, _dns x == _dns y
, _namedconf x == _namedconf y
, _sshPubKey x == _sshPubKey y
, _dockerImage x == _dockerImage y
, let simpl v = map (\a -> a "") (_dockerRunParams v)
in simpl x == simpl y
]
deriving (Eq)
instance Monoid Attr where
mempty = Attr Nothing Nothing mempty mempty Nothing mempty
mempty = Attr mempty mempty mempty mempty mempty
mappend old new = Attr
{ _os = case _os new of
Just v -> Just v
Nothing -> _os old
, _sshPubKey = case _sshPubKey new of
Just v -> Just v
Nothing -> _sshPubKey old
, _dns = _dns new <> _dns old
, _namedconf = _namedconf new <> _namedconf old
, _dockerImage = case _dockerImage new of
Just v -> Just v
Nothing -> _dockerImage old
, _dockerRunParams = _dockerRunParams old <> _dockerRunParams new
{ _os = _os old <> _os new
, _sshPubKey = _sshPubKey old <> _sshPubKey new
, _dns = _dns old <> _dns new
, _namedconf = _namedconf old <> _namedconf new
, _dockerattr = _dockerattr old <> _dockerattr new
}
instance Show Attr where
@ -52,6 +32,43 @@ instance Show Attr where
, "sshPubKey " ++ show (_sshPubKey a)
, "dns " ++ show (_dns a)
, "namedconf " ++ show (_namedconf a)
, "docker image " ++ show (_dockerImage a)
, show (_dockerattr a)
]
data Val a = Val a | NoVal
deriving (Eq, Show)
instance Monoid (Val a) where
mempty = NoVal
mappend old new = case new of
NoVal -> old
_ -> new
fromVal :: Val a -> Maybe a
fromVal (Val a) = Just a
fromVal NoVal = Nothing
data DockerAttr = DockerAttr
{ _dockerImage :: Val String
, _dockerRunParams :: [HostName -> String]
}
instance Eq DockerAttr where
x == y = and
[ _dockerImage x == _dockerImage y
, let simpl v = map (\a -> a "") (_dockerRunParams v)
in simpl x == simpl y
]
instance Monoid DockerAttr where
mempty = DockerAttr mempty mempty
mappend old new = DockerAttr
{ _dockerImage = _dockerImage old <> _dockerImage new
, _dockerRunParams = _dockerRunParams old <> _dockerRunParams new
}
instance Show DockerAttr where
show a = unlines
[ "docker image " ++ show (_dockerImage a)
, "docker run params " ++ show (map (\mk -> mk "") (_dockerRunParams a))
]