Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(67)

Side by Side Diff: third_party/grpc/tools/gcp/utils/kubernetes_api.py

Issue 1932353002: Initial checkin of gRPC to third_party/ Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #!/usr/bin/env python2.7
2 # Copyright 2015-2016, Google Inc.
3 # All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
7 # met:
8 #
9 # * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # * Redistributions in binary form must reproduce the above
12 # copyright notice, this list of conditions and the following disclaimer
13 # in the documentation and/or other materials provided with the
14 # distribution.
15 # * Neither the name of Google Inc. nor the names of its
16 # contributors may be used to endorse or promote products derived from
17 # this software without specific prior written permission.
18 #
19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 import requests
32 import json
33
34 _REQUEST_TIMEOUT_SECS = 10
35
36
37 def _make_pod_config(pod_name, image_name, container_port_list, cmd_list,
38 arg_list, env_dict):
39 """Creates a string containing the Pod defintion as required by the Kubernetes API"""
40 body = {
41 'kind': 'Pod',
42 'apiVersion': 'v1',
43 'metadata': {
44 'name': pod_name,
45 'labels': {'name': pod_name}
46 },
47 'spec': {
48 'containers': [
49 {
50 'name': pod_name,
51 'image': image_name,
52 'ports': [{'containerPort': port,
53 'protocol': 'TCP'}
54 for port in container_port_list],
55 'imagePullPolicy': 'Always'
56 }
57 ]
58 }
59 }
60
61 env_list = [{'name': k, 'value': v} for (k, v) in env_dict.iteritems()]
62 if len(env_list) > 0:
63 body['spec']['containers'][0]['env'] = env_list
64
65 # Add the 'Command' and 'Args' attributes if they are passed.
66 # Note:
67 # - 'Command' overrides the ENTRYPOINT in the Docker Image
68 # - 'Args' override the CMD in Docker image (yes, it is confusing!)
69 if len(cmd_list) > 0:
70 body['spec']['containers'][0]['command'] = cmd_list
71 if len(arg_list) > 0:
72 body['spec']['containers'][0]['args'] = arg_list
73 return json.dumps(body)
74
75
76 def _make_service_config(service_name, pod_name, service_port_list,
77 container_port_list, is_headless):
78 """Creates a string containing the Service definition as required by the Kuber netes API.
79
80 NOTE:
81 This creates either a Headless Service or 'LoadBalancer' service depending on
82 the is_headless parameter. For Headless services, there is no 'type' attribute
83 and the 'clusterIP' attribute is set to 'None'. Also, if the service is
84 Headless, Kubernetes creates DNS entries for Pods - i.e creates DNS A-records
85 mapping the service's name to the Pods' IPs
86 """
87 if len(container_port_list) != len(service_port_list):
88 print(
89 'ERROR: container_port_list and service_port_list must be of same size')
90 return ''
91 body = {
92 'kind': 'Service',
93 'apiVersion': 'v1',
94 'metadata': {
95 'name': service_name,
96 'labels': {
97 'name': service_name
98 }
99 },
100 'spec': {
101 'ports': [],
102 'selector': {
103 'name': pod_name
104 }
105 }
106 }
107 # Populate the 'ports' list in the 'spec' section. This maps service ports
108 # (port numbers that are exposed by Kubernetes) to container ports (i.e port
109 # numbers that are exposed by your Docker image)
110 for idx in range(len(container_port_list)):
111 port_entry = {
112 'port': service_port_list[idx],
113 'targetPort': container_port_list[idx],
114 'protocol': 'TCP'
115 }
116 body['spec']['ports'].append(port_entry)
117
118 # Make this either a LoadBalancer service or a headless service depending on
119 # the is_headless parameter
120 if is_headless:
121 body['spec']['clusterIP'] = 'None'
122 else:
123 body['spec']['type'] = 'LoadBalancer'
124 return json.dumps(body)
125
126
127 def _print_connection_error(msg):
128 print('ERROR: Connection failed. Did you remember to run Kubenetes proxy on '
129 'localhost (i.e kubectl proxy --port=<proxy_port>) ?. Error: %s' % msg)
130
131
132 def _do_post(post_url, api_name, request_body):
133 """Helper to do HTTP POST.
134
135 Note:
136 1) On success, Kubernetes returns a success code of 201(CREATED) not 200(OK)
137 2) A response code of 509(CONFLICT) is interpreted as a success code (since
138 the error is most likely due to the resource already existing). This makes
139 _do_post() idempotent which is semantically desirable.
140 """
141 is_success = True
142 try:
143 r = requests.post(post_url,
144 data=request_body,
145 timeout=_REQUEST_TIMEOUT_SECS)
146 if r.status_code == requests.codes.conflict:
147 print('WARN: Looks like the resource already exists. Api: %s, url: %s' %
148 (api_name, post_url))
149 elif r.status_code != requests.codes.created:
150 print('ERROR: %s API returned error. HTTP response: (%d) %s' %
151 (api_name, r.status_code, r.text))
152 is_success = False
153 except (requests.exceptions.Timeout,
154 requests.exceptions.ConnectionError) as e:
155 is_success = False
156 _print_connection_error(str(e))
157 return is_success
158
159
160 def _do_delete(del_url, api_name):
161 """Helper to do HTTP DELETE.
162
163 Note: A response code of 404(NOT_FOUND) is treated as success to keep
164 _do_delete() idempotent.
165 """
166 is_success = True
167 try:
168 r = requests.delete(del_url, timeout=_REQUEST_TIMEOUT_SECS)
169 if r.status_code == requests.codes.not_found:
170 print('WARN: The resource does not exist. Api: %s, url: %s' %
171 (api_name, del_url))
172 elif r.status_code != requests.codes.ok:
173 print('ERROR: %s API returned error. HTTP response: %s' %
174 (api_name, r.text))
175 is_success = False
176 except (requests.exceptions.Timeout,
177 requests.exceptions.ConnectionError) as e:
178 is_success = False
179 _print_connection_error(str(e))
180 return is_success
181
182
183 def create_service(kube_host, kube_port, namespace, service_name, pod_name,
184 service_port_list, container_port_list, is_headless):
185 """Creates either a Headless Service or a LoadBalancer Service depending
186 on the is_headless parameter.
187 """
188 post_url = 'http://%s:%d/api/v1/namespaces/%s/services' % (
189 kube_host, kube_port, namespace)
190 request_body = _make_service_config(service_name, pod_name, service_port_list,
191 container_port_list, is_headless)
192 return _do_post(post_url, 'Create Service', request_body)
193
194
195 def create_pod(kube_host, kube_port, namespace, pod_name, image_name,
196 container_port_list, cmd_list, arg_list, env_dict):
197 """Creates a Kubernetes Pod.
198
199 Note that it is generally NOT considered a good practice to directly create
200 Pods. Typically, the recommendation is to create 'Controllers' to create and
201 manage Pods' lifecycle. Currently Kubernetes only supports 'Replication
202 Controller' which creates a configurable number of 'identical Replicas' of
203 Pods and automatically restarts any Pods in case of failures (for eg: Machine
204 failures in Kubernetes). This makes it less flexible for our test use cases
205 where we might want slightly different set of args to each Pod. Hence we
206 directly create Pods and not care much about Kubernetes failures since those
207 are very rare.
208 """
209 post_url = 'http://%s:%d/api/v1/namespaces/%s/pods' % (kube_host, kube_port,
210 namespace)
211 request_body = _make_pod_config(pod_name, image_name, container_port_list,
212 cmd_list, arg_list, env_dict)
213 return _do_post(post_url, 'Create Pod', request_body)
214
215
216 def delete_service(kube_host, kube_port, namespace, service_name):
217 del_url = 'http://%s:%d/api/v1/namespaces/%s/services/%s' % (
218 kube_host, kube_port, namespace, service_name)
219 return _do_delete(del_url, 'Delete Service')
220
221
222 def delete_pod(kube_host, kube_port, namespace, pod_name):
223 del_url = 'http://%s:%d/api/v1/namespaces/%s/pods/%s' % (kube_host, kube_port,
224 namespace, pod_name)
225 return _do_delete(del_url, 'Delete Pod')
226
227
228 def create_pod_and_service(kube_host, kube_port, namespace, pod_name,
229 image_name, container_port_list, cmd_list, arg_list,
230 env_dict, is_headless_service):
231 """A helper function that creates a pod and a service (if pod creation was suc cessful)."""
232 is_success = create_pod(kube_host, kube_port, namespace, pod_name, image_name,
233 container_port_list, cmd_list, arg_list, env_dict)
234 if not is_success:
235 print 'Error in creating Pod'
236 return False
237
238 is_success = create_service(
239 kube_host,
240 kube_port,
241 namespace,
242 pod_name, # Use pod_name for service
243 pod_name,
244 container_port_list, # Service port list same as container port list
245 container_port_list,
246 is_headless_service)
247 if not is_success:
248 print 'Error in creating Service'
249 return False
250
251 print 'Successfully created the pod/service %s' % pod_name
252 return True
253
254
255 def delete_pod_and_service(kube_host, kube_port, namespace, pod_name):
256 """ A helper function that calls delete_pod and delete_service """
257 is_success = delete_pod(kube_host, kube_port, namespace, pod_name)
258 if not is_success:
259 print 'Error in deleting pod %s' % pod_name
260 return False
261
262 # Note: service name assumed to the the same as pod name
263 is_success = delete_service(kube_host, kube_port, namespace, pod_name)
264 if not is_success:
265 print 'Error in deleting service %s' % pod_name
266 return False
267
268 print 'Successfully deleted the Pod/Service: %s' % pod_name
269 return True
OLDNEW
« no previous file with comments | « third_party/grpc/tools/gcp/utils/big_query_utils.py ('k') | third_party/grpc/tools/http2_interop/README.md » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698