Stage deploy.

This commit is contained in:
Oly 2019-10-11 16:45:52 +01:00
commit b3ba803631
6 changed files with 681 additions and 0 deletions

View File

@ -0,0 +1,62 @@
{:registry ""
:images {:django "registry.gitlab.com/maidstone-hackspace/maidstone-hackspace-website:latest"
:nginx-ingress "nginx/nginx-ingress"
:nginx "nginx:alpine"
:redis "redis:5.0-rc"
:rabbitmq "rabbitmq:management-alpine"
:postgres "postgres"}
:environment "stage"
:vars
{:MY_DOMAIN_NAME "stage.maidstone-hackspace.org.uk"
:COMPOSE_PROJECT_NAME "hackstage"
:GUNICORN "/stage-gunicorn-mhackspace.sh"
:POSTGRES_PASSWORD "mysecretpass"
:POSTGRES_USER "postgresuser"
:DATABASE_URL "postgres://postgresuser:mysecretpass@postgres:5432/postgresuser"
:DJANGO_ADMIN_URL "trustee/"
:DJANGO_SETTINGS_MODULE "config.settings.stage"
:DJANGO_SECRET_KEY "iud%k99yw!e+z+c12uatugbn \"&lsdyd(t_byk9)@dp@lj6*c*n"
:DJANGO_ALLOWED_HOSTS "stage.maidstone-hackspace.org.uk,165.227.230.86"
:DJANGO_DEBUG "False"
:BUCKET_PREFIX_PATH "stage/"
:DJANGO_AWS_ACCESS_KEY_ID ""
:DJANGO_AWS_SECRET_ACCESS_KEY ""
:DJANGO_AWS_STORAGE_BUCKET_NAME ""
:REDIS_URL "redis://redis:6379"
:CELERY_BROKER_URL "redis://redis:6379"
:CELERY_RESULT_BACKEND "redis://redis:6379"
:DJANGO_MAILGUN_API_KEY ""
:DJANGO_SERVER_EMAIL "support@digitaloctave.com"
:MAILGUN_SENDER_DOMAIN ""
:EMAIL_USER "no-reply@digitaloctave.com"
:EMAIL_PASSWORD "5fere5V.9quQe"
:DJANGO_ACCOUNT_ALLOW_REGISTRATION "True"
:COMPRESS_ENABLED ""
:PAYMENT_ENVIRONMENT "sandbox"
:PAYMENT_REDIRECT_URL "https://test.maidstone-hackspace.org.uk"
:BRAINTREE_MERCHANT_ID "b3sdmyczd3fz6b3p"
:BRAINTREE_PUBLIC_KEY "rxb7yffm3tk758rq"
:BRAINTREE_PRIVATE_KEY "62f92d2b00a451c40fdf5fbca54f0421"
:PAYPAL_CLIENT_ID "AaGlNEvd26FiEJiJi53nfpXh19_oKetteV1NGkBi4DDYZSqBexKVgaz9Lp0SI82gYFSAYpsmxO4iDtxU"
:PAYPAL_CLIENT_SECRET "EMcIuDJE_VDNSNZS7C7NLi9DEHaDvVu9jlIYyCCHaLmrLuy_VQ6C0bbcRnyF-7B6CcN__Dn6HqUwsgMG"
:GOCARDLESS_APP_ID "MNHBS3C4X4ZG211SM70WSS7WCN8B3X1KAWZBKV9S8N6KH2RNH6YZ5Z5865RFD3H6"
:GOCARDLESS_APP_SECRET "NE4NWYDQY4FNN1B47VT9SZ318GPQND130DW7QGQ73JMVTZQZHJQNF23ZFNP48GKV"
:GOCARDLESS_ACCESS_TOKEN "CJ7G7V36VAH5KVAHTYXD8VE8M4M0S41EQXH2E1HTGV5AN5TAZBER36ERAF4CG2NR"
;:GOCARDLESS_ACCESS_TOKEN "sandbox_-ATBL3jeCXroOBM2nhvwjNzr1utQ7UN5esbB4vIc"
:GOCARDLESS_MERCHANT_ID "11QFXD7TTA"
:MATRIX_ROOM "fmCpNwqgIiuwATlcdw:matrix.org"
:MATRIX_USERNAME "mhackspace"
:MATRIX_PASSWORD "AjwsoD952vdOo"
:BUCKET_NAME "mhackspace"
:BUCKET_ACCESS_KEY "UGCVGOUYW2XER4UNV62W"
:BUCKET_SECRET_KEY "bWB6H/LQuPUuZSAOvQuei0gtDSR4BQYz/gBOYUn+VIU"
:LDAP_ORGANISATION "Maidstone Hackspace Test"
:LDAP_DOMAIN "stage.maidstone-hackspace.org.uk"
:LDAP_ADMIN_PASSWORD "NSNZ8xjXwVxis"
:LDAP_SERVER "directory"
:LDAP_ROOT "dc \"stage, dc \"maidstone-hackspace, dc \"org, dc \"uk"
:TWITTER_CONSUMER_KEY "ZdLvlgNBiTNfTWkkKY0ub9F1j"
:TWITTER_CONSUMER_SECRET "z3q5mANhNnIHEO6pXhz5Onex41WHObbZRGZ6MS9WchoTA29qQ7"
:TWITTER_ACCESS_TOKEN "2756146621-3vJvbfIaeHMMoghaPy7D587xls3QmukyXkC4OGh"
:TWITTER_ACCESS_SECRET "PWc6oZFZCXuYxf9VWZxBidPw2AKj69gSvZX0qSz8JQFPu"
:RFID_SECRET "jkhgfkjghjhjgf,kjknsfdkjjadjhglaskjnfjvysyjhbfsckjkbh"}}

