Skip to content

Commit 7478258

Browse files
committed
Add a simple example to be run in integration tests
1 parent 0190166 commit 7478258

File tree

6 files changed

+194
-0
lines changed

6 files changed

+194
-0
lines changed

examples/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
dist
2+
dist-newstyle
3+
*.cabal
4+
.stack-work

examples/LICENSE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../LICENSE

examples/package.yaml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: kubernetes-examples
2+
version: 0.1.0.1
3+
description: |
4+
Examples to interact with Kubernetes using kubernetes-client and kubernetes-client-core
5+
synopsis: Kubernetes examples with Haskell
6+
maintainer:
7+
- Shimin Guo <[email protected]>
8+
- Akshay Mankar <[email protected]>
9+
category: Examples, Kubernetes
10+
license: Apache-2.0
11+
license-file: LICENSE
12+
13+
executables:
14+
simple:
15+
main: Main.hs
16+
source-dirs: simple
17+
ghc-options:
18+
- -Wall
19+
20+
dependencies:
21+
- base
22+
- containers
23+
- http-client
24+
- http-types
25+
- kubernetes-client
26+
- kubernetes-client-core
27+
- safe-exceptions
28+
- stm
29+
- text

examples/simple/Main.hs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
module Main where
3+
4+
import Control.Concurrent.STM
5+
import Control.Exception.Safe
6+
import Kubernetes.Client
7+
import Kubernetes.OpenAPI
8+
import Kubernetes.OpenAPI.API.AppsV1
9+
import Kubernetes.OpenAPI.API.CoreV1
10+
import Network.HTTP.Client
11+
import Network.HTTP.Types.Status
12+
import System.Environment
13+
14+
import qualified Data.Map as Map
15+
import qualified Data.Text as T
16+
import qualified Data.Text.IO as T
17+
18+
main :: IO ()
19+
main = do
20+
kubeConfigFile <- getEnv "KUBECONFIG"
21+
oidcCache <- newTVarIO $ Map.fromList []
22+
(manager, cfg) <- mkKubeClientConfig oidcCache
23+
$ KubeConfigFile kubeConfigFile
24+
let createNamespaceRequest =
25+
createNamespace (ContentType MimeJSON) (Accept MimeJSON) testNamespace
26+
createdNS <- assertMimeSuccess =<< dispatchMime manager cfg createNamespaceRequest
27+
nsName <- assertJust "Expected K8s to generate name for namespace, but it didn't"
28+
$ (v1ObjectMetaName =<< v1NamespaceMetadata createdNS)
29+
T.putStrLn $ "Created Namespace: " <> nsName
30+
31+
let createDeploymentRequest =
32+
createNamespacedDeployment (ContentType MimeJSON) (Accept MimeJSON) testDeployment (Namespace nsName)
33+
deployment <- assertMimeSuccess =<< dispatchMime manager cfg createDeploymentRequest
34+
T.putStrLn $ "Created Deployment: " <> maybe "No name!?" id (v1DeploymentMetadata deployment >>= v1ObjectMetaName)
35+
36+
let listDeploymentsRequest =
37+
listNamespacedDeployment (Accept MimeJSON) (Namespace nsName)
38+
listedDeployments <- assertMimeSuccess =<< dispatchMime manager cfg listDeploymentsRequest
39+
let numberOfDeployments = length $ v1DeploymentListItems listedDeployments
40+
if numberOfDeployments /= 1
41+
then throwM $ AssertionFailure $ "Expected 1 deployment, found: " <> show numberOfDeployments
42+
else putStrLn "Test successful!"
43+
44+
-- NOTE: We cannot use dispatchMime due to this issue: https://github.com/kubernetes/kubernetes/issues/59501
45+
let deleteNamespaceRequest =
46+
deleteNamespace (ContentType MimeJSON) (Accept MimeJSON) (Name nsName)
47+
deleteNamespaceResponse <- dispatchLbs manager cfg deleteNamespaceRequest
48+
if responseStatus deleteNamespaceResponse /= status200
49+
then throwM $ AssertionFailure
50+
$ "Failed to cleanup namespace: " <> T.unpack nsName
51+
<> "\nStatus Code: " <> show (responseStatus deleteNamespaceResponse)
52+
<> "\nBody: " <> show (responseBody deleteNamespaceResponse)
53+
else return ()
54+
putStrLn "Clenaup complete!"
55+
56+
testDeployment :: V1Deployment
57+
testDeployment =
58+
let labelSelector =
59+
mkV1LabelSelector
60+
{ v1LabelSelectorMatchLabels =
61+
Just $ Map.fromList [("app", "test")] }
62+
container =
63+
(mkV1Container "container-name")
64+
{ v1ContainerImage = Just $ "nginx" }
65+
podTemplate =
66+
mkV1PodTemplateSpec
67+
{ v1PodTemplateSpecMetadata =
68+
Just $ mkV1ObjectMeta
69+
{ v1ObjectMetaLabels = Just $ Map.fromList [("app", "test")] }
70+
, v1PodTemplateSpecSpec =
71+
Just $
72+
mkV1PodSpec [container]
73+
}
74+
in mkV1Deployment
75+
{ v1DeploymentMetadata =
76+
Just $ mkV1ObjectMeta { v1ObjectMetaName = Just "test-deployment" }
77+
, v1DeploymentSpec =
78+
Just
79+
$ (mkV1DeploymentSpec labelSelector podTemplate)
80+
}
81+
82+
testNamespace :: V1Namespace
83+
testNamespace =
84+
let nsMetadata =
85+
mkV1ObjectMeta
86+
{ v1ObjectMetaGenerateName = Just "haskell-client-test-" }
87+
in mkV1Namespace
88+
{ v1NamespaceMetadata = Just nsMetadata }
89+
90+
assertMimeSuccess :: MonadThrow m => MimeResult a -> m a
91+
assertMimeSuccess (MimeResult (Right res) _) = pure res
92+
assertMimeSuccess (MimeResult (Left err) _) =
93+
throwM $ AssertionFailure $ "Unexpected MimeError: " ++ show err
94+
95+
assertJust :: MonadThrow m => String -> Maybe a -> m a
96+
assertJust err Nothing = throwM $ AssertionFailure err
97+
assertJust _ (Just x) = return x
98+
99+
data AssertionFailure = AssertionFailure String
100+
deriving Show
101+
102+
instance Exception AssertionFailure

