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

Side by Side Diff: deploytool/cmd/kubernetes.go

Issue 2182213002: deploytool: Add README.md, migrate docs to it. (Closed) Base URL: https://github.com/luci/luci-go@master
Patch Set: Rename to "luci_deploy" Created 4 years, 4 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
« no previous file with comments | « deploytool/cmd/doc.go ('k') | deploytool/cmd/layout.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 package main
6
7 import (
8 "fmt"
9 "sort"
10
11 "github.com/luci/luci-go/common/errors"
12 "github.com/luci/luci-go/deploytool/api/deploy"
13
14 "golang.org/x/net/context"
15 "gopkg.in/yaml.v2"
16 )
17
18 var errKubeResourceNotFound = errors.New("resource not found")
19
20 // kubeDeployment defines a [v1beta1.Deployment].
21 type kubeDeployment struct {
22 Kind string `yaml:"kind"`
23 APIVersion string `yaml:"apiVersion"`
24 Metadata *kubeObjectMeta `yaml:"metadata,omitempty"`
25 Spec *kubeDeploymentSpec `yaml:"spec,omitempty"`
26 Status *kubeDeploymentStatus `yaml:"status,omitempty"`
27 }
28
29 // kubeDeploymentSpec defines a [v1beta1.DeploymentSpec].
30 type kubeDeploymentSpec struct {
31 Replicas int `yaml:"replicas,omitempty"`
32 Selector *kubeLabelSelector `yaml:"selector,omitempty"`
33 Template *kubePodTemplateSpec `yaml:"template"`
34
35 MinReadySeconds int `yaml:"minReadySeconds,omitempty"`
36 RevisionHistoryLimit int `yaml:"revisionHistoryLimit,omitempty"`
37 Paused bool `yaml:"paused,omitempty"`
38 }
39
40 // kubeDeploymentSpec defines a [v1beta1.DeploymentStatus].
41 type kubeDeploymentStatus struct {
42 ObservedGeneration int `yaml:"observedGeneration"`
43 Replicas int `yaml:"replicas"`
44 UpdatedReplicas int `yaml:"updatedReplicas"`
45 AvailableRepicas int `yaml:"availableReplicas"`
46 UnavailableReplicas int `yaml:"unavailableReplicas"`
47 }
48
49 // kubePodTemplateSpec defines a [v1.PodTemplateSpec].
50 type kubePodTemplateSpec struct {
51 Metadata *kubeObjectMeta `yaml:"metadata,omitempty"`
52 Spec *kubePodSpec `yaml:"spec,omitempty"`
53 }
54
55 // kubePodSpec defines a [v1.PodSpec].
56 type kubePodSpec struct {
57 Containers []*kubeContainer `yaml:"containers"`
58 RestartPolicy string `yaml:"restartPolicy,omitempty"`
59
60 TerminationGracePeriodSeconds int `yaml:"terminationGracePeriodSeconds,o mitempty"`
61 ActiveDeadlineSeconds int `yaml:"activeDeadlineSeconds,omitempty "`
62 }
63
64 // kubeContainer defines a [v1.Container].
65 type kubeContainer struct {
66 Name string `yaml:"name"`
67 Image string `yaml:"image,omitempty"`
68 Command []string `yaml:"command,omitempty"`
69 Args []string `yaml:"args,omitempty"`
70 WorkingDir string `yaml:"workingDir,omitempty"`
71
72 Ports []*kubeContainerPort `yaml:"ports,omitempty"`
73 Env []*kubeEnvVar `yaml:"env,omitempty"`
74 Resources *kubeResourceRequirements `yaml:"resources,omitempty"`
75
76 LivenessProbe *kubeProbe `yaml:"livenessProbe,omitempty"`
77 ReadinessProbe *kubeProbe `yaml:"readinessProbe,omitempty"`
78
79 Lifecycle *kubeLifecycle `yaml:"lifecycle,omitempty"`
80 }
81
82 // kubeContainerPort defines a [v1.ContainerPort].
83 type kubeContainerPort struct {
84 Name string `yaml:"name,omitempty"`
85 HostPort int `yaml:"hostPort,omitempty"`
86 ContainerPort int `yaml:"containerPort"`
87 Protocol string `yaml:"protocol,omitempty"`
88 HostIP string `yaml:"hostIP,omitempty"`
89 }
90
91 // kubeEnvVar defines a [v1.EnvVar].
92 type kubeEnvVar struct {
93 Name string `yaml:"name"`
94 Value string `yaml:"name,omitempty"`
95 ValueFrom *kubeEnvVarSource `yaml:"valueFrom,omitempty"`
96 }
97
98 // kubeEnvVarSource represents a [v1.EnvVarSource].
99 type kubeEnvVarSource struct {
100 FieldRef *kubeObjectFieldSelector
101 ConfigMapKeyRef *kubeConfigMapKeySelector `yaml:"configMapKeyRef,omitemp ty"`
102 SecretKeyRef *kubeSecretKeySelector `yaml:"secretKeyRef,omitempty" `
103 }
104
105 // kubeLabelSelector represents a [v1beta1.LabelSelector].
106 type kubeLabelSelector struct {
107 MatchLabels map[string]interface{} `yaml:"matchLabels,omitem pty"`
108 MatchExpressions *kubeLabelSelectorRequirement `yaml:"matchExpressions,o mitempty"`
109 }
110
111 // kubeLabelSelectorRequirement represets a [v1beta1.LabelSelectorRequirement].
112 type kubeLabelSelectorRequirement struct {
113 Key string `yaml:"key"`
114 Operator string `yaml:"operator"`
115 Values []string `yaml:"values,omitempty"`
116 }
117
118 // kubeObjectFieldSelector defines a [v1.ObjectFieldSelector].
119 type kubeObjectFieldSelector struct {
120 APIVersion string `yaml:"apiVersion,omitempty"`
121 FieldPath string `yaml:"fieldPath"`
122 }
123
124 // kubeConfigMapKeySelector defines a [v1.ConfigMapKeySelector].
125 type kubeConfigMapKeySelector struct {
126 Name string `yaml:"name,omitempty"`
127 Key string `yaml:"key"`
128 }
129
130 // kubeSecretKeySelector defines a [v1.SecretKeySelector].
131 type kubeSecretKeySelector struct {
132 Name string `yaml:"name,omitempty"`
133 Key string `yaml:"key"`
134 }
135
136 // kubeResourceRequirements defines a [v1.ResourceRequirements].
137 type kubeResourceRequirements struct {
138 Limits map[string]interface{} `yaml:"limits,omitempty"`
139 Requests map[string]interface{} `yaml:"requests,omitempty"`
140 }
141
142 // kubeHTTPGetAction defines a [v1.HTTPGetAction].
143 type kubeHTTPGetAction struct {
144 Path string `yaml:"path,omitempty"`
145 Port int `yaml:"port"`
146 Host string `yaml:"host,omitempty"`
147 Scheme string `yaml:"scheme,omitempty"`
148
149 HTTPHeaders []*kubeHTTPHeader `yaml:"httpHeaders,omitempty"`
150 }
151
152 // kubeHTTPHeader defines a [v1.HTTPHeader].
153 type kubeHTTPHeader struct {
154 Key string `yaml:"key"`
155 Value string `yaml:"value,omitempty"`
156 }
157
158 // kubeProbe defines a [v1.Probe]
159 type kubeProbe struct {
160 // Exec defines a [v1.ExecAction].
161 Exec *kubeExecAction
162 HTTPGet *kubeHTTPGetAction `yaml:"httpGet,omitempty"`
163
164 InitialDelaySeconds int `yaml:"initialDelaySeconds,omitempty"`
165 TimeoutSeconds int `yaml:"timeoutSeconds,omitempty"`
166 PeriodSeconds int `yaml:"periodSeconds,omitempty"`
167 SuccessThreshold int `yaml:"successThreshold,omitempty"`
168 FailureThreshold int `yaml:"failureThreshold,omitempty"`
169 }
170
171 // kubeExecAction defines a [v1.ExecAction].
172 type kubeExecAction struct {
173 Command []string `yaml:"command"`
174 }
175
176 // kubeLifecycle defines a [v1.Lifecycle].
177 type kubeLifecycle struct {
178 PostStart *kubeHandler `yaml:"postStart,omitempty"`
179 PreStop *kubeHandler `yaml:"preStop,omitempty"`
180 }
181
182 // kubeHandler defines a [v1.Handler].
183 type kubeHandler struct {
184 Exec *kubeExecAction `yaml:"exec,omitempty"`
185 HTTPGet *kubeHTTPGetAction `yaml:"httpGet,omitempty"`
186 }
187
188 // kubeObjectMeta defines a [v1.ObjectMeta].
189 type kubeObjectMeta struct {
190 Name string `yaml:"name,omitempty"`
191 GenerateName string `yaml:"generateName,omitempty"`
192 Namespace string `yaml:"namespace,omitempty"`
193
194 SelfLink string `yaml:"selfLink,omitempty"`
195 UID string `yaml:"uid,omitempty"`
196 ResourceVersion string `yaml:"resourceVersion,omitempty"`
197 Generation string `yaml:"generation,omitempty"`
198 CreationTimestamp string `yaml:"creationTimestamp,omitempty"`
199 DeletionTimestamp string `yaml:"deletionTimestamp,omitempty"`
200 DeletionGracePeriodSeconds int `yaml:"deletionGracePeriodSeconds,omit empty"`
201
202 // Labels defines a series of [any] labels.
203 Labels map[string]interface{} `yaml:"labels,omitempty"`
204 // Annotations defines a series of [any] annotations.
205 Annotations map[string]interface{} `yaml:"annotations,omitempty"`
206 }
207
208 func (meta *kubeObjectMeta) addLabel(key string, value interface{}) {
209 if meta.Labels == nil {
210 meta.Labels = make(map[string]interface{})
211 }
212 meta.Labels[key] = value
213 }
214
215 func (meta *kubeObjectMeta) addAnnotation(key string, value interface{}) {
216 if meta.Annotations == nil {
217 meta.Annotations = make(map[string]interface{})
218 }
219 meta.Annotations[key] = value
220 }
221
222 func kubeBuildDeploymentYAML(pb *layoutDeploymentGKEPodBinding, name string,
223 imageMap map[string]string) *kubeDeployment {
224 kp := pb.pod.KubePod
225 dep := kubeDeployment{
226 Kind: "Deployment",
227 APIVersion: "extensions/v1beta1",
228 Metadata: &kubeObjectMeta{
229 Name: name,
230 Labels: make(map[string]interface{}),
231 Annotations: make(map[string]interface{}),
232 },
233 Spec: &kubeDeploymentSpec{
234 Replicas: int(pb.Replicas),
235 Template: &kubePodTemplateSpec{
236 Metadata: &kubeObjectMeta{},
237 Spec: &kubePodSpec{
238 Containers: make([]*k ubeContainer, len(kp.Container)),
239 RestartPolicy: kp.Restar tPolicy.KubeString(),
240 TerminationGracePeriodSeconds: int(kp.Te rminationGracePeriod.Duration().Seconds()),
241 ActiveDeadlineSeconds: int(kp.Ac tiveDeadline.Duration().Seconds()),
242 },
243 },
244 MinReadySeconds: int(kp.MinReady.Duration().Seconds()),
245 },
246 }
247 tmpl := dep.Spec.Template
248
249 // Pod Template Metadata
250 for k, v := range kp.Labels {
251 tmpl.Metadata.Labels[k] = v
252 }
253
254 // Pod Template Containers
255 for i, kc := range kp.Container {
256 cont := kubeContainer{
257 Name: kc.Name,
258 Image: imageMap[kc.Name],
259 Command: kc.Command,
260 Args: kc.Args,
261 WorkingDir: kc.WorkingDir,
262 }
263
264 // Ports
265 if len(kc.Ports) > 0 {
266 cont.Ports = make([]*kubeContainerPort, len(kc.Ports))
267 for i, port := range kc.Ports {
268 cont.Ports[i] = &kubeContainerPort{
269 Name: port.Name,
270 ContainerPort: int(port.ContainerPort),
271 }
272 }
273 }
274
275 // Environment
276 if len(kc.Env) > 0 {
277 cont.Env = make([]*kubeEnvVar, 0, len(kc.Env))
278 for k, v := range kc.Env {
279 cont.Env = append(cont.Env, &kubeEnvVar{
280 Name: k,
281 Value: v,
282 })
283 }
284 sort.Sort(sortableEnvVarSlice(cont.Env))
285 }
286
287 // Resources
288 var res kubeResourceRequirements
289 for _, r := range []struct {
290 r *deploy.KubernetesPod_Container_Resources
291 p *map[string]interface{}
292 }{
293 {kc.Limits, &res.Limits},
294 {kc.Requested, &res.Requests},
295 } {
296 if r.r == nil {
297 continue
298 }
299
300 m := make(map[string]interface{}, 2)
301 if cpu := r.r.Cpu; cpu > 0 {
302 m["cpu"] = cpu
303 }
304 if mem := r.r.Memory; mem != nil {
305 m["memory"] = fmt.Sprintf("%d%s", mem.Amount, me m.Unit.KubeSuffix())
306 }
307 if len(m) > 0 {
308 // We have at least one resource value, so assig n.
309 *r.p = m
310 cont.Resources = &res
311 }
312 }
313
314 // Probes
315 for _, p := range []struct {
316 v *deploy.KubernetesPod_Container_Probe
317 p **kubeProbe
318 }{
319 {kc.LivenessProbe, &cont.LivenessProbe},
320 {kc.ReadinessProbe, &cont.ReadinessProbe},
321 } {
322 if p.v == nil {
323 continue
324 }
325
326 probe := kubeProbe{
327 InitialDelaySeconds: int(p.v.InitialDelay.Durati on().Seconds()),
328 TimeoutSeconds: int(p.v.Timeout.Duration(). Seconds()),
329 PeriodSeconds: int(p.v.Period.Duration().S econds()),
330 SuccessThreshold: int(p.v.SuccessThreshold),
331 FailureThreshold: int(p.v.FailureThreshold),
332 }
333 if exec := p.v.Exec; len(exec) > 0 {
334 probe.Exec = &kubeExecAction{
335 Command: exec,
336 }
337 }
338 if hg := p.v.HttpGet; hg != nil {
339 probe.HTTPGet = kubeMakeHTTPGetAction(hg)
340 }
341 *p.p = &probe
342 }
343
344 // Handlers
345 var lc kubeLifecycle
346 for _, h := range []struct {
347 v *deploy.KubernetesPod_Container_Handler
348 p **kubeHandler
349 }{
350 {kc.PostStart, &lc.PostStart},
351 {kc.PreStop, &lc.PreStop},
352 } {
353 if h.v == nil {
354 continue
355 }
356
357 var handler kubeHandler
358 if exec := h.v.ExecCommand; len(exec) > 0 {
359 handler.Exec = &kubeExecAction{
360 Command: exec,
361 }
362 }
363 if hg := h.v.HttpGet; hg != nil {
364 handler.HTTPGet = kubeMakeHTTPGetAction(hg)
365 }
366
367 // We have an entry here, so assign.
368 *h.p = &handler
369 cont.Lifecycle = &lc
370 }
371
372 tmpl.Spec.Containers[i] = &cont
373 }
374
375 return &dep
376 }
377
378 func kubeMakeHTTPGetAction(hg *deploy.KubernetesPod_Container_HttpGet) *kubeHTTP GetAction {
379 act := kubeHTTPGetAction{
380 Path: hg.Path,
381 Port: int(hg.Port),
382 Host: hg.Host,
383 Scheme: hg.Scheme,
384 }
385 if len(hg.Headers) > 0 {
386 act.HTTPHeaders = make([]*kubeHTTPHeader, len(hg.Headers))
387 for i, hdr := range hg.Headers {
388 act.HTTPHeaders[i] = &kubeHTTPHeader{
389 Key: hdr.Name,
390 Value: hdr.Value,
391 }
392 }
393 }
394 return &act
395 }
396
397 type sortableEnvVarSlice []*kubeEnvVar
398
399 func (s sortableEnvVarSlice) Len() int { return len(s) }
400 func (s sortableEnvVarSlice) Less(i, j int) bool { return s[i].Name < s[j].Name }
401 func (s sortableEnvVarSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
402
403 // kubeTool wraps the "kubectl" tool.
404 type kubeTool struct {
405 exe string
406 ctx string
407 }
408
409 func (t *kubeTool) hasContext(c context.Context) (bool, error) {
410 x := execute(t.exe, "config", "view",
411 "--output", fmt.Sprintf(`jsonpath='{.users[?(@.name == %q)].name }'`, t.ctx))
412 if err := x.check(c); err != nil {
413 return false, err
414 }
415 return (x.stdout.String() != "''"), nil
416 }
417
418 func (t *kubeTool) exec(commands ...string) *workExecutor {
419 args := make([]string, 0, 2+len(commands))
420 args = append(args, "--context", t.ctx)
421 args = append(args, commands...)
422 return execute(t.exe, args...)
423 }
424
425 func (t *kubeTool) getResource(c context.Context, resource string, obj interface {}) error {
426 x := t.exec("get", resource, "-o", "yaml")
427 switch rv, err := x.run(c); {
428 case err != nil:
429 return err
430
431 case rv != 0:
432 return errKubeResourceNotFound
433
434 default:
435 if err := yaml.Unmarshal(x.stdout.Bytes(), obj); err != nil {
436 return errors.Annotate(err).Reason("failed to unmarshal YAML %(type)T").D("type", obj).Err()
437 }
438 return nil
439 }
440 }
OLDNEW
« no previous file with comments | « deploytool/cmd/doc.go ('k') | deploytool/cmd/layout.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698