1{-# LANGUAGE RecordWildCards #-}
2{-# LANGUAGE ScopedTypeVariables #-}
4module Docker.Client.Types (
16 , ContainerDetails(..)
17 , DockerClientOpts(..)
22 , ContainerPortInfo(..)
41 , VolumePermission(..)
48 , LogDriverOptions(..)
52 , NetworkInterface(..)
67 , ContainerResources(..)
68 , defaultContainerResources
74 , defaultContainerConfig
78import Data.Aeson (FromJSON, ToJSON, genericParseJSON,
79 genericToJSON, object, parseJSON, toJSON,
80 (.!=), (.:), (.:?), (.=))
81import qualified Data.Aeson as JSON
82import Data.Aeson.Types (defaultOptions, fieldLabelModifier)
83import Data.Char (isAlphaNum, toUpper)
84import qualified Data.HashMap.Strict as HM
85import qualified Data.Map as M
86import Data.Monoid ((<>))
87import Data.Text (Text)
88import qualified Data.Text as T
89import Data.Time.Clock (UTCTime)
90import GHC.Generics (Generic)
91import Prelude hiding (all, tail)
92import Text.Read (readMaybe)
96 | ListContainersEndpoint ListOpts
97 | ListImagesEndpoint ListOpts
98 | CreateContainerEndpoint CreateOpts
99 | StartContainerEndpoint StartOpts ContainerID
100 | StopContainerEndpoint Timeout ContainerID
101 | KillContainerEndpoint Signal ContainerID
102 | RestartContainerEndpoint Timeout ContainerID
103 | PauseContainerEndpoint ContainerID
104 | UnpauseContainerEndpoint ContainerID
105 | ContainerLogsEndpoint LogOpts Bool ContainerID -- Second argument (Bool) is whether to follow.
106 | DeleteContainerEndpoint DeleteOpts ContainerID
107 | InspectContainerEndpoint ContainerID
111type ApiVersion = Text
112newtype ContainerID = ContainerID Text
115fromContainerID :: ContainerID -> Text
116fromContainerID (ContainerID t) = t
118toContainerID :: Text -> Maybe ContainerID
120 if T.all (\c -> isAlphaNum c || c == ':') t then -- Note: Can we improve this whitelist?
125newtype ImageID = ImageID Text
128fromImageID :: ImageID -> Text
129fromImageID (ImageID t) = t
131toImageID :: Text -> Maybe ImageID
133 if T.all (\c -> isAlphaNum c || c == ':') t then -- Note: Can we improve this whitelist?
138data Timeout = Timeout Integer | DefaultTimeout deriving (Eq, Show)
140-- TODO: Add more Signals or use an existing lib
148 | SIGKILL deriving (Eq, Show)
150instance FromJSON Signal where
151 parseJSON (JSON.String "SIGTERM") = return SIGTERM
152 parseJSON (JSON.String "SIGHUP") = return SIGHUP -- Note: Guessing on the string values for these.
153 parseJSON (JSON.String "SIGINT") = return SIGINT
154 parseJSON (JSON.String "SIGQUIT") = return SIGQUIT
155 parseJSON (JSON.String "SIGSTOP") = return SIGSTOP
156 parseJSON (JSON.String "SIGUSR1") = return SIGUSR1
157 parseJSON _ = fail "Unknown Signal"
159instance ToJSON Signal where
160 toJSON SIGHUP = "SIGHUP"
161 toJSON SIGINT = "SIGINT"
162 toJSON SIGQUIT = "SIGQUIT"
163 toJSON SIGSTOP = "SIGSTOP"
164 toJSON SIGTERM = "SIGTERM"
165 toJSON SIGUSR1 = "SIGUSR1"
166 toJSON (SIG i) = toJSON i
167 toJSON SIGKILL = "SIGKILL"
169data ContainerDetails = ContainerDetails {
170 appArmorProfile :: Text
172 , containerDetailsConfig :: ContainerConfig
175 -- , execIDs -- Not sure what this is in 1.24 spec.
176 , containerDetailsHostConfig :: HostConfig
177 , hostnamePath :: FilePath
178 , hostsPath :: FilePath
179 , logPath :: FilePath
180 , containerDetailsId :: ContainerID
181 , containerDetailsImage :: ImageID
184 , networkSettings :: NetworkSettings
186 , processLabel :: Text
187 , resolveConfPath :: FilePath
188 , restartCount :: Int
189 , state :: ContainerState
192 deriving (Eq, Show, Generic)
196 , mountSource :: FilePath
197 , mountDestination :: FilePath
198 , mountDriver :: Text
199 , mountMode :: Text -- Note: Improve this?
201 , mountPropogation :: Text
203 deriving (Eq, Show, Generic)
205instance FromJSON Mount where
206 parseJSON (JSON.Object o) = do
209 dest <- o .: "Destination"
210 driver <- o .: "Driver"
213 prop <- o .: "Propagation"
214 return $ Mount name src dest driver mode rw prop
215 parseJSON _ = fail "Mount is not an object"
217data ContainerState = ContainerState {
218 containerError :: Text
220 , finishedAt :: Maybe UTCTime -- Note: Is this a maybe?
227 , startedAt :: UTCTime
230 deriving (Eq, Show, Generic)
232instance FromJSON ContainerState where
233 parseJSON (JSON.Object o) = do
235 exit <- o .: "ExitCode"
236 finished <- o .:? "FinishedAt"
237 oomKilled <- o .: "OOMKilled"
239 paused <- o .: "Paused"
241 restarting <- o .: "Restarting"
242 running <- o .: "Running"
243 started <- o .: "StartedAt"
245 return $ ContainerState err exit finished oomKilled dead paused pid restarting running started st
246 parseJSON _ = fail "ContainerState is not an object"
248data DockerClientOpts = DockerClientOpts {
254defaultClientOpts :: DockerClientOpts
255defaultClientOpts = DockerClientOpts {
257 , baseUrl = "http://127.0.0.1:2375"
260data ListOpts = ListOpts { all :: Bool } deriving (Eq, Show)
262defaultListOpts :: ListOpts
263defaultListOpts = ListOpts { all=False }
265data DockerVersion = DockerVersion {
267 , apiVersion :: ApiVersion
272 , kernelVersion :: Text
274 } deriving (Show, Eq, Generic)
277instance ToJSON DockerVersion where
278 toJSON = genericToJSON defaultOptions {
279 fieldLabelModifier = (\(x:xs) -> toUpper x : xs)}
281instance FromJSON DockerVersion where
282 parseJSON = genericParseJSON defaultOptions {
283 fieldLabelModifier = (\(x:xs) -> toUpper x : xs)}
285-- instance ToJSON ContainerDetails where
286-- toJSON = error "TODO"
288instance FromJSON ContainerDetails where
289 parseJSON (JSON.Object o) = do
290 appArmor <- o .: "AppArmorProfile"
292 config <- o .: "Config"
293 created <- o .: "Created"
294 driver <- o .: "Driver"
295 hostConfig <- o .: "HostConfig"
296 hostnamePath <- o .: "HostnamePath"
297 hostsPath <- o .: "HostsPath"
298 logPath <- o .: "LogPath"
300 image <- o .: "Image"
301 mountLabel <- o .: "MountLabel"
303 networkSettings <- o .: "NetworkSettings"
305 processLabel <- o .: "ProcessLabel"
306 resolveConfPath <- o .: "ResolvConfPath"
307 restartCount <- o .: "RestartCount"
308 state <- o .: "State"
309 mounts <- o .: "Mounts"
310 return $ ContainerDetails appArmor args config created driver hostConfig hostnamePath hostsPath logPath id image mountLabel name networkSettings path processLabel resolveConfPath restartCount state mounts
311 parseJSON _ = fail "ContainerDetails is not an object"
313instance ToJSON ContainerID where
314 toJSON (ContainerID cid) = object ["Id" .= cid]
316instance FromJSON ContainerID where
317 parseJSON (JSON.Object o) = do
319 case toContainerID cid of
321 fail "Invalid ContainerID"
324 parseJSON _ = fail "ContainerID is not an object."
326instance ToJSON ImageID where
327 toJSON (ImageID iid) = JSON.String iid
329instance FromJSON ImageID where
330 parseJSON (JSON.String t) = case toImageID t of
332 fail "Invalid ImageID"
335 parseJSON _ = fail "ImageID is not an object."
337data ContainerPortInfo = ContainerPortInfo {
338 ipAddressInfo :: Maybe Text
339 , privatePortInfo :: Port
340 , publicPortInfo :: Maybe Port
341 , portTypeInfo :: Maybe PortType
342 } deriving (Eq, Show)
344instance FromJSON ContainerPortInfo where
345 parseJSON (JSON.Object v) =
346 ContainerPortInfo <$> (v .:? "IP")
347 <*> (v .: "PrivatePort")
348 <*> (v .:? "PublicPort")
350 parseJSON _ = fail "ContainerPortInfo: Not a JSON object."
352-- For inspecting container details.
353data NetworkOptions = NetworkOptions {
354-- ipamConfig :: Maybe Text -- Don't see in 1.24
355-- , links :: Maybe Text -- Don't see in 1.24
356-- , aliases :: Maybe Text -- Don't see in 1.24
357 networkOptionsId :: Text
358 , networkOptionsEndpointId :: Text
359 , networkOptionsGateway :: Text
360 , networkOptionsIpAddress :: Text -- Note: Parse this?
361 , networkOptionsIpPrefixLen :: Int
362 , networkOptionsIpV6Gateway :: Maybe Text
363 , networkOptionsGlobalIPv6Address :: Maybe Text
364 , networkOptionsGlobalIPv6PrefixLen :: Maybe Int
365 , networkOptionsMacAddress :: Text
366 } deriving (Eq, Show)
368instance FromJSON NetworkOptions where
369 parseJSON (JSON.Object o) = do
370 networkId <- o .: "NetworkID"
371 endpointId <- o .: "EndpointID"
372 gateway <- o .: "Gateway"
373 ip <- o .: "IPAddress"
374 ipLen <- o .: "IPPrefixLen"
375 ip6Gateway <- o .:? "IPv6Gateway"
376 globalIP6 <- o .:? "GlobalIPv6Address"
377 globalIP6Len <- o .:? "GlobalIPv6PrefixLen"
378 mac <- o .: "MacAddress"
379 return $ NetworkOptions networkId endpointId gateway ip ipLen ip6Gateway globalIP6 globalIP6Len mac
380 parseJSON _ = fail "NetworkOptions is not an object"
382newtype Networks = Networks (M.Map NetworkMode NetworkOptions) -- Note: Is it ever possible that there will be duplicates of network modes?
385instance FromJSON Networks where
386 parseJSON (JSON.Object o) = do
387 Networks <$> HM.foldlWithKey' f (return M.empty) o
392 k <- parseJSON $ JSON.String k'
394 return $ M.insert k v acc
396 parseJSON _ = fail "Networks is not an object"
398data NetworkSettings = NetworkSettings {
399 networkSettingsBridge :: Text
400 , networkSettingsSandboxId :: Text
401 , networkSettingsHairpinMode :: Bool
402 , networkSettingsLinkLocalIPv6Address :: Text
403 , networkSettingsLinkLocalIPv6PrefixLen :: Int
404 , networkSettingsPorts :: [Port] -- TODO: 1.24 spec is unclear
405 , networkSettingsSandboxKey :: Text
406 , networkSettingsSecondaryIPAddresses :: Maybe [Text] -- TODO: 1.24 spec is unclear
407 , networkSettingsSecondaryIPv6Addresses :: Maybe [Text] -- TODO: 1.24 spec is unclear
408 , networkSettingsEndpointID :: Text
409 , networkSettingsGateway :: Text
410 , networkSettingsGlobalIPv6Address :: Text
411 , networkSettingsGlobalIPv6PrefixLen :: Int
412 , networkSettingsIpAddress :: Text
413 , networkSettingsIpPrefixLen :: Int
414 , networkSettingsIpv6Gateway
415 , networkSettingsMacAddress
416 , networkSettingsNetworks :: Networks
420instance FromJSON NetworkSettings where
421 parseJSON (JSON.Object o) = do
422 bridge <- o .: "Bridge"
423 sandbox <- o .: "SandboxID"
424 hairpin <- o .: "HairpinMode"
425 localIP6 <- o .: "LinkLocalIPv6Address"
426 localIP6Len <- o .: "LinkLocalIPv6PrefixLen"
427 ports <- o .:? "Ports" .!= []
428 sandboxKey <- o .: "SandboxKey"
429 secondaryIP <- o .: "SecondaryIPAddresses"
430 secondayIP6 <- o .: "SecondaryIPv6Addresses"
431 endpointID <- o .: "EndpointID"
432 gateway <- o .: "Gateway"
433 globalIP6 <- o .: "GlobalIPv6Address"
434 globalIP6Len <- o .: "GlobalIPv6PrefixLen"
435 ip <- o .: "IPAddress"
436 ipLen <- o .: "IPPrefixLen"
437 ip6Gateway <- o .: "IPv6Gateway"
438 mac <- o .: "MacAddress"
439 networks <- o .: "Networks"
440 return $ NetworkSettings bridge sandbox hairpin localIP6 localIP6Len ports sandboxKey secondaryIP secondayIP6 endpointID gateway globalIP6 globalIP6Len ip ipLen ip6Gateway mac networks
441 parseJSON _ = fail "NetworkSettings is not an Object"
443data Container = Container
444 { containerId :: ContainerID
445 , containerNames :: [Text]
446 , containerImageName :: Text
447 , containerImageId :: ImageID
448 , containerCommand :: Text
449 , containerCreatedAt :: Int
450 , containerStatus :: Status
451 , containerPorts :: [ContainerPortInfo]
452 , containerLabels :: Labels
453 , containerNetworks :: Networks
454 , containerMounts :: [Mount]
455 } deriving (Show, Eq)
457instance FromJSON Container where
458 parseJSON (JSON.Object v) =
459 Container <$> (v .: "Id")
468 <*> (v .: "NetworkSettings" >>= parseNetworks)
471 parseNetworks (JSON.Object v) =
472 (v .: "Networks") >>= parseJSON
473 parseNetworks _ = fail "Container NetworkSettings: Not a JSON object."
475 parseJSON _ = fail "Container: Not a JSON object."
477data Status = Created | Restarting | Running | Paused | Exited | Dead
478 deriving (Eq, Show, Generic)
480instance FromJSON Status where
481 parseJSON (JSON.String "running") = return Running
482 parseJSON (JSON.String "created") = return Created -- Note: Guessing on the string values of these.
483 parseJSON (JSON.String "restarting") = return Restarting
484 parseJSON (JSON.String "paused") = return Paused
485 parseJSON (JSON.String "exited") = return Exited
486 parseJSON (JSON.String "dead") = return Dead
487 parseJSON _ = fail "Unknown Status"
491newtype Labels = Labels (M.Map Name Value) deriving (Eq, Show)
493instance FromJSON Labels where
494 parseJSON val = Labels <$> parseJSON val
496instance ToJSON Labels where
497 toJSON (Labels kvs) = object [k .= v | (k,v) <- (M.toList kvs)]
501data Image = DockerImage {
503 , imageCreated :: Integer
504 , imageParentId :: Maybe ImageID
505 , imageRepoTags :: [Tag]
506 , imageRepoDigests :: Maybe [Digest]
507 , imageSize :: Integer
508 , imageVirtualSize :: Integer
509 , imageLabels :: Maybe Labels
510 } deriving (Show, Eq, Generic)
512dropImagePrefix :: [a] -> [a]
513dropImagePrefix = drop 5
515instance FromJSON Image where
516 parseJSON = genericParseJSON defaultOptions {
517 fieldLabelModifier = dropImagePrefix}
519data CreateOpts = CreateOpts {
520 containerConfig :: ContainerConfig
521 , hostConfig :: HostConfig
522 } deriving (Eq, Show)
524instance ToJSON CreateOpts where
525 toJSON (CreateOpts cc hc) = do
526 let ccJSON = toJSON cc
527 let hcJSON = toJSON hc
529 JSON.Object (o :: HM.HashMap T.Text JSON.Value) -> do
530 JSON.Object $ HM.insert "HostConfig" hcJSON o
531 _ -> error "ContainerConfig is not an object." -- This should never happen.
533defaultContainerConfig :: Text -> ContainerConfig
534defaultContainerConfig imageName = ContainerConfig {
542 , exposedPorts=ExposedPorts M.empty
551 , networkDisabled=False
557defaultHostConfig :: HostConfig
558defaultHostConfig = HostConfig {
560 , containerIDFile=Nothing
561 , logConfig=LogDriverConfig JsonFile Nothing
563 , portBindings=PortBindings []
564 , restartPolicy=RestartOff
565 , volumeDriver=Nothing
575 , oomScoreAdj=Nothing
577 , publishAllPorts=False
578 , readOnlyRootfs=False
581 , resources=defaultContainerResources
584defaultContainerResources :: ContainerResources
585defaultContainerResources = ContainerResources {
587 , blkioWeight=Nothing
588 , blkioWeightDevice=Nothing
589 , blkioDeviceReadBps=Nothing
590 , blkioDeviceWriteBps=Nothing
591 , blkioDeviceReadIOps=Nothing
592 , blkioDeviceWriteIOps=Nothing
597 , kernelMemory=Nothing
599 , memoryReservation=Nothing
601 , oomKillDisable=False
606defaultCreateOpts :: T.Text -> CreateOpts
607defaultCreateOpts imageName = CreateOpts { containerConfig = defaultContainerConfig imageName, hostConfig = defaultHostConfig }
609-- detachKeys – Override the key sequence for detaching a container.
610-- Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _.
611data DetachKeys = WithCtrl Char | WithoutCtrl Char | DefaultDetachKey deriving (Eq, Show)
613data StartOpts = StartOpts { detachKeys :: DetachKeys } deriving (Eq, Show)
615defaultStartOpts :: StartOpts
616defaultStartOpts = StartOpts { detachKeys = DefaultDetachKey }
618data DeleteOpts = DeleteOpts {
619 deleteVolumes :: Bool
621 } deriving (Eq, Show)
623type Timestamp = Integer
624data TailLogOpt = Tail Integer | All deriving (Eq, Show)
626data LogOpts = LogOpts {
629 , since :: Maybe Timestamp
632 } deriving (Eq, Show)
634defaultLogOpts :: LogOpts
635defaultLogOpts = LogOpts { stdout = True
642data VolumePermission = Rw | Ro deriving (Eq, Show, Generic)
644-- instance ToJSON VolumePermission where
645-- toJSON = error "TODO"
646-- instance FromJSON VolumePermission where
647-- parseJSON = error "TODO"
649-- Note: Note really sure what this should be (1.24).
650-- This is not the same as [Volume] in HostConfig.
651newtype Volumes = Volumes [Text] -- [Volume]
654instance FromJSON Volumes where
655 parseJSON (JSON.Object o) = return $ Volumes $ HM.keys o
656 parseJSON _ = fail "Volumes is not an object"
658instance ToJSON Volumes where
659 toJSON (Volumes vs) = toJSON vs
661data Volume = Volume { hostSrc :: Text
662 , containerDest :: Text
663 , volumePermission :: Maybe VolumePermission
664 } deriving (Eq, Show)
666instance FromJSON Volume where
667 parseJSON (JSON.String t) = case T.split (== ':') t of
668 [src, dest] -> return $ Volume src dest Nothing
669 [src, dest, "rw"] -> return $ Volume src dest $ Just Rw
670 [src, dest, "ro"] -> return $ Volume src dest $ Just Ro
671 _ -> fail "Could not parse Volume"
672 parseJSON _ = fail "Volume is not a string"
674data Device = Device {
675 pathOnHost :: FilePath
676 , pathInContainer :: FilePath
677 , cgroupPermissions :: Text
678 } deriving (Eq, Show, Generic)
680instance ToJSON Device where
681 toJSON = genericToJSON defaultOptions {
682 fieldLabelModifier = (\(x:xs) -> toUpper x : xs)}
684instance FromJSON Device where
685 parseJSON = genericParseJSON defaultOptions {
686 fieldLabelModifier = (\(x:xs) -> toUpper x : xs)}
688type ContainerName = Text
690data VolumeFrom = VolumeFrom ContainerName (Maybe VolumePermission) deriving (Eq, Show)
692instance FromJSON VolumeFrom where
693 parseJSON (JSON.String t) = case T.split (== ':') t of
694 [vol] -> return $ VolumeFrom vol Nothing
695 [vol, "rw"] -> return $ VolumeFrom vol $ Just Rw
696 [vol, "ro"] -> return $ VolumeFrom vol $ Just Ro
697 _ -> fail "Could not parse VolumeFrom"
698 parseJSON _ = fail "VolumeFrom is not a string"
700instance ToJSON VolumeFrom where
701 toJSON (VolumeFrom n p) = case p of
702 Nothing -> toJSON $ n <> ":" <> "rw"
703 Just per -> toJSON $ n <> ":" <> (T.pack $ show per)
705instance ToJSON Volume where
706 toJSON (Volume src dest mode) = toJSON $ case mode of
707 Nothing -> T.concat[src, ":", dest]
708 Just m -> T.concat[src, ":", dest, ":", (T.pack $ show m)]
710data Link = Link Text (Maybe Text) deriving (Eq, Show)
712instance FromJSON Link where
713 parseJSON (JSON.String t) = case T.split (== ':') t of
714 [f] -> return $ Link f Nothing
715 [f,s] -> return $ Link f $ Just s
716 _ -> fail "Could not parse Link"
717 parseJSON _ = fail "Link is not a string"
719instance ToJSON Link where
720 toJSON (Link n1 n2) = toJSON $ case n2 of
721 Nothing -> T.concat[n1, ":", n1] -- use same name in container
722 Just n -> T.concat[n1, ":", n] -- used specified name in container
724-- { "Type": "<driver_name>", "Config": {"key1": "val1"} }
725data LogDriverType = JsonFile | Syslog | Journald | Gelf | Fluentd | AwsLogs | Splunk | Etwlogs | LoggingDisabled deriving (Eq, Show)
727instance FromJSON LogDriverType where
728 parseJSON (JSON.String "json-file") = return JsonFile
729 parseJSON (JSON.String "syslog") = return Syslog
730 parseJSON (JSON.String "journald") = return Journald
731 parseJSON (JSON.String "gelf") = return Gelf
732 parseJSON (JSON.String "fluentd") = return Fluentd
733 parseJSON (JSON.String "awslogs") = return AwsLogs
734 parseJSON (JSON.String "splunk") = return Splunk
735 parseJSON (JSON.String "etwlogs") = return Etwlogs
736 parseJSON (JSON.String "none") = return LoggingDisabled
737 parseJSON _ = fail "Unknown LogDriverType"
739instance ToJSON LogDriverType where
740 toJSON JsonFile = JSON.String "json-file"
741 toJSON Syslog = JSON.String "syslog"
742 toJSON Journald = JSON.String "journald"
743 toJSON Gelf = JSON.String "gelf"
744 toJSON Fluentd = JSON.String "fluentd"
745 toJSON AwsLogs = JSON.String "awslogs"
746 toJSON Splunk = JSON.String "splunk"
747 toJSON Etwlogs = JSON.String "etwlogs"
748 toJSON LoggingDisabled = JSON.String "none"
750newtype LogDriverOptions = LogDriverOptions (M.Map Text Text) deriving (Eq, Show)
752instance FromJSON LogDriverOptions where
753 parseJSON (JSON.Object o) = do
754 LogDriverOptions <$> HM.foldlWithKey' f (return M.empty) o
757 f accM k (JSON.String v) = do
759 return $ M.insert k v acc
760 f _ _ _ = fail "Value of LogDriverOptions is not a string"
762 parseJSON JSON.Null = return $ LogDriverOptions M.empty
763 parseJSON _ = fail "LogDriverOptions is not an object"
765instance ToJSON LogDriverOptions where
766 toJSON (LogDriverOptions mp) = toJSON mp
768data LogDriverConfig = LogDriverConfig LogDriverType (Maybe LogDriverOptions) deriving (Eq, Show)
770instance ToJSON LogDriverConfig where
771 toJSON (LogDriverConfig driverType driverOptions) = object ["Type" .= driverType, "Config" .= driverOptions]
773instance FromJSON LogDriverConfig where
774 parseJSON (JSON.Object o) = do
776 opts <- o .: "Config"
777 return $ LogDriverConfig typ opts
778 parseJSON _ = fail "LogDriverConfig is not an object"
780-- TODO: Add container:<name|id> mode
781data NetworkMode = Bridge | Host | NetworkDisabled
782 deriving (Eq, Show, Ord)
784instance FromJSON NetworkMode where
785 parseJSON (JSON.String "bridge") = return Bridge
786 parseJSON (JSON.String "host") = return Host -- Note: Guessing on these.
787 parseJSON (JSON.String "none") = return NetworkDisabled
788 parseJSON _ = fail "Unknown NetworkMode"
790instance ToJSON NetworkMode where
791 toJSON Bridge = JSON.String "bridge"
792 toJSON Host = JSON.String "host"
793 toJSON NetworkDisabled = JSON.String "none"
795data PortType = TCP | UDP deriving (Eq, Show, Generic, Read, Ord)
797instance ToJSON PortType where
801instance FromJSON PortType where
802 parseJSON val = case val of
805 _ -> fail "PortType: Invalid port type."
807newtype NetworkInterface = NetworkInterface Text deriving (Eq, Show)
809instance FromJSON NetworkInterface where
810 parseJSON (JSON.String v) = return $ NetworkInterface v
811 parseJSON _ = fail "Network interface is not a string."
813instance ToJSON NetworkInterface where
814 toJSON (NetworkInterface i) = JSON.String i
816-- | This datastructure models mapping a Port from the container onto the
817-- host system s that the service running in the container can be accessed from
818-- the outside world. We either map a port onto all interfaces (default) or onto a specific
819-- interface like `127.0.0.1`.
820newtype PortBindings = PortBindings [PortBinding]
823-- { <port>/<protocol>: [{ "HostPort": "<port>" }] }
824data PortBinding = PortBinding {
825 containerPort :: Port
826 , portType :: PortType
827 , hostPorts :: HostPorts
828 } deriving (Eq, Show)
831portAndType2Text :: Port -> PortType -> Text
832portAndType2Text p t = (T.pack $ show p) <> "/" <> (T.pack $ show t)
834instance ToJSON PortBinding where
835 toJSON (PortBinding {..}) = object [portAndType2Text containerPort portType .= hostPorts]
837instance FromJSON PortBindings where
838 parseJSON (JSON.Object o) = do
839 PortBindings <$> HM.foldlWithKey' f (return []) o
842 f accM k v = case T.split (== '/') k of
843 [port', portType'] -> do
844 port <- parseIntegerText port'
845 portType <- parseJSON $ JSON.String portType'
848 return $ (PortBinding port portType hps):acc
850 fail "Could not parse PortBindings"
851 parseJSON _ = fail "PortBindings is not an object"
853instance ToJSON PortBindings where
854 toJSON (PortBindings []) = JSON.Object HM.empty
855 toJSON (PortBindings (p:ps)) = toJSON (p:ps)
857data HostPort = HostPort NetworkInterface Port
860instance ToJSON HostPort where
861 toJSON (HostPort i p) = object ["HostPort" .= p, "HostIP" .= i]
863instance FromJSON HostPort where
864 parseJSON (JSON.Object o) = do
867 return $ HostPort i p
868 parseJSON _ = fail "HostPort is not an object."
870newtype HostPorts = HostPorts [HostPort]
874instance ToJSON HostPorts where
875 toJSON (HostPorts hps) = toJSON hps
877instance FromJSON HostPorts where
878 parseJSON (JSON.Object o) = do
879 HostPorts <$> HM.foldlWithKey' f (return []) o
885 p <- parseIntegerText p'
886 return $ (HostPort (NetworkInterface k) p):acc
887 parseJSON _ = fail "HostPorts is not an object"
889-- { "Name": "on-failure" , "MaximumRetryCount": 2}
890type RetryCount = Integer
891data RestartPolicy = RestartAlways | RestartUnlessStopped | RestartOnFailure RetryCount | RestartOff deriving (Eq, Show)
893instance FromJSON RestartPolicy where
894 parseJSON (JSON.Object o) = do
895 (name :: Text) <- o .: "Name"
897 "always" -> return RestartAlways
898 "unless-stopped" -> return RestartUnlessStopped
900 retry <- o .: "MaximumRetryCount"
901 return $ RestartOnFailure retry
902 "" -> return RestartOff -- Note: Is this correct? 1.24 spec is unclear.
903 _ -> fail "Could not parse RestartPolicy"
904 parseJSON _ = fail "RestartPolicy is not an object"
906instance ToJSON RestartPolicy where
907 toJSON RestartAlways = object ["Name" .= JSON.String "always"]
908 toJSON RestartUnlessStopped = object ["Name" .= JSON.String "unless-stopped"]
909 toJSON (RestartOnFailure c) = object ["Name" .= JSON.String "on-failure", "MaximumRetryCount" .= c]
910 toJSON RestartOff = object ["Name" .= JSON.String "off"]
912data Isolation = Default | Process | Hyperv deriving (Eq, Show)
914newtype UTSMode = UTSMode Text deriving (Eq, Show)
916-- TODO: Add Tmpfs : List of tmpfs (mounts) used for the container
917-- TODO: Add UTSMode : UTS namespace to use for the container
918-- TODO: Sysctls map[string]string `json:",omitempty"` // List of Namespaced sysctls used for the container
919data HostConfig = HostConfig
921 , containerIDFile :: Maybe FilePath -- 1.24: Only in responses, not create
922 , logConfig :: LogDriverConfig
923 , networkMode :: NetworkMode
924 , portBindings :: PortBindings
925 , restartPolicy :: RestartPolicy
926 , volumeDriver :: Maybe Text
927 , volumesFrom :: [VolumeFrom]
931 , dnsOptions :: [Text]
932 , dnsSearch :: [Text]
933 , extraHosts :: [Text]
934 -- , groupAdd :: [Integer] -- 1.24: Missing from inspecting container details... Going to omit for now.
935 , ipcMode :: Maybe Text -- 1.24: Only in inspect, not create
937 , oomScoreAdj :: Maybe Integer
938 -- , pidMode :: Text -- 1.24: Don't see pidMode, just pidsLimit
940 , publishAllPorts :: Bool
941 , readOnlyRootfs :: Bool
942 , securityOpt :: [Text]
943 -- , utsMode :: UTSMode -- 1.24: Don't see this
944 , shmSize :: Maybe Integer
945 -- , consoleSize :: Integer -- 1.24: Don't see this
946 -- , isolation :: Isolation -- 1.24: Don't see this
947 , resources :: ContainerResources
948 } deriving (Eq, Show, Generic)
950instance FromJSON HostConfig where
951 parseJSON = genericParseJSON defaultOptions {
952 fieldLabelModifier = (\(x:xs) -> toUpper x : xs)}
954instance ToJSON HostConfig where
955 toJSON = genericToJSON defaultOptions {
956 fieldLabelModifier = (\(x:xs) -> toUpper x : xs)}
959-- { "Name": <name>, "Soft": <soft limit>, "Hard": <hard limit> }
960-- { "Name": "nofile", "Soft": 1024, "Hard": 2048 }
961data Ulimit = Ulimit {
963 , ulimitSoft :: Integer
964 , ulimitHard :: Integer
965 } deriving (Eq, Show, Generic)
967instance FromJSON Ulimit where
968 parseJSON = genericParseJSON defaultOptions {
969 fieldLabelModifier = drop 5}
971instance ToJSON Ulimit where
972 toJSON = genericToJSON defaultOptions {
973 fieldLabelModifier = drop 5}
975data ContainerResources = ContainerResources {
976 cpuShares :: Maybe Integer
977 -- , cgroupParent :: Text -- 1.24: Missing from inspecting container details... Going to omit for now.
978 , blkioWeight :: Maybe Text
979 , blkioWeightDevice :: Maybe Text
980 , blkioDeviceReadBps :: Maybe Text
981 , blkioDeviceWriteBps :: Maybe Text
982 , blkioDeviceReadIOps :: Maybe Text
983 , blkioDeviceWriteIOps :: Maybe Text
984 , cpuPeriod :: Maybe Integer
985 -- , cpuQuota :: Integer -- 1.24: Missing from inspecting container details... Going to omit for now.
986 , cpusetCpus :: Maybe Integer
987 , cpusetMems :: Maybe Text
988 , devices :: [Device]
989 -- , diskQuota :: Integer -- Don't see this ins 1.24.
990 , kernelMemory :: Maybe Integer
991 , memory :: Maybe Integer
992 , memoryReservation :: Maybe Integer
993 , memorySwap :: Maybe Integer
994 -- , memorySwappiness :: Integer -- 1.24: Missing from inspecting container details... Going to omit for now.
995 , oomKillDisable :: Bool
996 -- , pidsLimit :: Integer -- 1.24: Missing from inspecting container details... Going to omit for now.
997 , ulimits :: [Ulimit]
998 -- TODO: Missing from 1.24
999 -- StorageOpt :: [(Text, Text)]
1000 -- VolumeDriver :: ??
1001 -- EndpointsConfig :: ??
1002 -- TODO: Only in inspect container in 1.24
1003 -- CpuPercent :: Int +
1004 -- MaximumIOps :: Int +
1005 -- MaximumIOBps :: Int +
1006 -- LxcConf :: [??] +
1007 } deriving (Eq, Show, Generic)
1009instance ToJSON ContainerResources where
1010 toJSON = genericToJSON defaultOptions {
1011 fieldLabelModifier = (\(x:xs) -> toUpper x : xs)}
1013instance FromJSON ContainerResources where
1014 parseJSON = genericParseJSON defaultOptions {
1015 fieldLabelModifier = (\(x:xs) -> toUpper x : xs)}
1022data EnvVar = EnvVar Name Value
1025instance FromJSON EnvVar where
1026 parseJSON (JSON.String env) =
1027 let (n, v') = T.break (== '=') env in
1028 let v = T.drop 1 v' in
1030 parseJSON _ = fail "EnvVar is not a string"
1032instance ToJSON EnvVar where
1033 toJSON (EnvVar n v) = object [n .= v]
1035-- | ExposedPorts represent a enumeraton of all the ports (and their type)
1036-- that a container should expose to other containers or the host system.
1037-- `NOTE`: This does not automatically expose the ports onto the host
1038-- system but rather it just tags them. It's best to be used with
1039-- the PublishAllPorts flag. It is also useful for
1040-- the daemon to know which Environment variables to
1041-- inject into a container linking to our container.
1042-- Example linking a Postgres container named db would inject the following
1043-- environment variables automatically if we set the corresponding
1045-- DB_PORT_5432_TCP_PORT="5432"
1046-- DB_PORT_5432_TCP_PROTO="tcp"
1047-- DB_PORT_5432_TCP="tcp://172.17.0.1:5432"
1048newtype ExposedPorts = ExposedPorts (M.Map Port PortType) deriving (Eq, Show)
1049-- JP: Should this be ExposedPorts [(Port, PortType)]?
1051instance FromJSON ExposedPorts where
1052 parseJSON (JSON.Object o) = do
1053 ExposedPorts <$> HM.foldlWithKey' f (return M.empty) o
1056 f accM k _ = case T.split (== '/') k of
1057 [port', portType'] -> do
1058 port <- parseIntegerText port'
1059 portType <- parseJSON $ JSON.String portType'
1061 return $ M.insert port portType acc
1063 fail "Could not parse ExposedPorts"
1064 parseJSON _ = fail "ExposedPorts is not an object."
1066instance ToJSON ExposedPorts where
1067 toJSON (ExposedPorts kvs) = object [((T.pack $ show p) <> "/" <> (T.pack $ show t)) .= JSON.Object HM.empty | (p,t) <- (M.toList kvs)]
1070data ContainerConfig = ContainerConfig {
1071 hostname :: Maybe Text
1072 , domainname :: Maybe Text
1073 , user :: Maybe Text
1074 , attachStdin :: Bool
1075 , attachStdout :: Bool
1076 , attachStderr :: Bool
1077 , exposedPorts :: ExposedPorts
1078 -- , publishService :: Text -- Don't see this in 1.24
1084 -- , argsEscaped :: Bool -- Don't see this in 1.24
1086 , volumes :: Maybe Volumes
1087 , workingDir :: Maybe FilePath
1088 , entrypoint :: Maybe Text -- Can be null?
1089 , networkDisabled :: Bool
1090 , macAddress :: Maybe Text
1091 -- , onBuild :: Text -- For 1.24, only see this in the inspect response.
1092 , labels :: Maybe Labels
1093 , stopSignal :: Signal
1094 } deriving (Eq, Show, Generic)
1096instance ToJSON ContainerConfig where
1097 toJSON = genericToJSON defaultOptions {
1098 fieldLabelModifier = (\(x:xs) -> toUpper x : xs)}
1100instance FromJSON ContainerConfig where
1101 parseJSON = genericParseJSON defaultOptions {
1102 fieldLabelModifier = (\(x:xs) -> toUpper x : xs)}
1104parseIntegerText :: (Monad m) =>Text -> m Integer
1105parseIntegerText t = case readMaybe $ T.unpack t of
1107 fail "Could not parse Integer"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list