forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
buildpodutil.go
133 lines (121 loc) · 3.58 KB
/
buildpodutil.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package admission
import (
"errors"
"fmt"
"k8s.io/kubernetes/pkg/admission"
kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
buildapi "github.com/openshift/origin/pkg/build/api"
)
// IsBuildPod returns true if a pod is a pod generated for a Build
func IsBuildPod(a admission.Attributes) bool {
if a.GetResource() != kapi.Resource("pods") {
return false
}
if len(a.GetSubresource()) != 0 {
return false
}
pod, err := GetPod(a)
if err != nil {
return false
}
return hasBuildAnnotation(pod) && hasBuildEnvVar(pod)
}
// GetBuild returns a build object encoded in a pod's BUILD environment variable along with
// its encoding version
func GetBuild(a admission.Attributes) (*buildapi.Build, *unversioned.GroupVersion, error) {
pod, err := GetPod(a)
if err != nil {
return nil, nil, err
}
build, version, err := getBuildFromPod(pod)
if err != nil {
return nil, nil, admission.NewForbidden(a, fmt.Errorf("unable to get build from pod: %v", err))
}
return build, version, nil
}
// GetPod returns a pod from an admission attributes object
func GetPod(a admission.Attributes) (*kapi.Pod, error) {
pod, isPod := a.GetObject().(*kapi.Pod)
if !isPod {
return nil, admission.NewForbidden(a, fmt.Errorf("unrecognized request object: %#v", a.GetObject()))
}
return pod, nil
}
// SetBuild encodes a build object and sets it in a pod's BUILD environment variable
func SetBuild(a admission.Attributes, build *buildapi.Build, groupVersion *unversioned.GroupVersion) error {
pod, err := GetPod(a)
if err != nil {
return err
}
err = setBuildInPod(build, pod, groupVersion)
if err != nil {
return admission.NewForbidden(a, fmt.Errorf("unable to set build in pod: %v", err))
}
return nil
}
// getBuildFromPod detects the encoding of a Build in a pod and returns the Build
// object along with its detected version.
func getBuildFromPod(pod *kapi.Pod) (*buildapi.Build, *unversioned.GroupVersion, error) {
envVar, err := buildEnvVar(pod)
if err != nil {
return nil, nil, err
}
kind, err := kapi.Scheme.DataKind([]byte(envVar.Value))
if err != nil {
return nil, nil, err
}
groupVersion, err := unversioned.ParseGroupVersion(kind.Version)
if err != nil {
return nil, nil, err
}
obj, err := kapi.Scheme.Decode([]byte(envVar.Value))
if err != nil {
return nil, nil, err
}
build, ok := obj.(*buildapi.Build)
if !ok {
return nil, nil, errors.New("decoded object is not of type Build")
}
return build, &groupVersion, nil
}
// setBuildInPod encodes a build with the given version and sets it in the BUILD environment variable
// of the pod.
func setBuildInPod(build *buildapi.Build, pod *kapi.Pod, groupVersion *unversioned.GroupVersion) error {
envVar, err := buildEnvVar(pod)
if err != nil {
return err
}
encodedBuild, err := kapi.Scheme.EncodeToVersion(build, groupVersion.Version)
if err != nil {
return err
}
envVar.Value = string(encodedBuild)
return nil
}
func buildEnvVar(pod *kapi.Pod) (*kapi.EnvVar, error) {
if len(pod.Spec.Containers) == 0 {
return nil, errors.New("pod has no containers")
}
env := pod.Spec.Containers[0].Env
for i := range env {
if env[i].Name == "BUILD" {
if len(env[i].Value) == 0 {
return nil, errors.New("BUILD environment variable is empty")
}
return &env[i], nil
}
}
return nil, errors.New("pod does not have a BUILD environment variable")
}
func hasBuildEnvVar(pod *kapi.Pod) bool {
_, err := buildEnvVar(pod)
return err == nil
}
func hasBuildAnnotation(pod *kapi.Pod) bool {
if pod.Annotations == nil {
return false
}
_, hasAnnotation := pod.Annotations[buildapi.BuildAnnotation]
return hasAnnotation
}