From 821397b7b503cd14982821f46b54a7b84f4080c1 Mon Sep 17 00:00:00 2001 From: Nick Vrvilo Date: Wed, 5 Jun 2019 07:47:15 -0500 Subject: [PATCH 1/4] Move service-id->k8s-app-name docstring --- waiter/src/waiter/scheduler/kubernetes.clj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/waiter/src/waiter/scheduler/kubernetes.clj b/waiter/src/waiter/scheduler/kubernetes.clj index bee501e71..89d785d54 100644 --- a/waiter/src/waiter/scheduler/kubernetes.clj +++ b/waiter/src/waiter/scheduler/kubernetes.clj @@ -67,7 +67,7 @@ ;; If we have fewer than 48 characters, then we'll probably want to shorten the hash. (< k8s-max-name-length 48)) -(defn service-id->k8s-app-name [{:keys [max-name-length pod-suffix-length] :as scheduler} service-id] +(defn service-id->k8s-app-name "Shorten a full Waiter service-id to a Kubernetes-compatible application name. May return the service-id unmodified if it doesn't violate the configured name-length restrictions for this Kubernetes cluster. @@ -78,6 +78,7 @@ {:max-name-length 32} \"waiter-myapp-e8b625cc83c411e8974c38d5474b213d\") ==> \"myapp-e8b625cc474b213d\"" + [{:keys [max-name-length pod-suffix-length] :as scheduler} service-id] (let [[_ app-prefix x y z] (re-find #"([^-]+)-(\w{8})(\w+)(\w{8})$" service-id) k8s-max-name-length (- max-name-length pod-suffix-length 1) suffix (if (use-short-service-hash? k8s-max-name-length) From d3f5bcc6d60b66619bd16d9c912e470fd7d2b9a6 Mon Sep 17 00:00:00 2001 From: Nick Vrvilo Date: Wed, 5 Jun 2019 07:49:50 -0500 Subject: [PATCH 2/4] Add waiter/cluster Kubernetes label Replaces waiter-cluster label. See #721. --- waiter/src/waiter/scheduler/kubernetes.clj | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/waiter/src/waiter/scheduler/kubernetes.clj b/waiter/src/waiter/scheduler/kubernetes.clj index 89d785d54..0d0bf7d2f 100644 --- a/waiter/src/waiter/scheduler/kubernetes.clj +++ b/waiter/src/waiter/scheduler/kubernetes.clj @@ -735,7 +735,11 @@ :apiVersion replicaset-api-version :metadata {:annotations {:waiter/service-id service-id} :labels {:app k8s-name + ;; TODO - remove waiter-cluster + ;; after waiter/cluster is exclusively in use + ;; (see GitHub issue #721) :waiter-cluster cluster-name + :waiter/cluster cluster-name :waiter/user run-as-user} :name k8s-name :namespace (or namespace default-namespace)} @@ -747,6 +751,7 @@ :waiter/service-id service-id} :labels {:app k8s-name :waiter-cluster cluster-name + :waiter/cluster cluster-name :waiter/user run-as-user}} :spec {;; Service account tokens allow easy access to the k8s api server, ;; but this is only enabled when the x-waiter-namespace is set explicitly From 1df92cbe73592de7e16427023d763005a203b14d Mon Sep 17 00:00:00 2001 From: Nick Vrvilo Date: Wed, 5 Jun 2019 07:50:40 -0500 Subject: [PATCH 3/4] Add waiter/service-hash Kubernetes label --- waiter/src/waiter/scheduler/kubernetes.clj | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/waiter/src/waiter/scheduler/kubernetes.clj b/waiter/src/waiter/scheduler/kubernetes.clj index 0d0bf7d2f..5cfd39cd5 100644 --- a/waiter/src/waiter/scheduler/kubernetes.clj +++ b/waiter/src/waiter/scheduler/kubernetes.clj @@ -90,6 +90,11 @@ (subs 0 prefix-max-length))] (str app-prefix' suffix))) +(defn service-id->service-hash + "Extract the 32-char (256-bit) hash string from a Waiter service-id" + [service-id] + (subs service-id (- (count service-id) 32))) + (defn replicaset->Service "Convert a Kubernetes ReplicaSet JSON response into a Waiter Service record." [replicaset-json] @@ -729,17 +734,24 @@ k8s-name (service-id->k8s-app-name scheduler service-id) health-check-scheme (-> (or health-check-proto backend-proto) http-utils/backend-proto->scheme string/upper-case) health-check-url (sd/service-description->health-check-url service-description) - memory (str mem "Mi")] + memory (str mem "Mi") + service-hash (service-id->service-hash service-id)] (cond-> {:kind "ReplicaSet" :apiVersion replicaset-api-version - :metadata {:annotations {:waiter/service-id service-id} + :metadata {;; Since there are length restrictions on Kubernetes label values, + ;; we store just the 32-char hash portion of the service-id as a searchable label, + ;; but store the full service-id as an annotation. + ;; https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#syntax-and-character-set + ;; https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/#syntax-and-character-set + :annotations {:waiter/service-id service-id} :labels {:app k8s-name ;; TODO - remove waiter-cluster ;; after waiter/cluster is exclusively in use ;; (see GitHub issue #721) :waiter-cluster cluster-name :waiter/cluster cluster-name + :waiter/service-hash service-hash :waiter/user run-as-user} :name k8s-name :namespace (or namespace default-namespace)} @@ -752,6 +764,7 @@ :labels {:app k8s-name :waiter-cluster cluster-name :waiter/cluster cluster-name + :waiter/service-hash service-hash :waiter/user run-as-user}} :spec {;; Service account tokens allow easy access to the k8s api server, ;; but this is only enabled when the x-waiter-namespace is set explicitly From 4f153382a2835e9f37407514f2a703359a776588 Mon Sep 17 00:00:00 2001 From: Nick Vrvilo Date: Wed, 5 Jun 2019 08:30:59 -0500 Subject: [PATCH 4/4] Update unit tests for new k8s labels --- waiter/src/waiter/scheduler/kubernetes.clj | 8 +- .../test/waiter/scheduler/kubernetes_test.clj | 180 +++++++++++++----- 2 files changed, 137 insertions(+), 51 deletions(-) diff --git a/waiter/src/waiter/scheduler/kubernetes.clj b/waiter/src/waiter/scheduler/kubernetes.clj index 5cfd39cd5..3153d6dbd 100644 --- a/waiter/src/waiter/scheduler/kubernetes.clj +++ b/waiter/src/waiter/scheduler/kubernetes.clj @@ -91,9 +91,13 @@ (str app-prefix' suffix))) (defn service-id->service-hash - "Extract the 32-char (256-bit) hash string from a Waiter service-id" + "Extract the 32-char (256-bit) hash string from a Waiter service-id. + Returns the whole service-id if it's 32 characters or shorter." [service-id] - (subs service-id (- (count service-id) 32))) + (let [hash-offset (- (count service-id) 32)] + (cond-> service-id + (pos? hash-offset) + (subs hash-offset)))) (defn replicaset->Service "Convert a Kubernetes ReplicaSet JSON response into a Waiter Service record." diff --git a/waiter/test/waiter/scheduler/kubernetes_test.clj b/waiter/test/waiter/scheduler/kubernetes_test.clj index 1f9d39511..a3953f8f8 100644 --- a/waiter/test/waiter/scheduler/kubernetes_test.clj +++ b/waiter/test/waiter/scheduler/kubernetes_test.clj @@ -224,22 +224,28 @@ :items [{:metadata {:name "test-app-1234" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/service-id "test-app-1234"}} :spec {:replicas 2 :selector {:matchLabels {:app "test-app-1234" - :waiter-cluster "waiter"}}} + :waiter-cluster "waiter" + :waiter/cluster "waiter"}}} :status {:replicas 2 :readyReplicas 2 :availableReplicas 2}} {:metadata {:name "test-app-6789" :namespace "myself" :labels {:app "test-app-6789" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-6789"} :annotations {:waiter/service-id "test-app-6789"}} :spec {:replicas 3 :selector {:matchLabels {:app "test-app-6789" - :waiter-cluster "waiter"}}} + :waiter-cluster "waiter" + :waiter/cluster "waiter"}}} :status {:replicas 3 :readyReplicas 1 :availableReplicas 2 @@ -257,11 +263,14 @@ :items [{:metadata {:name "test-app-abcd" :namespace "myself" :labels {:app "test-app-abcd" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-abcd"} :annotations {:waiter/service-id "test-app-abcd"}} :spec {:replicas 2 :selector {:matchLabels {:app "test-app-abcd" - :waiter-cluster "waiter"}}} + :waiter-cluster "waiter" + :waiter/cluster "waiter"}}} :status {:replicas 2 :readyReplicas 2 :availableReplicas 2}} @@ -269,11 +278,14 @@ {:metadata {:name "test-app-wxyz" :namespace "myself" :labels {:app "test-app-wxyz" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-wxyz"} :annotations {:waiter/service-id "test-app-wxyz"}} :spec {:replicas 3 :selector {:matchLabels {:app "test-app-wxyz" - :waiter-cluster "waiter"}}} + :waiter-cluster "waiter" + :waiter/cluster "waiter"}}} :status {:replicas 3 :readyReplicas 1 :availableReplicas 2 @@ -292,11 +304,14 @@ :items [{:metadata {:name "test-app-4321" :namespace "myself" :labels {:app "test-app-4321" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-4321"} :annotations {:waiter/service-id "test-app-4321"}} :spec {:replicas 3 :selector {:matchLabels {:app "test-app-4321" - :waiter-cluster "waiter"}}} + :waiter-cluster "waiter" + :waiter/cluster "waiter"}}} :status {:replicas 3 :readyReplicas 1 :availableReplicas 1 @@ -311,11 +326,14 @@ :items [{:metadata {:name "test-app-9999" :namespace "myself" :labels {:app "test-app-9999" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-9999"} :annotations {:waiter/service-id "test-app-9999"}} :spec {:replicas 0 :selector {:matchLabels {:app "test-app-9999" - :waiter-cluster "waiter"}}} + :waiter-cluster "waiter" + :waiter/cluster "waiter"}}} :status {:replicas 0 :readyReplicas 0 :availableReplicas 0}}]} @@ -341,7 +359,9 @@ :namespace "myself" :labels {:app "test-app-1234" :waiter-cluster "waiter" - :waiter/user "myself"} + :waiter/cluster "waiter" + :waiter/user "myself" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/service-id "test-app-1234"}} :spec {:replicas 2} :status {:replicas 2 @@ -350,7 +370,9 @@ {:metadata {:name "test-app-6789" :namespace "myself" :labels {:app "test-app-6789" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-6789"} :annotations {:waiter/service-id "test-app-6789"}} :spec {:replicas 3} :status {:replicas 3 @@ -365,6 +387,8 @@ :namespace "myself" :labels {:app "test-app-1234" :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234" :waiter/user "myself"} :annotations {:waiter/port-count "1" :waiter/service-id "test-app-1234"}} @@ -378,7 +402,9 @@ :namespace "myself" :labels {:app "test-app-1234" :waiter-cluster "waiter" - :waiter/user "myself"} + :waiter/cluster "waiter" + :waiter/user "myself" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/port-count "1" :waiter/service-id "test-app-1234"}} :spec {:containers [{:ports [{:containerPort 8080 :protocol "TCP"}]}]} @@ -391,7 +417,9 @@ :namespace "myself" :labels {:app "test-app-6789" :waiter-cluster "waiter" - :waiter/user "myself"} + :waiter/cluster "waiter" + :waiter/user "myself" + :waiter/service-hash "test-app-6789"} :annotations {:waiter/port-count "1" :waiter/service-id "test-app-6789"}} :spec {:containers [{:ports [{:containerPort 8080 :protocol "TCP"}]}]} @@ -404,7 +432,9 @@ :namespace "myself" :labels {:app "test-app-6789" :waiter-cluster "waiter" - :waiter/user "myself"} + :waiter/cluster "waiter" + :waiter/user "myself" + :waiter/service-hash "test-app-6789"} :annotations {:waiter/port-count "1" :waiter/service-id "test-app-6789"}} :spec {:containers [{:ports [{:containerPort 8080 :protocol "TCP"}]}]} @@ -419,7 +449,9 @@ :namespace "myself" :labels {:app "test-app-6789" :waiter-cluster "waiter" - :waiter/user "myself"} + :waiter/cluster "waiter" + :waiter/user "myself" + :waiter/service-hash "test-app-6789"} :annotations {:waiter/port-count "1" :waiter/service-id "test-app-6789"}} :spec {:containers [{:ports [{:containerPort 8080 :protocol "TCP"}]}]} @@ -516,7 +548,9 @@ :items [{:metadata {:name service-id :namespace "myself" :labels {:app service-id - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash service-id} :annotations {:waiter/service-id service-id}} :spec {:replicas 1} :status {:replicas 1 @@ -574,11 +608,14 @@ :items [{:metadata {:name service-id :namespace "myself" :labels {:app service-id - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash service-id} :annotations {:waiter/service-id service-id}} :spec {:replicas 2 :selector {:matchLabels {:app service-id - :waiter-cluster "waiter"}}} + :waiter-cluster "waiter" + :waiter/cluster "waiter"}}} :status {:replicas 2 :readyReplicas 2 :availableReplicas 2}}]} @@ -884,7 +921,6 @@ (deftest test-start-k8s-watch! (let [service-id "test-app-1234" - rs-response {:kind "ReplicaSetList" :apiVersion "extensions/v1beta1" @@ -892,11 +928,14 @@ :items [{:metadata {:name "test-app-1234" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/service-id "test-app-1234"}} :spec {:replicas 2 :selector {:matchLabels {:app "test-app-1234" - :waiter-cluster "waiter"}}} + :waiter-cluster "waiter" + :waiter/cluster "waiter"}}} :status {:replicas 2 :readyReplicas 1 :availableReplicas 2}}]} @@ -906,12 +945,15 @@ :object {:metadata {:name "test-app-1234" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/service-id "test-app-1234"} :resourceVersion "1001"} :spec {:replicas 2 :selector {:matchLabels {:app "test-app-1234" - :waiter-cluster "waiter"}}} + :waiter-cluster "waiter" + :waiter/cluster "waiter"}}} :status {:replicas 2 :readyReplicas 2 :availableReplicas 2}}} @@ -919,12 +961,15 @@ :object {:metadata {:name "test-app-1234" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/service-id "test-app-1234"} :resourceVersion "1002"} :spec {:replicas 3 :selector {:matchLabels {:app "test-app-1234" - :waiter-cluster "waiter"}}} + :waiter-cluster "waiter" + :waiter/cluster "waiter"}}} :status {:replicas 3 :readyReplicas 2 :availableReplicas 3}}} @@ -932,12 +977,15 @@ :object {:metadata {:name "test-app-1234" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/service-id "test-app-1234"} :resourceVersion "1003"} :spec {:replicas 2 :selector {:matchLabels {:app "test-app-1234" - :waiter-cluster "waiter"}}} + :waiter-cluster "waiter" + :waiter/cluster "waiter"}}} :status {:replicas 2 :readyReplicas 1 :availableReplicas 2}}}] @@ -949,7 +997,9 @@ :items [{:metadata {:name "test-app-1234-abcd1" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/port-count "1" :waiter/service-id "test-app-1234"}} :spec {:containers [{:ports [{:containerPort 8080 :protocol "TCP"}]}]} @@ -961,7 +1011,9 @@ {:metadata {:name "test-app-1234-abcd2" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/port-count "1" :waiter/service-id "test-app-1234"}} :spec {:containers [{:ports [{:containerPort 8080 :protocol "TCP"}]}]} @@ -975,7 +1027,9 @@ :object {:metadata {:name "test-app-1234-abcd2" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/port-count "1" :waiter/service-id "test-app-1234"} :resourceVersion "1001"} @@ -989,7 +1043,9 @@ :object {:metadata {:name "test-app-1234-abcd3" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/port-count "1" :waiter/service-id "test-app-1234"} :resourceVersion "1002"} @@ -1123,11 +1179,14 @@ :items [{:metadata {:name "test-app-1234" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/service-id "test-app-1234"}} :spec {:replicas 2 :selector {:matchLabels {:app "test-app-1234" - :waiter-cluster "waiter"}}} + :waiter-cluster "waiter" + :waiter/cluster "waiter"}}} :status {:replicas 2 :readyReplicas 1 :availableReplicas 2}}]} @@ -1137,12 +1196,15 @@ :object {:metadata {:name "test-app-1234" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/service-id "test-app-1234"} :resourceVersion "1001"} :spec {:replicas 2 :selector {:matchLabels {:app "test-app-1234" - :waiter-cluster "waiter"}}} + :waiter-cluster "waiter" + :waiter/cluster "waiter"}}} :status {:replicas 2 :readyReplicas 2 :availableReplicas 2}}} @@ -1150,12 +1212,15 @@ :object {:metadata {:name "test-app-1234" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/service-id "test-app-1234"} :resourceVersion "1002"} :spec {:replicas 3 :selector {:matchLabels {:app "test-app-1234" - :waiter-cluster "waiter"}}} + :waiter-cluster "waiter" + :waiter/cluster "waiter"}}} :status {:replicas 3 :readyReplicas 2 :availableReplicas 3}}} @@ -1163,12 +1228,15 @@ :object {:metadata {:name "test-app-1234" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/service-id "test-app-1234"} :resourceVersion "1004"} :spec {:replicas 2 :selector {:matchLabels {:app "test-app-1234" - :waiter-cluster "waiter"}}} + :waiter-cluster "waiter" + :waiter/cluster "waiter"}}} :status {:replicas 2 :readyReplicas 1 :availableReplicas 2}}}] @@ -1180,7 +1248,9 @@ :items [{:metadata {:name "test-app-1234-abcd1" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/port-count "1" :waiter/service-id "test-app-1234"}} :spec {:containers [{:ports [{:containerPort 8080 :protocol "TCP"}]}]} @@ -1192,7 +1262,9 @@ {:metadata {:name "test-app-1234-abcd2" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/port-count "1" :waiter/service-id "test-app-1234"}} :spec {:containers [{:ports [{:containerPort 8080 :protocol "TCP"}]}]} @@ -1208,7 +1280,9 @@ :items [{:metadata {:name "test-app-1234-abcd1" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/port-count "1" :waiter/service-id "test-app-1234"}} :spec {:containers [{:ports [{:containerPort 8080 :protocol "TCP"}]}]} @@ -1220,7 +1294,9 @@ {:metadata {:name "test-app-1234-abcd2" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/port-count "1" :waiter/service-id "test-app-1234"}} :spec {:containers [{:ports [{:containerPort 8080 :protocol "TCP"}]}]} @@ -1232,7 +1308,9 @@ {:metadata {:name "test-app-1234-abcd3" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/port-count "1" :waiter/service-id "test-app-1234"} :resourceVersion "1002"} @@ -1247,7 +1325,9 @@ :object {:metadata {:name "test-app-1234-abcd2" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/port-count "1" :waiter/service-id "test-app-1234"} :resourceVersion "1001"} @@ -1261,7 +1341,9 @@ :object {:metadata {:name "test-app-1234-abcd3" :namespace "myself" :labels {:app "test-app-1234" - :waiter-cluster "waiter"} + :waiter-cluster "waiter" + :waiter/cluster "waiter" + :waiter/service-hash "test-app-1234"} :annotations {:waiter/port-count "1" :waiter/service-id "test-app-1234"} :resourceVersion "1002"}