12
project.clj Normal file
View File

@ -0,0 +1,12 @@
(defproject kube-deploy "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/data.codec "0.1.1"]
[nano-id "0.9.3"]
[brosenan/lambdakube "0.7.0"]]
:plugins [[lein-auto "0.1.3"]]
:auto {:default {:file-pattern #"\.(clj|cljs|cljx|cljc|edn)$"}}
:main kube-deploy.core)

3
readme.org Normal file
View File

@ -0,0 +1,3 @@
# Auto deploy script
Based on (https://github.com/brosenan/lambdakube-example) using (https://github.com/brosenan/lambda-kube) library.

331
src/kube_deploy/core.clj Normal file
View File

@ -0,0 +1,331 @@
(ns kube-deploy.core
(:require [lambdakube.core :as lk]
[kube-deploy.helpers :as lkh]
[lambdakube.util :as lku]
[clojure.java.shell :as sh]
[clojure.java.io :as io]))
(def conf (atom {}))
(def config {:num-be-slaves 3 :num-fe-replicas 3})
(def resources-mini
{:requests
{:cpu "100m" :memory "64Mi"}
:limits
{:cpu "200m" :memory "256Mi"}})
(def resources-small
{:requests
{:cpu "100m" :memory "100Mi"}
:limits
{:cpu "200m" :memory "400Mi"}})
(def resources-medium
{:requests
{:cpu "200m" :memory "400Mi"}
:limits
{:cpu "500m" :memory "1Gi"}})
; will not be needed soon
(defn kube-apply-namespace
([content file]
(kube-apply-namespace content file nil nil))
([content file namespace]
(kube-apply-namespace content namespace nil))
([content file kube-namespace kube-config]
(let [namespace-param (if (nil? namespace) nil (str "--namespace=" kube-namespace))
config-param (if (nil? config) nil (str "--kubeconfig=" kube-config))]
(when-not (and (.exists file)
(= (slurp file) content))
(spit file content)
(let [res (apply sh/sh (remove nil? ["kubectl" "apply" namespace-param config-param "-f" (str file)]))]
(when-not (= (:exit res) 0)
(.delete file)
(throw (Exception. (:err res)))))))))
(defn redis [kube-injector]
(-> kube-injector
(lk/rule :redis-master-rule []
(fn []
(-> (lk/pod :redis-master {:app :redis
:role :master
:tier :backend})
(lk/add-container :redis (get-in @conf [:images :redis])
(-> {}
(lkh/add-to-spec :resources resources-small)
(lkh/add-readiness-probe-cmd ["redis-cli" "--version"])
(lkh/add-liveness-probe-cmd ["redis-cli" "--version"])))
(lk/deployment 1)
(lk/expose-cluster-ip :redis-master
(lk/port :redis :redis 6379 6379)))))
(lk/rule :redis-slave-rule [:redis-master-rule :num-be-slaves]
(fn [backend-master num-be-slaves]
(-> (lk/pod :redis-slave {:app :redis
:role :slave
:tier :backend})
(lk/add-container :redis (get-in @conf [:images :redis])
(-> {}
(lkh/add-to-spec :resources resources-small)
(lkh/add-to-spec
:args ["--slaveof"
(:hostname backend-master)
(-> backend-master :ports :redis str)])
(lkh/add-liveness-probe-cmd ["redis-cli" "--version"])))
(lk/deployment num-be-slaves)
(lk/expose-cluster-ip :redis-slave
(lk/port :redis :redis 6379 6379)))))))
(defn database [kube-injector]
(-> kube-injector
(lk/rule :postgres-master-rule []
(fn []
(-> (lk/pod
:postgres-master
{:app :postgres :role :master :tier :backend})
(lk/add-container :postgres (get-in @conf [:images :postgres])
(-> {}
(lkh/add-to-spec :resources resources-small)
(lkh/add-readiness-probe-cmd ["pg_isready"])
(lkh/add-liveness-probe-cmd ["pg_isready"])
(lkh/add-to-spec :envFrom [{:secretRef {:name "environment"}}])))
(lk/deployment 1)
(lk/expose-cluster-ip :postgres-master
(lk/port :postgres :postgres 5432 5432)))))))
(defn rabbitmq [kube-injector]
(-> kube-injector
(lk/rule :rabbit-master-rule []
(fn []
(-> (lk/pod
:rabbit-master
{:app :rabbit :role :master :tier :backend})
(lk/add-container
:rabbit
(get-in @conf [:images :rabbitmq])
(-> {}
(lkh/add-to-spec :resources resources-medium)
(lkh/add-liveness-probe-cmd ["rabbitmq-diagnostics" "ping" "-q"])))
(lk/deployment 1)
(lk/expose-cluster-ip
:rabbit-master (lk/port :rabbit :rabbit 5672 5672)))))))
(defn hackspace [kube-injector]
(-> kube-injector
(lk/rule :hackspace-backend-master [:postgres-master-rule :redis-master-rule]
(fn [postgres redis]
(-> (lk/pod :hackspace-master {:app :hackspace
:role :master
:tier :backend}
{:imagePullSecrets [{:name "docker-registry"}]})
; Add containers to the pod, one for frontend assets and one for backend
(lk/add-container
:hackspace-backend
(get-in @conf [:images :django])
(-> {}
(lkh/add-to-spec :resources resources-medium)
(lkh/add-to-spec :command ["/gunicorn.sh"])
(lkh/add-to-spec :ports [{:containerPort 5000 :name "gunicorn-port"}])
(lkh/add-to-spec :envFrom [{:secretRef {:name "environment"}}])
(lkh/add-readiness-probe-cmd ["wget" "127.0.0.1:5000"])
(lkh/add-liveness-probe-cmd ["wget" "127.0.0.1:5000"])))
#_(lk/add-container
:hackspace-frontend
(get-in @conf [:images :nginx])
(-> {}
(lkh/add-to-spec :resources resources-mini)
(lkh/add-to-spec :ports [{:containerPort 80 :name "nginx-port"}])
(lkh/add-readiness-probe-cmd ["wget" "127.0.0.1/static/images/favicon.ico"])
(lkh/add-liveness-probe-cmd ["wget" "127.0.0.1/static/images/favicon.ico"])))
(lk/add-volume "static-files" {:emptyDir {}}
{:hackspace-backend "/app/staticfiles"})
; order does matter here, deployment after initcontainers
(lku/wait-for-service-port postgres :postgres)
(lku/wait-for-service-port redis :redis)
; wrap in a deployment
(lk/deployment 2)
(lk/expose-cluster-ip :hackspace-backend
(lk/port :hackspace-master :gunicorn-port 5000 5000))
(lk/expose-cluster-ip :hackspace-frontend
(lk/port :hackspace-master :nginx-port 80 80)))))
(lk/rule :hackspace-queue-master []
(fn []
(-> (lk/pod :hackspace-queue
{:app :hackspace
:role :master
:tier :backend}
{:imagePullSecrets [{:name "docker-registry"}]})
(lk/add-container
:hackspace
(get-in @conf [:images :django])
(-> {}
(lkh/add-to-spec :resources resources-small)
(lkh/add-to-spec :command ["/app/manage.py" "huey"])
(lkh/add-to-spec :envFrom [{:secretRef {:name "environment"}}])))
(lk/deployment 2))))))
(defn footprint [kube-injector]
(-> kube-injector
(lk/rule :footprint-backend-master [:postgres-master-rule :redis-master-rule :rabbit-master-rule]
(fn [postgres redis rabbit]
(-> (lk/pod :footprint-master {:app :footprint
:role :master
:tier :backend}
{:imagePullSecrets [{:name "docker-registry"}]})
; Add containers to the pod, one for frontend assets and one for backend
(lk/add-container
:footprint-backend
(get-in @conf [:images :footprint])
(-> {}
(lkh/add-to-spec :resources resources-medium)
(lkh/add-to-spec :command ["/gunicorn.sh"])
(lkh/add-to-spec :ports [{:containerPort 5000 :name "gunicorn-port"}])
(lkh/add-to-spec :envFrom [{:secretRef {:name "environment"}}])
#_(lkh/add-readiness-probe-get "http://127.0.0.1" 5000)
(lkh/add-liveness-probe-get "http://127.0.0.1" 5000)))
(lk/add-container
:footprint-frontend
(get-in @conf [:images :nginx])
(-> {}
(lkh/add-to-spec :resources resources-mini)
(lkh/add-to-spec :ports [{:containerPort 80 :name "nginx-port"}])
#_(lkh/add-readiness-probe-get "127.0.0.1/static/images/favicon.ico" 80)
(lkh/add-liveness-probe-get "http://127.0.0.1/static/images/favicon.ico" 80)))
(lk/add-volume "static-files" {:emptyDir {}}
{:footprint-backend "/app/staticfiles"
:footprint-frontend "/usr/share/nginx/html/static/"})
; order does matter here, deployment after initcontainers
(lku/wait-for-service-port postgres :postgres)
(lku/wait-for-service-port redis :redis)
(lku/wait-for-service-port rabbit :rabbit)
; wrap in a deployment
(lk/deployment 2)
(lk/expose-cluster-ip :footprint-backend
(lk/port :footprint-master :gunicorn-port 5000 5000))
(lk/expose-cluster-ip :footprint-frontend
(lk/port :footprint-master :nginx-port 80 80)))))
(lk/rule :footprint-queue-master []
(fn []
(-> (lk/pod :footprint-queue
{:app :footprint
:role :master
:tier :backend}
{:imagePullSecrets [{:name "docker-registry"}]})
(lk/add-container
:footprint
(get-in @conf [:images :footprint])
(-> {}
(lkh/add-to-spec :resources resources-small)
(lkh/add-to-spec :command ["/app/manage.py" "rundramatiq" "-p" "1" "-t" "1"])
(lkh/add-to-spec :envFrom [{:secretRef {:name "environment"}}])))
(lk/deployment 2))))))
(defn make-secrets [kube-injector name data]
(-> kube-injector
(lk/rule :secrets []
(fn []
(-> (lkh/secrets (keyword name) data))))))
(defn make-registry-secrets [kube-injector name data]
(-> kube-injector
(lk/rule
:secrets-registry []
(fn []
(lkh/secrets-registry name {} (lkh/encode-secret-map data))))))
(defn make-namespace [kube-injector name]
(-> kube-injector
(lk/rule :namespace []
(fn []
(lkh/kube-namespace (keyword name))))))
(defn make-environment-secrets [kube-injector name data]
(-> kube-injector
(lk/rule :secrets-environment []
(fn []
(lkh/secrets name {}
(lkh/encode-secret-map data))))))
(defn make-ingress [kube-injector]
(lk/rule kube-injector :lkube-ingress []
(fn []
(-> (lkh/ingress "lkube-ingress" {:app :nginx-ingress})
(lkh/add-spec :tls [{:hosts [:lkube-ingress] :secretName "lkube-tls"}])
(lkh/add-spec :rules [{:host "lkube-ingress.35.197.252.20.nip.io"
:http {:paths
[{:path "/"
:backend
{:serviceName "footprint-backend"
:servicePort 5000}}
{:path "/static/"
:backend
{:serviceName "footprint-frontend"
:servicePort 80}}]}}])
(lk/add-annotation :kubernetes.io/tls-acme "true")
(lk/add-annotation :kubernetes.io/ingress.class "nginx")))))
(defn footprint-deployment [namespace kube-config]
(reset! conf (clojure.edn/read-string (slurp (str namespace "-config.edn"))))
; run deployment in default namespace to create a namespace called footprint
(-> (lk/injector)
(make-namespace namespace)
lk/standard-descs
(lk/get-deployable config)
(lkh/to-yaml-store (str namespace "-store.yaml"))
(kube-apply-namespace (io/file (str namespace "-deploy.yaml")) nil kube-config))
; run deployment under footprint namespace
(-> (lk/injector)
(make-environment-secrets :environment (:vars @conf))
(make-registry-secrets :docker-registry {:.dockerconfigjson (:registry @conf)})
make-ingress
rabbitmq
database
redis
footprint
lk/standard-descs
(lk/get-deployable config)
(lkh/to-yaml-store (str namespace "-store.yaml"))
(kube-apply-namespace (io/file (str namespace "-deploy.yaml")) "footprint" kube-config)))
(defn hackspace-deployment [namespace kube-config]
(reset! conf (clojure.edn/read-string (slurp (str namespace "-config.edn"))))
; run deployment in default namespace to create a namespace called footprint
(-> (lk/injector)
(make-namespace namespace)
;lk/standard-descs
(lk/get-deployable config)
(lkh/to-yaml-store (str namespace "-store.yaml"))
(kube-apply-namespace (io/file (str namespace "-deploy.yaml")) nil kube-config))
; run deployment under footprint namespace
(-> (lk/injector)
(make-environment-secrets :environment (:vars @conf))
;(make-registry-secrets :docker-registry {:.dockerconfigjson (:registry @conf)})
make-ingress
database
redis
hackspace
lk/standard-descs
(lk/get-deployable config)
(lkh/to-yaml-store (str namespace "-store.yaml"))
(kube-apply-namespace (io/file (str namespace "-deploy.yaml")) namespace kube-config)))
(defn -main []
(hackspace-deployment "maidstone-hackspace" "/home/oly/.kube/dke.yml")
(footprint-deployment "footprint" "/home/oly/.kube/ake.yml"))

170
src/kube_deploy/helpers.clj Normal file
View File

@ -0,0 +1,170 @@
(ns kube-deploy.helpers
(:require [lambdakube.core :as lk]
[clojure.data.codec.base64 :as b64]))
(defn kube-namespace
([name]
{:apiVersion "v1"
:kind "Namespace"
:metadata {:name name}}))
(defn secrets
([name labels options]
{:apiVersion "v1"
:kind "Secret"
:type "Opaque"
:metadata {:name name :labels labels}
:data options}))
(defn secrets-registry
([name labels options]
{:apiVersion "v1"
:kind "Secret"
:type "kubernetes.io/dockerconfigjson"
:metadata {:name name :labels labels}
:data options}))
(defn ingress
([name labels]
(ingress name labels {}))
([name labels spec]
{:apiVersion "networking.k8s.io/v1beta1"
:kind "Ingress"
:metadata {:name name :labels labels}
:spec spec}))
(defn add-to-spec
([container name value]
(-> container
(assoc name value))))
(defn add-readiness-probe-get
([container url port]
(add-readiness-probe-get container url port 60 60))
([container url port delay period]
(-> container
(assoc :readinessProbe
{:periodSeconds period
:initialDelaySeconds delay
:failureThreshold 5
:httpGet {:path url :port port}}))))
(defn add-readiness-probe-cmd
([container command]
(add-readiness-probe-cmd container command 60 60))
([container command delay period]
(-> container
(assoc :readinessProbe
{:periodSeconds period
:initialDelaySeconds delay
:failureThreshold 5
:exec {:command command}}))))
(defn add-liveness-probe-get
([container url port]
(add-liveness-probe-get container url port 60 60))
([container url port delay period]
(-> container
(assoc :livenessProbe
{:periodSeconds period
:initialDelaySeconds delay
:failureThreshold 5
:httpGet {:path url :port port}}))))
(defn add-liveness-probe-cmd
([container command]
(add-liveness-probe-cmd container command 60 60))
([container command delay period]
(-> container
(assoc :livenessProbe
{:periodSeconds delay
:initialDelaySeconds period
:failureThreshold 5
:exec {:command command}}))))
(defn add-tls [obj key val]
(-> obj
(update-in [:spec :tls] assoc key val)))
(defn add-rules [obj key val]
(-> obj
(update-in [:spec :rules] assoc key val)))
;; livenessProbe:
;; exec:
;; command:
;; - cat
;; - /tmp/healthy
;; initialDelaySeconds: 5
;; periodSeconds: 5
;; (defn add-spec [obj key val]
;; (-> obj
;; (update-in [:spec] assoc key val)))
(defn add-spec [obj key val]
(-> obj
(update-in [:spec] assoc key val)))
(defn encode-secret [value]
(b64/encode (.getBytes value)))
(defn encode-secret-map [data]
(reduce-kv
(fn [m k v] (assoc m k (encode-secret v)))
{}
data))
(defn to-yaml-store [$ filename]
(let [y (lk/to-yaml $)]
(spit filename y) y))
(defn to-yaml [$]
(let [y (lk/to-yaml $)]
(spit "test.yaml" y)
y))
;; (defn add-init-container
;; ([pod name image options]
;; (let [container (-> options
;; (merge {:name name
;; :image image}))]
;; (update pod :spec field-conj :initContainers container)))
;; ([pod name image]
;; (add-init-container pod name image {})))
;; (defn update-container [pod cont-name f & args]
;; (let [update-cont (fn [cont]
;; (if (= (:name cont) cont-name)
;; (apply f cont args)
;; ;; else
;; cont))]
;; (-> pod
;; (update-in [:spec :containers] #(map update-cont %))
;; (update-in [:spec :initContainers] #(map update-cont %))
;; (update :spec #(if (empty? (:initContainers %))
;; (dissoc % :initContainers)
;; ;; else
;; %)))))
;; (defn wait-for-service-port
;; ([pod dep portname]
;; (let [{:keys [hostname ports]} dep
;; cont (keyword (str "wait-for-" (name hostname) "-" (name portname)))]
;; (-> pod
;; (lk/add-init-container cont "busybox"
;; {:command ["sh"
;; "-c"
;; (str "while ! nc -z " hostname " " (ports portname) "; do sleep 1; done")]}))))
;; ([pod dep]
;; (when-not (= (-> dep :ports count) 1)
;; (throw (Exception. "Port name must be specified when waiting for a service exposing more than one port.")))
;; (let [portname (-> dep :ports first first)]
;; (wait-for-service-port pod dep portname))))

View File

@ -0,0 +1,103 @@
(ns kube-deploy.core-test
(require [clojure.test :refer :all]
[kube-deploy.core :as lke]
[lambdakube.core :as lk]
[lambdakube.util :as lku]
[lambdakube.testing :as lkt]))
(defn test-module [$]
(-> $
;; Tests that the master-slave configuration works. We set a
;; value in the master, and then read it from the slave,
;; expecting it to be the same.
(lkt/test :redis-slave-configured
{:num-be-slaves 1}
[:backend-master :backend-slave]
(fn [master slave]
(-> (lk/pod :test {})
;; Wait for both the master and slave to be up
(lku/wait-for-service-port master :redis)
(lku/wait-for-service-port slave :redis)
;; We use midje for the tests
(lku/add-midje-container
:test
'[[org.clojure/clojure "1.8.0"]
;; Carmine is a Redis client library for Clojure
[com.taoensso/carmine "2.18.1"]]
;; We pass the connection details for the Redis
;; master and slave, as provided by our
;; dependencies as constants to the test.
{:master-conn {:pool {} :spec {:host (:hostname master)
:port (-> master :ports :redis)}}
:slave-conn {:pool {} :spec {:host (:hostname slave)
:port (-> slave :ports :redis)}}}
'[(ns main-test
(:require [midje.sweet :refer :all]
[taoensso.carmine :as car]))
(fact
;; Set the value in the master.
(car/wcar master-conn
(car/with-replies
(car/set "foo" "bar")) => "OK")
;; Wait for value to propagate to slave
(Thread/sleep 1000)
;; Get the value from the slave.
(car/wcar slave-conn
(car/with-replies
(car/get "foo")) => "bar"))]))))
;; This tests the PHP code in the frontent. It sets value to a
;; key and then queries it.
(lkt/test :frontend-set-and-get
{:num-be-slaves 1
:num-fe-replicas 1}
[:frontend]
(fn [frontend]
(-> (lk/pod :test {})
;; We wait for the frontend to come up
(lku/wait-for-service-port frontend :web)
(lku/add-midje-container
:test
'[[org.clojure/clojure "1.8.0"]
;; We use clj-http to query the PHP page.
[clj-http "3.9.1"]]
;; We pass the `base-url` to the PHP page as a
;; constant. Values are based on the `frontend`
;; dependency.
{:base-url (str "http://"
(:hostname frontend)
":"
(-> frontend :ports :web)
"/guestbook.php")}
'[(ns main-test
(:require [midje.sweet :refer :all]
[clj-http.client :as client]
[clojure.string :as str]))
;; A function that makes a query to the PHP
;; page, by constructing a URL and making a
;; GET request.
(defn wget [query]
(let [resp (client/get (str base-url "?" (str/join "&" (for [[k v] query]
(str k "=" v)))))]
(when-not (= (:status resp) 200)
(throw (Exception. (str "Bad status" (:status resp) ": " (:body resp)))))
(:body resp)))
;; Set a value.
(fact
(wget {"cmd" "set"
"key" "foo"
"value" "bar"}) => "{\"message\": \"Updated\"}")
;; Query that value.
(fact
(wget {"cmd" "get"
"key" "foo"}) => "{\"data\": \"bar\"}")]))))))
(deftest kubetests
(is (= (-> (lk/injector)
(lke/module)
(lk/standard-descs)
(test-module)
(lkt/kube-tests "lk-ex")) "")))