|
| 1 | +# kubernetes-client |
| 2 | + |
| 3 | +## Example |
| 4 | + |
| 5 | +```haskell |
| 6 | +{-# LANGUAGE OverloadedStrings #-} |
| 7 | + |
| 8 | +module Main where |
| 9 | + |
| 10 | +import Data.Function ((&)) |
| 11 | +import Kubernetes.Client (defaultTLSClientParams, |
| 12 | + disableServerCertValidation, |
| 13 | + disableServerNameValidation, |
| 14 | + disableValidateAuthMethods, |
| 15 | + loadPEMCerts, newManager, |
| 16 | + setCAStore, setClientCert, |
| 17 | + setMasterURI, setTokenAuth) |
| 18 | +import Kubernetes.OpenAPI (Accept (..), MimeJSON (..), |
| 19 | + dispatchMime, newConfig) |
| 20 | +import qualified Kubernetes.OpenAPI.API.CoreV1 as CoreV1 |
| 21 | +import Network.TLS (credentialLoadX509) |
| 22 | + |
| 23 | +main :: IO () |
| 24 | +main = do |
| 25 | + -- We need to first create a Kubernetes.Core.KubernetesConfig and a Network.HTTP.Client.Manager. |
| 26 | + -- Currently we need to construct these objects manually. Work is underway to construct these |
| 27 | + -- objects automatically from a kubeconfig file. See https://github.com/kubernetes-client/haskell/issues/2. |
| 28 | + kcfg <- |
| 29 | + newConfig |
| 30 | + & fmap (setMasterURI "https://mycluster.example.com") -- fill in master URI |
| 31 | + & fmap (setTokenAuth "mytoken") -- if using token auth |
| 32 | + & fmap disableValidateAuthMethods -- if using client cert auth |
| 33 | + myCAStore <- loadPEMCerts "/path/to/ca.crt" -- if using custom CA certs |
| 34 | + myCert <- -- if using client cert |
| 35 | + credentialLoadX509 "/path/to/client.crt" "/path/to/client.key" |
| 36 | + >>= either error return |
| 37 | + tlsParams <- |
| 38 | + defaultTLSClientParams |
| 39 | + & fmap disableServerNameValidation -- if master address is specified as an IP address |
| 40 | + & fmap disableServerCertValidation -- if you don't want to validate the server cert at all (insecure) |
| 41 | + & fmap (setCAStore myCAStore) -- if using custom CA certs |
| 42 | + & fmap (setClientCert myCert) -- if using client cert |
| 43 | + manager <- newManager tlsParams |
| 44 | + dispatchMime |
| 45 | + manager |
| 46 | + kcfg |
| 47 | + (CoreV1.listPodForAllNamespaces (Accept MimeJSON)) |
| 48 | + >>= print |
| 49 | +``` |
| 50 | + |
| 51 | +## Watch Example |
| 52 | +Following is a simple example which |
| 53 | +just streams to stdout. First some setup - this assumes kubernetes is accessible |
| 54 | +at http://localhost:8001, e.g. after running `kubectl proxy`: |
| 55 | + |
| 56 | +```haskell |
| 57 | +> import qualified Data.ByteString.Streaming.Char8 as Q |
| 58 | + |
| 59 | +> manager <- newManager defaultManagerSettings |
| 60 | +> defaultConfig <- newConfig |
| 61 | +> config = defaultConfig { configHost = "http://localhost:8001", configValidateAuthMethods = False } |
| 62 | +> request = listEndpointsForAllNamespaces (Accept MimeJSON) |
| 63 | +``` |
| 64 | + |
| 65 | +Launching 'dispatchWatch' with the above we get a stream of endpoints data: |
| 66 | + |
| 67 | +```haskell |
| 68 | + > dispatchWatch manager config request Q.stdout |
| 69 | + {"type":\"ADDED\","object":{"kind":\"Endpoints\","apiVersion":"v1","metadata":{"name":"heapster" .... |
| 70 | +``` |
| 71 | +
|
| 72 | +A more complex example involving some ggprocessing of the stream, the following |
| 73 | +prints out the event types of each event. First, define functions to allow us apply |
| 74 | +a parser to a stream: |
| 75 | +
|
| 76 | +
|
| 77 | +```haskell |
| 78 | +import Data.Aeson |
| 79 | +import qualified Data.ByteString.Streaming.Char8 as Q |
| 80 | +import Data.JsonStream.Parser |
| 81 | +import qualified Streaming.Prelude as S |
| 82 | +
|
| 83 | +-- | Parse the stream using the given parser. |
| 84 | +streamParse :: |
| 85 | + FromJSON a => |
| 86 | + Parser a |
| 87 | + -> Q.ByteString IO r |
| 88 | + -> Stream (Of [a]) IO r |
| 89 | +streamParse parser byteStream = do |
| 90 | + byteStream & Q.lines & parseEvent parser |
| 91 | +
|
| 92 | +-- | Parse a single event from the stream. |
| 93 | +parseEvent :: |
| 94 | + (FromJSON a, Monad m) => |
| 95 | + Parser a |
| 96 | + -> Stream (Q.ByteString m) m r |
| 97 | + -> Stream (Of [a]) m r |
| 98 | +parseEvent parser byteStream = S.map (parseByteString parser) (S.mapped Q.toStrict byteStream) |
| 99 | +``` |
| 100 | +
|
| 101 | +Next, define the parser and apply it to the stream: |
| 102 | +
|
| 103 | +```haskell |
| 104 | +> eventParser = value :: Parser (WatchEvent V1Endpoints) |
| 105 | +> withResponseBody body = streamParse eventParser body & S.map (map eventType) |
| 106 | +> dispatchWatch manager config request (S.print . withResponseBody) |
| 107 | +[\"ADDED\"] |
| 108 | +[\"ADDED\"] |
| 109 | +[\"MODIFIED\"] |
| 110 | +... |
| 111 | +``` |
| 112 | +
|
| 113 | +Packages in this example: |
| 114 | + * Data.Aeson -- from [aeson](https://hackage.haskell.org/package/aeson) |
| 115 | + * Data.ByteString.Streaming.Char8 from [streaming-bytestring](https://hackage.haskell.org/package/streaming-bytestring-0.1.5/docs/Data-ByteString-Streaming-Char8.html) |
| 116 | + * Data.JsonStream.Parser from [json-stream](https://hackage.haskell.org/package/json-stream-0.4.1.5/docs/Data-JsonStream-Parser.html) |
| 117 | + * Streaming.Prelude from [streaming](https://hackage.haskell.org/package/streaming-0.2.0.0/docs/Streaming-Prelude.html) |
0 commit comments