|
16 | 16 | (def ^:private ^:const DEFAULT_HELM_CHART_VERSION "1.7.2") |
17 | 17 | (def ^:private ^:const DEFAULT_CHAOS_MESH_VERSION "2.7.2") |
18 | 18 |
|
| 19 | +(def ^:private ^:const DEFAULT_CLUSTER_NODE_COUNT 3) |
| 20 | +(def ^:private ^:const DEFAULT_CASSANDRA_REPLICA_COUNT 3) |
| 21 | + |
19 | 22 | (def ^:private ^:const TIMEOUT_SEC 600) |
20 | 23 | (def ^:private ^:const INTERVAL_SEC 10) |
21 | 24 |
|
22 | 25 | (def ^:private ^:const CLUSTER_NODE_NAME "scalardb-cluster-node") |
| 26 | +(def ^:private ^:const CASSANDRA_NODE_NAME "cassandra-scalardb-cluster") |
23 | 27 |
|
24 | 28 | (def ^:private ^:const CLUSTER_VALUES |
25 | 29 | {:envoy {:enabled true |
|
30 | 34 | :tag (or (some-> (env :scalardb-cluster-version) not-empty) |
31 | 35 | DEFAULT_SCALARDB_CLUSTER_VERSION)} |
32 | 36 |
|
| 37 | + ;; Storage configurations will be set later |
33 | 38 | :scalardbClusterNodeProperties |
34 | 39 | (str/join "\n" |
35 | 40 | ;; ScalarDB Cluster configurations |
36 | 41 | ["scalar.db.cluster.membership.type=KUBERNETES" |
37 | 42 | "scalar.db.cluster.membership.kubernetes.endpoint.namespace_name=${env:SCALAR_DB_CLUSTER_MEMBERSHIP_KUBERNETES_ENDPOINT_NAMESPACE_NAME}" |
38 | 43 | "scalar.db.cluster.membership.kubernetes.endpoint.name=${env:SCALAR_DB_CLUSTER_MEMBERSHIP_KUBERNETES_ENDPOINT_NAME}" |
39 | 44 | "" |
40 | | - ;; Storage configurations |
41 | | - "scalar.db.storage=jdbc" |
42 | | - "scalar.db.contact_points=jdbc:postgresql://postgresql-scalardb-cluster.default.svc.cluster.local:5432/postgres" |
43 | | - "scalar.db.username=postgres" |
44 | | - "scalar.db.password=postgres" |
45 | | - "" |
46 | 45 | ;; Set to true to include transaction metadata in the records |
47 | 46 | "scalar.db.consensus_commit.include_metadata.enabled=true"]) |
48 | 47 |
|
|
51 | 50 | (defn- update-cluster-values |
52 | 51 | [test values] |
53 | 52 | (let [path [:scalardbCluster :scalardbClusterNodeProperties] |
| 53 | + [storage contact-points user-pass] |
| 54 | + (case (:db-type test) |
| 55 | + :cluster ["jdbc" |
| 56 | + "jdbc:postgresql://postgresql-scalardb-cluster.default.svc.cluster.local:5432/postgres" |
| 57 | + "postgres"] |
| 58 | + :cluster-cassandra ["cassandra" |
| 59 | + (->> (map #(str "cassandra-scalardb-cluster-" |
| 60 | + % |
| 61 | + ".cassandra-scalardb-cluster-headless.default.svc.cluster.local") |
| 62 | + (range DEFAULT_CASSANDRA_REPLICA_COUNT)) |
| 63 | + (str/join ",")) |
| 64 | + "cassandra"] |
| 65 | + (throw (ex-info "Unsupported DB type" {:db-type (:db-type test)}))) |
| 66 | + isolation-level (-> test |
| 67 | + :isolation-level |
| 68 | + name |
| 69 | + str/upper-case |
| 70 | + (str/replace #"-" "_")) |
54 | 71 | new-db-props (-> values |
55 | 72 | (get-in path) |
56 | 73 | (str |
| 74 | + ;; storage |
| 75 | + "\nscalar.db.storage=" |
| 76 | + storage |
| 77 | + "\nscalar.db.contact_points=" |
| 78 | + contact-points |
| 79 | + "\nscalar.db.username=" |
| 80 | + user-pass |
| 81 | + "\nscalar.db.password=" |
| 82 | + user-pass |
57 | 83 | ;; isolation level |
58 | 84 | "\nscalar.db.consensus_commit.isolation_level=" |
59 | | - (-> test |
60 | | - :isolation-level |
61 | | - name |
62 | | - str/upper-case |
63 | | - (str/replace #"-" "_")) |
| 85 | + isolation-level |
64 | 86 | ;; one phase commit |
65 | 87 | (when (:enable-one-phase-commit test) |
66 | 88 | "\nscalar.db.consensus_commit.one_phase_commit.enabled=true") |
|
109 | 131 |
|
110 | 132 | (defn- start! |
111 | 133 | [test] |
112 | | - ;; postgre |
113 | | - (c/exec |
114 | | - :helm :install "postgresql-scalardb-cluster" "bitnami/postgresql" |
115 | | - :--set "auth.postgresPassword=postgres" |
116 | | - :--set "primary.persistence.enabled=true" |
117 | | - ;; Need an external IP for storage APIs |
118 | | - :--set "service.type=LoadBalancer" |
119 | | - :--set "primary.service.type=LoadBalancer") |
| 134 | + ;; postgre or cassandra |
| 135 | + (case (:db-type test) |
| 136 | + :cluster (c/exec |
| 137 | + :helm :install "postgresql-scalardb-cluster" "bitnami/postgresql" |
| 138 | + :--set "auth.postgresPassword=postgres" |
| 139 | + :--set "primary.persistence.enabled=true" |
| 140 | + ;; Need an external IP for storage APIs |
| 141 | + :--set "service.type=LoadBalancer" |
| 142 | + :--set "primary.service.type=LoadBalancer") |
| 143 | + :cluster-cassandra (c/exec |
| 144 | + :helm :install "cassandra-scalardb-cluster" "bitnami/cassandra" |
| 145 | + :--set "dbUser.user=cassandra" |
| 146 | + :--set "dbUser.user=cassandra" |
| 147 | + :--set "dbUser.password=cassandra" |
| 148 | + :--set (str "replicaCount=" DEFAULT_CASSANDRA_REPLICA_COUNT) |
| 149 | + ;; Need an external IP for storage APIs |
| 150 | + :--set "service.type=LoadBalancer" |
| 151 | + :--set "primary.service.type=LoadBalancer") |
| 152 | + (throw (ex-info "Unsupported DB type" {:db-type (:db-type test)}))) |
120 | 153 |
|
121 | 154 | ;; ScalarDB Cluster |
122 | 155 | (let [chart-version (or (some-> (env :helm-chart-version) not-empty) |
|
139 | 172 | :--version DEFAULT_CHAOS_MESH_VERSION)) |
140 | 173 |
|
141 | 174 | (defn- wipe! |
142 | | - [] |
| 175 | + [test] |
| 176 | + ;; ignore errors because these files or pods might not exist |
143 | 177 | (try |
144 | 178 | (info "wiping old logs...") |
145 | 179 | (binding [c/*dir* (System/getProperty "user.dir")] |
146 | 180 | (some->> (-> (c/exec :ls) (str/split #"\s+")) |
147 | 181 | (filter #(re-matches #"scalardb-cluster-node-.*\.log" %)) |
148 | 182 | seq |
149 | 183 | (apply c/exec :rm :-f))) |
150 | | - (info "wiping the pods...") |
151 | | - (c/exec :helm :uninstall :postgresql-scalardb-cluster) |
| 184 | + (catch Exception _)) |
| 185 | + (info "wiping the pods...") |
| 186 | + (try |
| 187 | + (c/exec :helm :uninstall |
| 188 | + (case (:db-type test) |
| 189 | + :cluster :postgresql-scalardb-cluster |
| 190 | + :cluster-cassandra :cassandra-scalardb-cluster)) |
| 191 | + (catch Exception _)) |
| 192 | + (try |
152 | 193 | (c/exec :kubectl :delete |
153 | 194 | :pvc :-l "app.kubernetes.io/instance=postgresql-scalardb-cluster") |
| 195 | + (catch Exception _)) |
| 196 | + (try |
154 | 197 | (c/exec :helm :uninstall :scalardb-cluster) |
| 198 | + (catch Exception _)) |
| 199 | + (try |
155 | 200 | (c/exec :helm :uninstall :chaos-mesh :-n "chaos-mesh") |
156 | | - (catch Exception _ nil))) |
| 201 | + (catch Exception _))) |
157 | 202 |
|
158 | 203 | (defn- get-pod-list |
159 | 204 | [name] |
|
182 | 227 | first)) |
183 | 228 |
|
184 | 229 | (defn get-postgres-ip |
185 | | - "Get the IP of the load balancer" |
| 230 | + "Get the IP of the Postgres" |
186 | 231 | [] |
187 | 232 | (->> (c/exec :kubectl :get :svc) |
188 | 233 | str/split-lines |
|
191 | 236 | (map #(nth (str/split % #"\s+") 3)) |
192 | 237 | first)) |
193 | 238 |
|
| 239 | +(defn get-cassandra-ip |
| 240 | + "Get one IP of the Cassandra nodes" |
| 241 | + [] |
| 242 | + (->> (c/exec :kubectl :get :svc) |
| 243 | + str/split-lines |
| 244 | + (filter #(str/includes? % "cassandra-scalardb-cluster")) |
| 245 | + (filter #(str/includes? % "LoadBalancer")) |
| 246 | + (map #(nth (str/split % #"\s+") 3)) |
| 247 | + first)) |
| 248 | + |
194 | 249 | (defn- running-pods? |
195 | | - "Check a live node." |
196 | | - [test] |
| 250 | + "Check if nodes are running." |
| 251 | + [test prefix num] |
197 | 252 | (-> test |
198 | 253 | :nodes |
199 | 254 | first |
200 | | - (c/on (get-pod-list CLUSTER_NODE_NAME)) |
| 255 | + (c/on (get-pod-list prefix)) |
201 | 256 | count |
202 | | - ;; TODO: check the number of pods |
203 | | - (= 3))) |
| 257 | + (= num))) |
204 | 258 |
|
205 | 259 | (defn- cluster-nodes-ready? |
206 | 260 | [test] |
207 | | - (and (running-pods? test) |
| 261 | + (and (running-pods? test CLUSTER_NODE_NAME DEFAULT_CLUSTER_NODE_COUNT) |
208 | 262 | (try |
209 | 263 | (c/on (-> test :nodes first) |
210 | 264 | (->> (get-pod-list CLUSTER_NODE_NAME) |
|
217 | 271 | (warn (.getMessage e)) |
218 | 272 | false)))) |
219 | 273 |
|
| 274 | +(defn- cassandra-nodes-ready? |
| 275 | + [test] |
| 276 | + (or (not= (:db-type test) :cluster-cassandra) |
| 277 | + (and (running-pods? test |
| 278 | + CASSANDRA_NODE_NAME |
| 279 | + DEFAULT_CASSANDRA_REPLICA_COUNT) |
| 280 | + (try |
| 281 | + (c/on (-> test :nodes first) |
| 282 | + (->> (get-pod-list CASSANDRA_NODE_NAME) |
| 283 | + (mapv #(c/exec :kubectl :wait |
| 284 | + "--for=condition=Ready" |
| 285 | + "--timeout=120s" |
| 286 | + (str "pod/" %))))) |
| 287 | + true |
| 288 | + (catch Exception e |
| 289 | + (warn (.getMessage e)) |
| 290 | + false))))) |
| 291 | + |
220 | 292 | (defn- wait-for-recovery |
221 | 293 | "Wait for the node bootstrapping." |
222 | 294 | ([test] |
223 | 295 | (wait-for-recovery TIMEOUT_SEC INTERVAL_SEC test)) |
224 | 296 | ([timeout-sec interval-sec test] |
225 | | - (when-not (cluster-nodes-ready? test) |
| 297 | + (when-not (and (cassandra-nodes-ready? test) (cluster-nodes-ready? test)) |
226 | 298 | (Thread/sleep (* interval-sec 1000)) |
227 | 299 | (if (>= timeout-sec interval-sec) |
228 | 300 | (wait-for-recovery (- timeout-sec interval-sec) interval-sec test) |
|
236 | 308 | db/DB |
237 | 309 | (setup! [_ test _] |
238 | 310 | (when-not (:leave-db-running? test) |
239 | | - (wipe!)) |
| 311 | + (wipe! test)) |
240 | 312 | (install!) |
241 | 313 | (configure! test) |
242 | 314 | (start! test) |
|
245 | 317 |
|
246 | 318 | (teardown! [_ test _] |
247 | 319 | (when-not (:leave-db-running? test) |
248 | | - (wipe!))) |
| 320 | + (wipe! test))) |
249 | 321 |
|
250 | 322 | db/Primary |
251 | 323 | (primaries [_ test] (:nodes test)) |
|
270 | 342 | (defrecord ExtCluster [] |
271 | 343 | ext/DbExtension |
272 | 344 | (get-db-type [_] :cluster) |
273 | | - (live-nodes [_ test] (running-pods? test)) |
| 345 | + (live-nodes [_ test] (running-pods? test |
| 346 | + CLUSTER_NODE_NAME |
| 347 | + DEFAULT_CLUSTER_NODE_COUNT)) |
274 | 348 | (wait-for-recovery [_ test] (wait-for-recovery test)) |
275 | 349 | (create-table-opts [_ _] {}) |
276 | 350 | (create-properties |
|
288 | 362 | (ext/set-common-properties test))))) |
289 | 363 | (create-storage-properties [_ _] |
290 | 364 | (let [node (-> test :nodes first) |
291 | | - ip (c/on node (get-postgres-ip))] |
| 365 | + db-type (:db-type test) |
| 366 | + [storage contact-points user-pass] |
| 367 | + (c/on node (case db-type |
| 368 | + :cluster ["jdbc" |
| 369 | + (str "jdbc:postgresql://" |
| 370 | + (get-postgres-ip) |
| 371 | + ":5432/postgres") |
| 372 | + "postgres"] |
| 373 | + :cluster-cassandra ["cassandra" |
| 374 | + (get-cassandra-ip) |
| 375 | + "cassandra"] |
| 376 | + (throw (ex-info "Unsupported DB type" {:db-type db-type}))))] |
292 | 377 | (doto (Properties.) |
293 | | - (.setProperty "scalar.db.storage" "jdbc") |
294 | | - (.setProperty "scalar.db.contact_points" |
295 | | - (str "jdbc:postgresql://" ip ":5432/postgres")) |
296 | | - (.setProperty "scalar.db.username" "postgres") |
297 | | - (.setProperty "scalar.db.password" "postgres"))))) |
| 378 | + (.setProperty "scalar.db.storage" storage) |
| 379 | + (.setProperty "scalar.db.contact_points" contact-points) |
| 380 | + (.setProperty "scalar.db.username" user-pass) |
| 381 | + (.setProperty "scalar.db.password" user-pass))))) |
298 | 382 |
|
299 | 383 | (defn gen-db |
300 | 384 | [faults admin] |
|
0 commit comments