blob: b932b042843df2366853966ab54876f7806a59df [file] [log] [blame]
Dmitry Puzikovd0101df2019-04-25 14:33:48 +02001#!/usr/bin/env python
BorislavG06518262018-02-14 17:40:49 +02002import getopt
3import logging
4import os
5import sys
6import time
Dmitry Puzikov0c588d52019-04-25 14:53:03 +02007import random
Mandeep Khindad6ea9872017-06-24 11:49:37 -04008
BorislavG06518262018-02-14 17:40:49 +02009from kubernetes import client
10
11# extract env variables.
Mandeep Khindad6ea9872017-06-24 11:49:37 -040012namespace = os.environ['NAMESPACE']
13cert = os.environ['CERT']
14host = os.environ['KUBERNETES_SERVICE_HOST']
15token_path = os.environ['TOKEN']
16
17with open(token_path, 'r') as token_file:
18 token = token_file.read().replace('\n', '')
19
BorislavG06518262018-02-14 17:40:49 +020020# setup logging
Mandeep Khindad6ea9872017-06-24 11:49:37 -040021log = logging.getLogger(__name__)
22handler = logging.StreamHandler(sys.stdout)
k.kedron19664b32019-05-14 16:13:00 +020023formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
24handler.setFormatter(formatter)
Mandeep Khindad6ea9872017-06-24 11:49:37 -040025handler.setLevel(logging.INFO)
26log.addHandler(handler)
27log.setLevel(logging.INFO)
28
BorislavG06518262018-02-14 17:40:49 +020029configuration = client.Configuration()
30configuration.host = "https://" + host
31configuration.ssl_ca_cert = cert
32configuration.api_key['authorization'] = token
33configuration.api_key_prefix['authorization'] = 'Bearer'
34coreV1Api = client.CoreV1Api(client.ApiClient(configuration))
k.kedron19664b32019-05-14 16:13:00 +020035api_instance = client.ExtensionsV1beta1Api(client.ApiClient(configuration))
Mahendra Raghuwanshi6a8304c2019-01-28 09:49:30 +000036api = client.AppsV1beta1Api(client.ApiClient(configuration))
37batchV1Api = client.BatchV1Api(client.ApiClient(configuration))
38
k.kedron19664b32019-05-14 16:13:00 +020039
Mahendra Raghuwanshi6a8304c2019-01-28 09:49:30 +000040def is_job_complete(job_name):
41 complete = False
42 log.info("Checking if " + job_name + " is complete")
Mahendra Raghuwanshi6a8304c2019-01-28 09:49:30 +000043 try:
44 response = batchV1Api.read_namespaced_job_status(job_name, namespace)
45 if response.status.succeeded == 1:
46 job_status_type = response.status.conditions[0].type
47 if job_status_type == "Complete":
48 complete = True
49 log.info(job_name + " is complete")
50 else:
51 log.info(job_name + " is not complete")
52 else:
53 log.info(job_name + " has not succeeded yet")
54 return complete
55 except Exception as e:
56 log.error("Exception when calling read_namespaced_job_status: %s\n" % e)
57
k.kedron19664b32019-05-14 16:13:00 +020058
Mahendra Raghuwanshi6a8304c2019-01-28 09:49:30 +000059def wait_for_statefulset_complete(statefulset_name):
60 try:
61 response = api.read_namespaced_stateful_set(statefulset_name, namespace)
62 s = response.status
Sebastien Premont-Tendlandc1e95ee2020-05-26 18:32:33 -040063 if (s.replicas == response.spec.replicas and
Mahendra Raghuwanshi6a8304c2019-01-28 09:49:30 +000064 s.ready_replicas == response.spec.replicas and
Mahendra Raghuwanshi6a8304c2019-01-28 09:49:30 +000065 s.observed_generation == response.metadata.generation):
66 log.info("Statefulset " + statefulset_name + " is ready")
67 return True
68 else:
69 log.info("Statefulset " + statefulset_name + " is not ready")
70 return False
71 except Exception as e:
72 log.error("Exception when waiting for Statefulset status: %s\n" % e)
73
k.kedron19664b32019-05-14 16:13:00 +020074
Mahendra Raghuwanshi6a8304c2019-01-28 09:49:30 +000075def wait_for_deployment_complete(deployment_name):
76 try:
77 response = api.read_namespaced_deployment(deployment_name, namespace)
78 s = response.status
k.kedron19664b32019-05-14 16:13:00 +020079 if (s.unavailable_replicas is None and
Akansha Duab77da7a2019-10-03 17:15:21 +053080 ( s.updated_replicas is None or s.updated_replicas == response.spec.replicas ) and
Mahendra Raghuwanshi6a8304c2019-01-28 09:49:30 +000081 s.replicas == response.spec.replicas and
82 s.ready_replicas == response.spec.replicas and
83 s.observed_generation == response.metadata.generation):
84 log.info("Deployment " + deployment_name + " is ready")
85 return True
86 else:
87 log.info("Deployment " + deployment_name + " is not ready")
88 return False
89 except Exception as e:
90 log.error("Exception when waiting for deployment status: %s\n" % e)
Mandeep Khindad6ea9872017-06-24 11:49:37 -040091
k.kedron19664b32019-05-14 16:13:00 +020092
dfx19715d3e3922020-01-16 09:55:27 +020093def wait_for_daemonset_complete(daemonset_name):
94 try:
95 response = api_instance.read_namespaced_daemon_set(daemonset_name, namespace)
96 s = response.status
97 if s.desired_number_scheduled == s.number_ready:
98 log.info("DaemonSet: " + str(s.number_ready) + "/" + str(s.desired_number_scheduled) + " nodes ready --> " + daemonset_name + " is ready")
99 return True
100 else:
101 log.info("DaemonSet: " + str(s.number_ready) + "/" + str(s.desired_number_scheduled) + " nodes ready --> " + daemonset_name + " is not ready")
102 return False
103 except Exception as e:
104 log.error("Exception when waiting for DaemonSet status: %s\n" % e)
105
106
Mandeep Khindad6ea9872017-06-24 11:49:37 -0400107def is_ready(container_name):
Mandeep Khindad6ea9872017-06-24 11:49:37 -0400108 ready = False
BorislavG06518262018-02-14 17:40:49 +0200109 log.info("Checking if " + container_name + " is ready")
Mandeep Khindad6ea9872017-06-24 11:49:37 -0400110 try:
k.kedron19664b32019-05-14 16:13:00 +0200111 response = coreV1Api.list_namespaced_pod(namespace=namespace,
112 watch=False)
Mandeep Khindad6ea9872017-06-24 11:49:37 -0400113 for i in response.items:
BorislavG07dc7db2018-02-14 15:23:51 +0200114 # container_statuses can be None, which is non-iterable.
115 if i.status.container_statuses is None:
BorislavG06518262018-02-14 17:40:49 +0200116 continue
Mandeep Khindad6ea9872017-06-24 11:49:37 -0400117 for s in i.status.container_statuses:
Mahendra Raghuwanshi6a8304c2019-01-28 09:49:30 +0000118 if s.name == container_name:
k.kedron19664b32019-05-14 16:13:00 +0200119 name = read_name(i)
120 if i.metadata.owner_references[0].kind == "StatefulSet":
121 ready = wait_for_statefulset_complete(name)
Mahendra Raghuwanshi6a8304c2019-01-28 09:49:30 +0000122 elif i.metadata.owner_references[0].kind == "ReplicaSet":
k.kedron19664b32019-05-14 16:13:00 +0200123 deployment_name = get_deployment_name(name)
124 ready = wait_for_deployment_complete(deployment_name)
Mahendra Raghuwanshi6a8304c2019-01-28 09:49:30 +0000125 elif i.metadata.owner_references[0].kind == "Job":
k.kedron19664b32019-05-14 16:13:00 +0200126 ready = is_job_complete(name)
dfx19715d3e3922020-01-16 09:55:27 +0200127 elif i.metadata.owner_references[0].kind == "DaemonSet":
128 ready = wait_for_daemonset_complete(i.metadata.owner_references[0].name)
Mahendra Raghuwanshi6a8304c2019-01-28 09:49:30 +0000129
130 return ready
131
Mandeep Khindad6ea9872017-06-24 11:49:37 -0400132 else:
133 continue
134 return ready
135 except Exception as e:
136 log.error("Exception when calling list_namespaced_pod: %s\n" % e)
137
k.kedron19664b32019-05-14 16:13:00 +0200138
139def read_name(item):
dfx19715d3e3922020-01-16 09:55:27 +0200140 return item.metadata.owner_references[0].name
k.kedron19664b32019-05-14 16:13:00 +0200141
142
143def get_deployment_name(replicaset):
144 api_response = api_instance.read_namespaced_replica_set_status(replicaset,
145 namespace)
146 deployment_name = read_name(api_response)
147 return deployment_name
148
149
BorislavG06518262018-02-14 17:40:49 +0200150DEF_TIMEOUT = 10
151DESCRIPTION = "Kubernetes container readiness check utility"
k.kedron19664b32019-05-14 16:13:00 +0200152USAGE = "Usage: ready.py [-t <timeout>] -c <container_name> " \
153 "[-c <container_name> ...]\n" \
BorislavG06518262018-02-14 17:40:49 +0200154 "where\n" \
k.kedron19664b32019-05-14 16:13:00 +0200155 "<timeout> - wait for container readiness timeout in min, " \
156 "default is " + str(DEF_TIMEOUT) + "\n" \
BorislavG06518262018-02-14 17:40:49 +0200157 "<container_name> - name of the container to wait for\n"
158
k.kedron19664b32019-05-14 16:13:00 +0200159
BorislavG06518262018-02-14 17:40:49 +0200160def main(argv):
Mandeep Khindad6ea9872017-06-24 11:49:37 -0400161 # args are a list of container names
BorislavG06518262018-02-14 17:40:49 +0200162 container_names = []
163 timeout = DEF_TIMEOUT
164 try:
k.kedron19664b32019-05-14 16:13:00 +0200165 opts, args = getopt.getopt(argv, "hc:t:", ["container-name=",
166 "timeout=",
167 "help"])
BorislavG06518262018-02-14 17:40:49 +0200168 for opt, arg in opts:
169 if opt in ("-h", "--help"):
170 print("%s\n\n%s" % (DESCRIPTION, USAGE))
171 sys.exit()
172 elif opt in ("-c", "--container-name"):
173 container_names.append(arg)
174 elif opt in ("-t", "--timeout"):
175 timeout = float(arg)
176 except (getopt.GetoptError, ValueError) as e:
177 print("Error parsing input parameters: %s\n" % e)
178 print(USAGE)
179 sys.exit(2)
180 if container_names.__len__() == 0:
181 print("Missing required input parameter(s)\n")
182 print(USAGE)
183 sys.exit(2)
184
185 for container_name in container_names:
186 timeout = time.time() + timeout * 60
Mandeep Khindad6ea9872017-06-24 11:49:37 -0400187 while True:
188 ready = is_ready(container_name)
189 if ready is True:
190 break
191 elif time.time() > timeout:
k.kedron19664b32019-05-14 16:13:00 +0200192 log.warning("timed out waiting for '" + container_name +
193 "' to be ready")
Mandeep Khindad6ea9872017-06-24 11:49:37 -0400194 exit(1)
195 else:
k.kedron19664b32019-05-14 16:13:00 +0200196 # spread in time potentially parallel execution in multiple
197 # containers
Dmitry Puzikov0c588d52019-04-25 14:53:03 +0200198 time.sleep(random.randint(5, 11))
Mandeep Khindad6ea9872017-06-24 11:49:37 -0400199
k.kedron19664b32019-05-14 16:13:00 +0200200
Mandeep Khindad6ea9872017-06-24 11:49:37 -0400201if __name__ == "__main__":
BorislavG06518262018-02-14 17:40:49 +0200202 main(sys.argv[1:])
Mandeep Khindad6ea9872017-06-24 11:49:37 -0400203