examples/stack.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
resolver: lts-13.9
2+
packages:
3+
- .
4+
- ../kubernetes-client
5+
- ../kubernetes
6+
extra-deps:
7+
- jsonpath-0.1.0.1
8+
- jwt-0.10.0
9+
- katip-0.8.0.0
10+
- oidc-client-0.4.0.0
11+
- string-random-0.1.2.0

examples/stack.yaml.lock

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# This file was autogenerated by Stack.
2+
# You should not edit this file by hand.
3+
# For more information, please see the documentation at:
4+
# https://docs.haskellstack.org/en/stable/lock_files
5+
6+
packages:
7+
- completed:
8+
hackage: jsonpath-0.1.0.1@sha256:55718ac52b25cd8ce80fbdc9079a112344f032b056cfaf30737a29b6bd1a5c12,2377
9+
pantry-tree:
10+
size: 1097
11+
sha256: 027749c943abaa6a78adc58e5abd4b3f42644c17c5fb7edf816557424a79448b
12+
original:
13+
hackage: jsonpath-0.1.0.1
14+
- completed:
15+
hackage: jwt-0.10.0@sha256:d14551b0c357424fb9441ec9a7a9d5b90b13f805fcc9327ba49db548cd64fc29,4180
16+
pantry-tree:
17+
size: 1027
18+
sha256: e0cf95e834d99768ad8a3f7e99246948f0cdd2cfa18813517f540144aea6c3e5
19+
original:
20+
hackage: jwt-0.10.0
21+
- completed:
22+
hackage: katip-0.8.0.0@sha256:8a74858b692edfdbe83ac377b116111f81b4dcda774024615967d764f9f474b8,4097
23+
pantry-tree:
24+
size: 1140
25+
sha256: f6baad9ee2edc7ed02d71bd8433872403500ebbdfaead9e4ef226dc47b3c4b97
26+
original:
27+
hackage: katip-0.8.0.0
28+
- completed:
29+
hackage: oidc-client-0.4.0.0@sha256:f72a496ab27d9a5071be44e750718c539118ac52c2f1535a5fb3dde7f9874a55,3306
30+
pantry-tree:
31+
size: 1153
32+
sha256: 68c285c6365360975d50bbb18cb07755d5ef19af8bf0e998d3ea46d35ef4a4e1
33+
original:
34+
hackage: oidc-client-0.4.0.0
35+
- completed:
36+
hackage: string-random-0.1.2.0@sha256:db4f801dec1ec72cba7d662b9774da60ff54de6d05478e94478d6d730dc5034f,2439
37+
pantry-tree:
38+
size: 489
39+
sha256: 21c7e61fceea98d14b453fc74c947b715ce33fe4c665c65b1f28c6f417d4ab7e
40+
original:
41+
hackage: string-random-0.1.2.0
42+
snapshots:
43+
- completed:
44+
size: 496697
45+
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/13/9.yaml
46+
sha256: 3846ba7d13dd1b2679426dc3f450332a3b8a181063b0f3fc2d0c7d55db2e9c24
47+
original: lts-13.9

0 commit comments

Comments
 (0)