The BuildDefaults plugin allows setting default values for proxy
environment variables and git HTTP/S proxy settings.
The BuildOverrides plugin overrides the ForcePull setting on all
builds going through the build pod strategy.
1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,133 @@ |
0 |
+package admission |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "errors" |
|
4 |
+ "fmt" |
|
5 |
+ |
|
6 |
+ "k8s.io/kubernetes/pkg/admission" |
|
7 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
8 |
+ "k8s.io/kubernetes/pkg/api/unversioned" |
|
9 |
+ |
|
10 |
+ buildapi "github.com/openshift/origin/pkg/build/api" |
|
11 |
+) |
|
12 |
+ |
|
13 |
+// IsBuildPod returns true if a pod is a pod generated for a Build |
|
14 |
+func IsBuildPod(a admission.Attributes) bool { |
|
15 |
+ if a.GetResource() != kapi.Resource("pods") { |
|
16 |
+ return false |
|
17 |
+ } |
|
18 |
+ if len(a.GetSubresource()) != 0 { |
|
19 |
+ return false |
|
20 |
+ } |
|
21 |
+ pod, err := GetPod(a) |
|
22 |
+ if err != nil { |
|
23 |
+ return false |
|
24 |
+ } |
|
25 |
+ return hasBuildAnnotation(pod) && hasBuildEnvVar(pod) |
|
26 |
+} |
|
27 |
+ |
|
28 |
+// GetBuild returns a build object encoded in a pod's BUILD environment variable along with |
|
29 |
+// its encoding version |
|
30 |
+func GetBuild(a admission.Attributes) (*buildapi.Build, *unversioned.GroupVersion, error) { |
|
31 |
+ pod, err := GetPod(a) |
|
32 |
+ if err != nil { |
|
33 |
+ return nil, nil, err |
|
34 |
+ } |
|
35 |
+ build, version, err := getBuildFromPod(pod) |
|
36 |
+ if err != nil { |
|
37 |
+ return nil, nil, admission.NewForbidden(a, fmt.Errorf("unable to get build from pod: %v", err)) |
|
38 |
+ } |
|
39 |
+ return build, version, nil |
|
40 |
+} |
|
41 |
+ |
|
42 |
+// GetPod returns a pod from an admission attributes object |
|
43 |
+func GetPod(a admission.Attributes) (*kapi.Pod, error) { |
|
44 |
+ pod, isPod := a.GetObject().(*kapi.Pod) |
|
45 |
+ if !isPod { |
|
46 |
+ return nil, admission.NewForbidden(a, fmt.Errorf("unrecognized request object: %#v", a.GetObject())) |
|
47 |
+ } |
|
48 |
+ return pod, nil |
|
49 |
+} |
|
50 |
+ |
|
51 |
+// SetBuild encodes a build object and sets it in a pod's BUILD environment variable |
|
52 |
+func SetBuild(a admission.Attributes, build *buildapi.Build, groupVersion *unversioned.GroupVersion) error { |
|
53 |
+ pod, err := GetPod(a) |
|
54 |
+ if err != nil { |
|
55 |
+ return err |
|
56 |
+ } |
|
57 |
+ err = setBuildInPod(build, pod, groupVersion) |
|
58 |
+ if err != nil { |
|
59 |
+ return admission.NewForbidden(a, fmt.Errorf("unable to set build in pod: %v", err)) |
|
60 |
+ } |
|
61 |
+ return nil |
|
62 |
+} |
|
63 |
+ |
|
64 |
+// getBuildFromPod detects the encoding of a Build in a pod and returns the Build |
|
65 |
+// object along with its detected version. |
|
66 |
+func getBuildFromPod(pod *kapi.Pod) (*buildapi.Build, *unversioned.GroupVersion, error) { |
|
67 |
+ envVar, err := buildEnvVar(pod) |
|
68 |
+ if err != nil { |
|
69 |
+ return nil, nil, err |
|
70 |
+ } |
|
71 |
+ kind, err := kapi.Scheme.DataKind([]byte(envVar.Value)) |
|
72 |
+ if err != nil { |
|
73 |
+ return nil, nil, err |
|
74 |
+ } |
|
75 |
+ groupVersion, err := unversioned.ParseGroupVersion(kind.Version) |
|
76 |
+ if err != nil { |
|
77 |
+ return nil, nil, err |
|
78 |
+ } |
|
79 |
+ obj, err := kapi.Scheme.Decode([]byte(envVar.Value)) |
|
80 |
+ if err != nil { |
|
81 |
+ return nil, nil, err |
|
82 |
+ } |
|
83 |
+ build, ok := obj.(*buildapi.Build) |
|
84 |
+ if !ok { |
|
85 |
+ return nil, nil, errors.New("decoded object is not of type Build") |
|
86 |
+ } |
|
87 |
+ return build, &groupVersion, nil |
|
88 |
+} |
|
89 |
+ |
|
90 |
+// setBuildInPod encodes a build with the given version and sets it in the BUILD environment variable |
|
91 |
+// of the pod. |
|
92 |
+func setBuildInPod(build *buildapi.Build, pod *kapi.Pod, groupVersion *unversioned.GroupVersion) error { |
|
93 |
+ envVar, err := buildEnvVar(pod) |
|
94 |
+ if err != nil { |
|
95 |
+ return err |
|
96 |
+ } |
|
97 |
+ encodedBuild, err := kapi.Scheme.EncodeToVersion(build, groupVersion.Version) |
|
98 |
+ if err != nil { |
|
99 |
+ return err |
|
100 |
+ } |
|
101 |
+ envVar.Value = string(encodedBuild) |
|
102 |
+ return nil |
|
103 |
+} |
|
104 |
+ |
|
105 |
+func buildEnvVar(pod *kapi.Pod) (*kapi.EnvVar, error) { |
|
106 |
+ if len(pod.Spec.Containers) == 0 { |
|
107 |
+ return nil, errors.New("pod has no containers") |
|
108 |
+ } |
|
109 |
+ env := pod.Spec.Containers[0].Env |
|
110 |
+ for i := range env { |
|
111 |
+ if env[i].Name == "BUILD" { |
|
112 |
+ if len(env[i].Value) == 0 { |
|
113 |
+ return nil, errors.New("BUILD environment variable is empty") |
|
114 |
+ } |
|
115 |
+ return &env[i], nil |
|
116 |
+ } |
|
117 |
+ } |
|
118 |
+ return nil, errors.New("pod does not have a BUILD environment variable") |
|
119 |
+} |
|
120 |
+ |
|
121 |
+func hasBuildEnvVar(pod *kapi.Pod) bool { |
|
122 |
+ _, err := buildEnvVar(pod) |
|
123 |
+ return err == nil |
|
124 |
+} |
|
125 |
+ |
|
126 |
+func hasBuildAnnotation(pod *kapi.Pod) bool { |
|
127 |
+ if pod.Annotations == nil { |
|
128 |
+ return false |
|
129 |
+ } |
|
130 |
+ _, hasAnnotation := pod.Annotations[buildapi.BuildAnnotation] |
|
131 |
+ return hasAnnotation |
|
132 |
+} |
0 | 133 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,80 @@ |
0 |
+package admission |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "reflect" |
|
4 |
+ "testing" |
|
5 |
+ |
|
6 |
+ "k8s.io/kubernetes/pkg/api/unversioned" |
|
7 |
+ |
|
8 |
+ u "github.com/openshift/origin/pkg/build/admission/testutil" |
|
9 |
+ buildapi "github.com/openshift/origin/pkg/build/api" |
|
10 |
+) |
|
11 |
+ |
|
12 |
+func TestIsBuildPod(t *testing.T) { |
|
13 |
+ tests := []struct { |
|
14 |
+ pod *u.TestPod |
|
15 |
+ expected bool |
|
16 |
+ }{ |
|
17 |
+ { |
|
18 |
+ pod: u.Pod().WithAnnotation("foo", "bar"), |
|
19 |
+ expected: false, |
|
20 |
+ }, |
|
21 |
+ { |
|
22 |
+ pod: u.Pod().WithEnvVar("BUILD", "blah"), |
|
23 |
+ expected: false, |
|
24 |
+ }, |
|
25 |
+ { |
|
26 |
+ pod: u.Pod().WithAnnotation(buildapi.BuildAnnotation, "build"), |
|
27 |
+ expected: false, |
|
28 |
+ }, |
|
29 |
+ { |
|
30 |
+ pod: u.Pod(). |
|
31 |
+ WithAnnotation(buildapi.BuildAnnotation, "build"). |
|
32 |
+ WithEnvVar("BUILD", "true"), |
|
33 |
+ expected: true, |
|
34 |
+ }, |
|
35 |
+ } |
|
36 |
+ |
|
37 |
+ for _, tc := range tests { |
|
38 |
+ actual := IsBuildPod(tc.pod.ToAttributes()) |
|
39 |
+ if actual != tc.expected { |
|
40 |
+ t.Errorf("unexpected result (%v) for pod %#v", actual, tc.pod) |
|
41 |
+ } |
|
42 |
+ } |
|
43 |
+} |
|
44 |
+ |
|
45 |
+func TestGetBuild(t *testing.T) { |
|
46 |
+ build := u.Build().WithDockerStrategy() |
|
47 |
+ for _, version := range []string{"v1", "v1beta3"} { |
|
48 |
+ pod := u.Pod().WithBuild(t, build.AsBuild(), version) |
|
49 |
+ resultBuild, resultVersion, err := GetBuild(pod.ToAttributes()) |
|
50 |
+ if err != nil { |
|
51 |
+ t.Fatalf("unexpected error: %v", err) |
|
52 |
+ } |
|
53 |
+ if resultVersion.Version != version { |
|
54 |
+ t.Errorf("unexpected version: %s", resultVersion) |
|
55 |
+ } |
|
56 |
+ if !reflect.DeepEqual(build.AsBuild(), resultBuild) { |
|
57 |
+ t.Errorf("%s: did not get expected build: %#v", version, resultBuild) |
|
58 |
+ } |
|
59 |
+ } |
|
60 |
+} |
|
61 |
+ |
|
62 |
+func TestSetBuild(t *testing.T) { |
|
63 |
+ build := u.Build().WithSourceStrategy() |
|
64 |
+ for _, version := range []string{"v1", "v1beta3"} { |
|
65 |
+ pod := u.Pod().WithEnvVar("BUILD", "foo") |
|
66 |
+ groupVersion, err := unversioned.ParseGroupVersion(version) |
|
67 |
+ if err != nil { |
|
68 |
+ t.Fatalf("unexpected error: %v", err) |
|
69 |
+ } |
|
70 |
+ err = SetBuild(pod.ToAttributes(), build.AsBuild(), &groupVersion) |
|
71 |
+ if err != nil { |
|
72 |
+ t.Fatalf("unexpected error: %v", err) |
|
73 |
+ } |
|
74 |
+ resultBuild := pod.GetBuild(t) |
|
75 |
+ if !reflect.DeepEqual(build.AsBuild(), resultBuild) { |
|
76 |
+ t.Errorf("%s: did not get expected build: %#v", version, resultBuild) |
|
77 |
+ } |
|
78 |
+ } |
|
79 |
+} |
0 | 80 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,28 @@ |
0 |
+package admission |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "io" |
|
4 |
+ "io/ioutil" |
|
5 |
+ "reflect" |
|
6 |
+ |
|
7 |
+ "k8s.io/kubernetes/pkg/runtime" |
|
8 |
+ |
|
9 |
+ configlatest "github.com/openshift/origin/pkg/cmd/server/api/latest" |
|
10 |
+) |
|
11 |
+ |
|
12 |
+// ReadPluginConfig will read a plugin configuration object from a reader stream |
|
13 |
+func ReadPluginConfig(reader io.Reader, config runtime.Object) error { |
|
14 |
+ if reader == nil || reflect.ValueOf(reader).IsNil() { |
|
15 |
+ return nil |
|
16 |
+ } |
|
17 |
+ |
|
18 |
+ configBytes, err := ioutil.ReadAll(reader) |
|
19 |
+ if err != nil { |
|
20 |
+ return err |
|
21 |
+ } |
|
22 |
+ err = configlatest.ReadYAML(configBytes, config) |
|
23 |
+ if err != nil { |
|
24 |
+ return err |
|
25 |
+ } |
|
26 |
+ return nil |
|
27 |
+} |
0 | 28 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,72 @@ |
0 |
+package admission |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "bytes" |
|
4 |
+ "reflect" |
|
5 |
+ "testing" |
|
6 |
+ |
|
7 |
+ "k8s.io/kubernetes/pkg/api/unversioned" |
|
8 |
+ |
|
9 |
+ configapi "github.com/openshift/origin/pkg/cmd/server/api" |
|
10 |
+) |
|
11 |
+ |
|
12 |
+type TestConfig struct { |
|
13 |
+ unversioned.TypeMeta |
|
14 |
+ |
|
15 |
+ Item1 string `json:"item1"` |
|
16 |
+ Item2 []string `json:"item2"` |
|
17 |
+} |
|
18 |
+ |
|
19 |
+func (*TestConfig) IsAnAPIObject() {} |
|
20 |
+ |
|
21 |
+type TestConfig2 struct { |
|
22 |
+ unversioned.TypeMeta |
|
23 |
+ Item1 string `json:"item1"` |
|
24 |
+} |
|
25 |
+ |
|
26 |
+func (*TestConfig2) IsAnAPIObject() {} |
|
27 |
+ |
|
28 |
+func TestReadPluginConfig(t *testing.T) { |
|
29 |
+ groupVersion := unversioned.GroupVersion{Group: "", Version: ""} |
|
30 |
+ v1GroupVersion := unversioned.GroupVersion{Group: "", Version: "v1"} |
|
31 |
+ configapi.Scheme.AddKnownTypes(groupVersion, &TestConfig{}) |
|
32 |
+ configapi.Scheme.AddKnownTypes(v1GroupVersion, &TestConfig{}) |
|
33 |
+ configapi.Scheme.AddKnownTypes(groupVersion, &TestConfig2{}) |
|
34 |
+ configapi.Scheme.AddKnownTypes(v1GroupVersion, &TestConfig2{}) |
|
35 |
+ |
|
36 |
+ configString := `apiVersion: v1 |
|
37 |
+kind: TestConfig |
|
38 |
+item1: hello |
|
39 |
+item2: |
|
40 |
+- foo |
|
41 |
+- bar |
|
42 |
+` |
|
43 |
+ config := &TestConfig{} |
|
44 |
+ |
|
45 |
+ expected := &TestConfig{ |
|
46 |
+ Item1: "hello", |
|
47 |
+ Item2: []string{"foo", "bar"}, |
|
48 |
+ } |
|
49 |
+ // The config should match the expected config object |
|
50 |
+ err := ReadPluginConfig(bytes.NewBufferString(configString), config) |
|
51 |
+ if err != nil { |
|
52 |
+ t.Fatalf("unexpected: %v", err) |
|
53 |
+ } |
|
54 |
+ if !reflect.DeepEqual(config, expected) { |
|
55 |
+ t.Errorf("config does not equal expected: %#v", config) |
|
56 |
+ } |
|
57 |
+ |
|
58 |
+ // Passing a nil reader, should not get an error |
|
59 |
+ var nilBuffer *bytes.Buffer |
|
60 |
+ err = ReadPluginConfig(nilBuffer, &TestConfig{}) |
|
61 |
+ if err != nil { |
|
62 |
+ t.Fatalf("unexpected: %v", err) |
|
63 |
+ } |
|
64 |
+ |
|
65 |
+ // Passing the wrong type of destination object should result in an error |
|
66 |
+ config2 := &TestConfig2{} |
|
67 |
+ err = ReadPluginConfig(bytes.NewBufferString(configString), config2) |
|
68 |
+ if err == nil { |
|
69 |
+ t.Fatalf("expected error") |
|
70 |
+ } |
|
71 |
+} |
0 | 72 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,127 @@ |
0 |
+package defaults |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "io" |
|
4 |
+ |
|
5 |
+ "github.com/golang/glog" |
|
6 |
+ "k8s.io/kubernetes/pkg/admission" |
|
7 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
8 |
+ kclient "k8s.io/kubernetes/pkg/client/unversioned" |
|
9 |
+ |
|
10 |
+ buildadmission "github.com/openshift/origin/pkg/build/admission" |
|
11 |
+ buildapi "github.com/openshift/origin/pkg/build/api" |
|
12 |
+) |
|
13 |
+ |
|
14 |
+func init() { |
|
15 |
+ admission.RegisterPlugin("BuildDefaults", func(c kclient.Interface, config io.Reader) (admission.Interface, error) { |
|
16 |
+ |
|
17 |
+ defaultsConfig, err := getConfig(config) |
|
18 |
+ if err != nil { |
|
19 |
+ return nil, err |
|
20 |
+ } |
|
21 |
+ |
|
22 |
+ glog.V(4).Infof("Initializing BuildDefaults plugin with config: %#v", defaultsConfig) |
|
23 |
+ return NewBuildDefaults(defaultsConfig), nil |
|
24 |
+ }) |
|
25 |
+} |
|
26 |
+ |
|
27 |
+func getConfig(in io.Reader) (*BuildDefaultsConfig, error) { |
|
28 |
+ defaultsConfig := &BuildDefaultsConfig{} |
|
29 |
+ err := buildadmission.ReadPluginConfig(in, defaultsConfig) |
|
30 |
+ if err != nil { |
|
31 |
+ return nil, err |
|
32 |
+ } |
|
33 |
+ errs := ValidateBuildDefaultsConfig(defaultsConfig) |
|
34 |
+ if len(errs) > 0 { |
|
35 |
+ return nil, errs.ToAggregate() |
|
36 |
+ } |
|
37 |
+ return defaultsConfig, nil |
|
38 |
+} |
|
39 |
+ |
|
40 |
+type buildDefaults struct { |
|
41 |
+ *admission.Handler |
|
42 |
+ defaultsConfig *BuildDefaultsConfig |
|
43 |
+} |
|
44 |
+ |
|
45 |
+// NewBuildDefaults returns an admission control for builds that sets build defaults |
|
46 |
+// based on the plugin configuration |
|
47 |
+func NewBuildDefaults(defaultsConfig *BuildDefaultsConfig) admission.Interface { |
|
48 |
+ return &buildDefaults{ |
|
49 |
+ Handler: admission.NewHandler(admission.Create), |
|
50 |
+ defaultsConfig: defaultsConfig, |
|
51 |
+ } |
|
52 |
+} |
|
53 |
+ |
|
54 |
+// Admit applies configured build defaults to a pod that is identified |
|
55 |
+// as a build pod. |
|
56 |
+func (a *buildDefaults) Admit(attributes admission.Attributes) error { |
|
57 |
+ if a.defaultsConfig == nil { |
|
58 |
+ return nil |
|
59 |
+ } |
|
60 |
+ if !buildadmission.IsBuildPod(attributes) { |
|
61 |
+ return nil |
|
62 |
+ } |
|
63 |
+ build, version, err := buildadmission.GetBuild(attributes) |
|
64 |
+ if err != nil { |
|
65 |
+ return nil |
|
66 |
+ } |
|
67 |
+ |
|
68 |
+ glog.V(4).Infof("Handling build %s/%s", build.Namespace, build.Name) |
|
69 |
+ |
|
70 |
+ a.applyBuildDefaults(build) |
|
71 |
+ |
|
72 |
+ return buildadmission.SetBuild(attributes, build, version) |
|
73 |
+} |
|
74 |
+ |
|
75 |
+func (a *buildDefaults) applyBuildDefaults(build *buildapi.Build) { |
|
76 |
+ // Apply default env |
|
77 |
+ buildEnv := getBuildEnv(build) |
|
78 |
+ for _, envVar := range a.defaultsConfig.Env { |
|
79 |
+ glog.V(5).Infof("Adding default environment variable %s=%s to build %s/%s", envVar.Name, envVar.Value, build.Namespace, build.Name) |
|
80 |
+ addDefaultEnvVar(envVar, buildEnv) |
|
81 |
+ } |
|
82 |
+ |
|
83 |
+ // Apply git proxy defaults |
|
84 |
+ if build.Spec.Source.Git == nil { |
|
85 |
+ return |
|
86 |
+ } |
|
87 |
+ if len(a.defaultsConfig.GitHTTPProxy) != 0 { |
|
88 |
+ if build.Spec.Source.Git.HTTPProxy == nil { |
|
89 |
+ t := a.defaultsConfig.GitHTTPProxy |
|
90 |
+ glog.V(5).Infof("Setting default Git HTTP proxy of build %s/%s to %s", build.Namespace, build.Name, t) |
|
91 |
+ build.Spec.Source.Git.HTTPProxy = &t |
|
92 |
+ } |
|
93 |
+ } |
|
94 |
+ |
|
95 |
+ if len(a.defaultsConfig.GitHTTPSProxy) != 0 { |
|
96 |
+ if build.Spec.Source.Git.HTTPSProxy == nil { |
|
97 |
+ t := a.defaultsConfig.GitHTTPSProxy |
|
98 |
+ glog.V(5).Infof("Setting default Git HTTPS proxy of build %s/%s to %s", build.Namespace, build.Name, t) |
|
99 |
+ build.Spec.Source.Git.HTTPSProxy = &t |
|
100 |
+ } |
|
101 |
+ } |
|
102 |
+} |
|
103 |
+ |
|
104 |
+func getBuildEnv(build *buildapi.Build) *[]kapi.EnvVar { |
|
105 |
+ switch { |
|
106 |
+ case build.Spec.Strategy.DockerStrategy != nil: |
|
107 |
+ return &build.Spec.Strategy.DockerStrategy.Env |
|
108 |
+ case build.Spec.Strategy.SourceStrategy != nil: |
|
109 |
+ return &build.Spec.Strategy.SourceStrategy.Env |
|
110 |
+ case build.Spec.Strategy.CustomStrategy != nil: |
|
111 |
+ return &build.Spec.Strategy.CustomStrategy.Env |
|
112 |
+ } |
|
113 |
+ return nil |
|
114 |
+} |
|
115 |
+ |
|
116 |
+func addDefaultEnvVar(v kapi.EnvVar, envVars *[]kapi.EnvVar) { |
|
117 |
+ found := false |
|
118 |
+ for i := range *envVars { |
|
119 |
+ if (*envVars)[i].Name == v.Name { |
|
120 |
+ found = true |
|
121 |
+ } |
|
122 |
+ } |
|
123 |
+ if !found { |
|
124 |
+ *envVars = append(*envVars, v) |
|
125 |
+ } |
|
126 |
+} |
0 | 127 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,84 @@ |
0 |
+package defaults |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "testing" |
|
4 |
+ |
|
5 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
6 |
+ |
|
7 |
+ buildadmission "github.com/openshift/origin/pkg/build/admission" |
|
8 |
+ u "github.com/openshift/origin/pkg/build/admission/testutil" |
|
9 |
+) |
|
10 |
+ |
|
11 |
+func TestProxyDefaults(t *testing.T) { |
|
12 |
+ defaultsConfig := &BuildDefaultsConfig{ |
|
13 |
+ GitHTTPProxy: "http", |
|
14 |
+ GitHTTPSProxy: "https", |
|
15 |
+ } |
|
16 |
+ |
|
17 |
+ admitter := NewBuildDefaults(defaultsConfig) |
|
18 |
+ pod := u.Pod().WithBuild(t, u.Build().WithDockerStrategy().AsBuild(), "v1") |
|
19 |
+ err := admitter.Admit(pod.ToAttributes()) |
|
20 |
+ if err != nil { |
|
21 |
+ t.Fatalf("unexpected error: %v", err) |
|
22 |
+ } |
|
23 |
+ build, _, err := buildadmission.GetBuild(pod.ToAttributes()) |
|
24 |
+ if err != nil { |
|
25 |
+ t.Fatalf("unexpected error: %v", err) |
|
26 |
+ } |
|
27 |
+ |
|
28 |
+ if build.Spec.Source.Git.HTTPProxy == nil || len(*build.Spec.Source.Git.HTTPProxy) == 0 || *build.Spec.Source.Git.HTTPProxy != "http" { |
|
29 |
+ t.Errorf("failed to find http proxy in git source") |
|
30 |
+ } |
|
31 |
+ if build.Spec.Source.Git.HTTPSProxy == nil || len(*build.Spec.Source.Git.HTTPSProxy) == 0 || *build.Spec.Source.Git.HTTPSProxy != "https" { |
|
32 |
+ t.Errorf("failed to find http proxy in git source") |
|
33 |
+ } |
|
34 |
+} |
|
35 |
+ |
|
36 |
+func TestEnvDefaults(t *testing.T) { |
|
37 |
+ defaultsConfig := &BuildDefaultsConfig{ |
|
38 |
+ Env: []kapi.EnvVar{ |
|
39 |
+ { |
|
40 |
+ Name: "VAR1", |
|
41 |
+ Value: "VALUE1", |
|
42 |
+ }, |
|
43 |
+ { |
|
44 |
+ Name: "VAR2", |
|
45 |
+ Value: "VALUE2", |
|
46 |
+ }, |
|
47 |
+ }, |
|
48 |
+ } |
|
49 |
+ |
|
50 |
+ admitter := NewBuildDefaults(defaultsConfig) |
|
51 |
+ pod := u.Pod().WithBuild(t, u.Build().WithSourceStrategy().AsBuild(), "v1") |
|
52 |
+ err := admitter.Admit(pod.ToAttributes()) |
|
53 |
+ if err != nil { |
|
54 |
+ t.Fatalf("unexpected error: %v", err) |
|
55 |
+ } |
|
56 |
+ build, _, err := buildadmission.GetBuild(pod.ToAttributes()) |
|
57 |
+ if err != nil { |
|
58 |
+ t.Fatalf("unexpected error: %v", err) |
|
59 |
+ } |
|
60 |
+ |
|
61 |
+ env := getBuildEnv(build) |
|
62 |
+ var1found, var2found := false, false |
|
63 |
+ for _, ev := range *env { |
|
64 |
+ if ev.Name == "VAR1" { |
|
65 |
+ if ev.Value != "VALUE1" { |
|
66 |
+ t.Errorf("unexpected value %s", ev.Value) |
|
67 |
+ } |
|
68 |
+ var1found = true |
|
69 |
+ } |
|
70 |
+ if ev.Name == "VAR2" { |
|
71 |
+ if ev.Value != "VALUE2" { |
|
72 |
+ t.Errorf("unexpected value %s", ev.Value) |
|
73 |
+ } |
|
74 |
+ var2found = true |
|
75 |
+ } |
|
76 |
+ } |
|
77 |
+ if !var1found { |
|
78 |
+ t.Errorf("VAR1 not found") |
|
79 |
+ } |
|
80 |
+ if !var2found { |
|
81 |
+ t.Errorf("VAR2 not found") |
|
82 |
+ } |
|
83 |
+} |
0 | 84 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,22 @@ |
0 |
+/* |
|
1 |
+Package defaults contains the BuildDefaults admission control plugin. |
|
2 |
+ |
|
3 |
+The plugin allows setting default values for build setings like the git HTTP |
|
4 |
+and HTTPS proxy URLs and additional environment variables for the build |
|
5 |
+strategy |
|
6 |
+ |
|
7 |
+Configuration |
|
8 |
+ |
|
9 |
+Configuration is done via a BuildDefaultsConfig object: |
|
10 |
+ |
|
11 |
+ apiVersion: v1 |
|
12 |
+ kind: BuildDefaultsConfiguration |
|
13 |
+ gitHTTPProxy: http://my.proxy.server:12345 |
|
14 |
+ gitHTTPSProxy: https://my.proxy.server:7890 |
|
15 |
+ env: |
|
16 |
+ - name: ENV_VAR1 |
|
17 |
+ value: VALUE1 |
|
18 |
+ - name: ENV_VAR2 |
|
19 |
+ value: VALUE2 |
|
20 |
+*/ |
|
21 |
+package defaults |
0 | 5 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,29 @@ |
0 |
+package defaults |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "k8s.io/kubernetes/pkg/api/unversioned" |
|
4 |
+ |
|
5 |
+ _ "github.com/openshift/origin/pkg/build/admission/defaults/latest" |
|
6 |
+ "github.com/openshift/origin/pkg/cmd/server/api" |
|
7 |
+) |
|
8 |
+ |
|
9 |
+// SchemeGroupVersion is group version used to register these objects |
|
10 |
+var SchemeGroupVersion = unversioned.GroupVersion{Group: "", Version: ""} |
|
11 |
+ |
|
12 |
+// Kind takes an unqualified kind and returns back a Group qualified GroupKind |
|
13 |
+func Kind(kind string) unversioned.GroupKind { |
|
14 |
+ return SchemeGroupVersion.WithKind(kind).GroupKind() |
|
15 |
+} |
|
16 |
+ |
|
17 |
+// Resource takes an unqualified resource and returns back a Group qualified GroupResource |
|
18 |
+func Resource(resource string) unversioned.GroupResource { |
|
19 |
+ return SchemeGroupVersion.WithResource(resource).GroupResource() |
|
20 |
+} |
|
21 |
+ |
|
22 |
+func init() { |
|
23 |
+ api.Scheme.AddKnownTypes(SchemeGroupVersion, |
|
24 |
+ &BuildDefaultsConfig{}, |
|
25 |
+ ) |
|
26 |
+} |
|
27 |
+ |
|
28 |
+func (*BuildDefaultsConfig) IsAnAPIObject() {} |
0 | 29 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,21 @@ |
0 |
+package defaults |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
4 |
+ "k8s.io/kubernetes/pkg/api/unversioned" |
|
5 |
+) |
|
6 |
+ |
|
7 |
+// BuildDefaultsConfig controls the default information for Builds |
|
8 |
+type BuildDefaultsConfig struct { |
|
9 |
+ unversioned.TypeMeta |
|
10 |
+ |
|
11 |
+ // GitHTTPProxy is the location of the HTTPProxy for Git source |
|
12 |
+ GitHTTPProxy string |
|
13 |
+ |
|
14 |
+ // GitHTTPSProxy is the location of the HTTPSProxy for Git source |
|
15 |
+ GitHTTPSProxy string |
|
16 |
+ |
|
17 |
+ // Env is a set of default environment variables that will be applied to the |
|
18 |
+ // build if the specified variables do not exist on the build |
|
19 |
+ Env []kapi.EnvVar |
|
20 |
+} |
0 | 21 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,18 @@ |
0 |
+package v1 |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "k8s.io/kubernetes/pkg/api/unversioned" |
|
4 |
+ |
|
5 |
+ "github.com/openshift/origin/pkg/cmd/server/api" |
|
6 |
+) |
|
7 |
+ |
|
8 |
+// SchemeGroupVersion is group version used to register these objects |
|
9 |
+var SchemeGroupVersion = unversioned.GroupVersion{Group: "", Version: "v1"} |
|
10 |
+ |
|
11 |
+func init() { |
|
12 |
+ api.Scheme.AddKnownTypes(SchemeGroupVersion, |
|
13 |
+ &BuildDefaultsConfig{}, |
|
14 |
+ ) |
|
15 |
+} |
|
16 |
+ |
|
17 |
+func (*BuildDefaultsConfig) IsAnAPIObject() {} |
0 | 18 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,21 @@ |
0 |
+package v1 |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
4 |
+ "k8s.io/kubernetes/pkg/api/unversioned" |
|
5 |
+) |
|
6 |
+ |
|
7 |
+// BuildDefaultsConfig controls the default information for Builds |
|
8 |
+type BuildDefaultsConfig struct { |
|
9 |
+ unversioned.TypeMeta |
|
10 |
+ |
|
11 |
+ // GitHTTPProxy is the location of the HTTPProxy for Git source |
|
12 |
+ GitHTTPProxy string `json:"gitHTTPProxy,omitempty",description:"location of the git http proxy"` |
|
13 |
+ |
|
14 |
+ // GitHTTPSProxy is the location of the HTTPSProxy for Git source |
|
15 |
+ GitHTTPSProxy string `json:"gitHTTPSProxy,omitempty",description:"location of the git https proxy"` |
|
16 |
+ |
|
17 |
+ // Env is a set of default environment variables that will be applied to the |
|
18 |
+ // build if the specified variables do not exist on the build |
|
19 |
+ Env []kapi.EnvVar `json:"env,omitempty",description:"default environment variable values to add to builds"` |
|
20 |
+} |
0 | 21 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,25 @@ |
0 |
+package defaults |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "k8s.io/kubernetes/pkg/util/validation/field" |
|
4 |
+ |
|
5 |
+ buildvalidation "github.com/openshift/origin/pkg/build/api/validation" |
|
6 |
+) |
|
7 |
+ |
|
8 |
+// ValidateBuild tests required fields for a Build. |
|
9 |
+func ValidateBuildDefaultsConfig(config *BuildDefaultsConfig) field.ErrorList { |
|
10 |
+ allErrs := field.ErrorList{} |
|
11 |
+ allErrs = append(allErrs, validateURL(config.GitHTTPProxy, field.NewPath("gitHTTPProxy"))...) |
|
12 |
+ allErrs = append(allErrs, validateURL(config.GitHTTPSProxy, field.NewPath("gitHTTPSProxy"))...) |
|
13 |
+ allErrs = append(allErrs, buildvalidation.ValidateStrategyEnv(config.Env, field.NewPath("env"))...) |
|
14 |
+ return allErrs |
|
15 |
+} |
|
16 |
+ |
|
17 |
+// |
|
18 |
+func validateURL(u string, path *field.Path) field.ErrorList { |
|
19 |
+ allErrs := field.ErrorList{} |
|
20 |
+ if !buildvalidation.IsValidURL(u) { |
|
21 |
+ allErrs = append(allErrs, field.Invalid(path, u, "invalid URL")) |
|
22 |
+ } |
|
23 |
+ return allErrs |
|
24 |
+} |
0 | 25 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,120 @@ |
0 |
+package defaults |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "testing" |
|
4 |
+ |
|
5 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
6 |
+ "k8s.io/kubernetes/pkg/util/validation/field" |
|
7 |
+) |
|
8 |
+ |
|
9 |
+func TestValidateBuildDefaultsConfig(t *testing.T) { |
|
10 |
+ tests := []struct { |
|
11 |
+ config *BuildDefaultsConfig |
|
12 |
+ errExpected bool |
|
13 |
+ errField string |
|
14 |
+ errType field.ErrorType |
|
15 |
+ }{ |
|
16 |
+ // 0: Valid config |
|
17 |
+ { |
|
18 |
+ config: &BuildDefaultsConfig{ |
|
19 |
+ GitHTTPProxy: "http://valid.url", |
|
20 |
+ GitHTTPSProxy: "https://valid.url", |
|
21 |
+ Env: []kapi.EnvVar{ |
|
22 |
+ { |
|
23 |
+ Name: "VAR1", |
|
24 |
+ Value: "VALUE1", |
|
25 |
+ }, |
|
26 |
+ { |
|
27 |
+ Name: "VAR2", |
|
28 |
+ Value: "VALUE2", |
|
29 |
+ }, |
|
30 |
+ }, |
|
31 |
+ }, |
|
32 |
+ errExpected: false, |
|
33 |
+ }, |
|
34 |
+ // 1: invalid HTTP proxy |
|
35 |
+ { |
|
36 |
+ config: &BuildDefaultsConfig{ |
|
37 |
+ GitHTTPProxy: "some!@#$%^&*()url", |
|
38 |
+ GitHTTPSProxy: "https://valid.url", |
|
39 |
+ }, |
|
40 |
+ errExpected: true, |
|
41 |
+ errField: "gitHTTPProxy", |
|
42 |
+ errType: field.ErrorTypeInvalid, |
|
43 |
+ }, |
|
44 |
+ // 2: invalid HTTPS proxy |
|
45 |
+ { |
|
46 |
+ config: &BuildDefaultsConfig{ |
|
47 |
+ GitHTTPProxy: "https://valid.url", |
|
48 |
+ GitHTTPSProxy: "some!@#$%^&*()url", |
|
49 |
+ }, |
|
50 |
+ errExpected: true, |
|
51 |
+ errField: "gitHTTPSProxy", |
|
52 |
+ errType: field.ErrorTypeInvalid, |
|
53 |
+ }, |
|
54 |
+ // 3: missing Env variable name |
|
55 |
+ { |
|
56 |
+ config: &BuildDefaultsConfig{ |
|
57 |
+ Env: []kapi.EnvVar{ |
|
58 |
+ { |
|
59 |
+ Name: "", |
|
60 |
+ Value: "test", |
|
61 |
+ }, |
|
62 |
+ }, |
|
63 |
+ }, |
|
64 |
+ errExpected: true, |
|
65 |
+ errField: "env[0].name", |
|
66 |
+ errType: field.ErrorTypeRequired, |
|
67 |
+ }, |
|
68 |
+ // 4: invalid Env variable name |
|
69 |
+ { |
|
70 |
+ config: &BuildDefaultsConfig{ |
|
71 |
+ Env: []kapi.EnvVar{ |
|
72 |
+ { |
|
73 |
+ Name: " invalid,name", |
|
74 |
+ Value: "test", |
|
75 |
+ }, |
|
76 |
+ }, |
|
77 |
+ }, |
|
78 |
+ errExpected: true, |
|
79 |
+ errField: "env[0].name", |
|
80 |
+ errType: field.ErrorTypeInvalid, |
|
81 |
+ }, |
|
82 |
+ // 5: valueFrom present in env var |
|
83 |
+ { |
|
84 |
+ config: &BuildDefaultsConfig{ |
|
85 |
+ Env: []kapi.EnvVar{ |
|
86 |
+ { |
|
87 |
+ Name: "name", |
|
88 |
+ Value: "test", |
|
89 |
+ ValueFrom: &kapi.EnvVarSource{}, |
|
90 |
+ }, |
|
91 |
+ }, |
|
92 |
+ }, |
|
93 |
+ errExpected: true, |
|
94 |
+ errField: "env[0].valueFrom", |
|
95 |
+ errType: field.ErrorTypeInvalid, |
|
96 |
+ }, |
|
97 |
+ } |
|
98 |
+ |
|
99 |
+ for i, tc := range tests { |
|
100 |
+ result := ValidateBuildDefaultsConfig(tc.config) |
|
101 |
+ if !tc.errExpected { |
|
102 |
+ if len(result) > 0 { |
|
103 |
+ t.Errorf("%d: unexpected error: %v", i, result.ToAggregate()) |
|
104 |
+ } |
|
105 |
+ continue |
|
106 |
+ } |
|
107 |
+ if tc.errExpected && len(result) == 0 { |
|
108 |
+ t.Errorf("%d: did not get expected error", i) |
|
109 |
+ continue |
|
110 |
+ } |
|
111 |
+ err := result[0] |
|
112 |
+ if err.Type != tc.errType { |
|
113 |
+ t.Errorf("%d: unexpected error type: %v", i, err.Type) |
|
114 |
+ } |
|
115 |
+ if err.Field != tc.errField { |
|
116 |
+ t.Errorf("%d: unexpected error field: %v", i, err.Field) |
|
117 |
+ } |
|
118 |
+ } |
|
119 |
+} |
0 | 120 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,8 @@ |
0 |
+/* |
|
1 |
+Package admission contains admission control plugins that work with builds or |
|
2 |
+pods that are running builds. |
|
3 |
+ |
|
4 |
+Each admission control plugin has its own sub package. Common utilities live directly |
|
5 |
+in this package. |
|
6 |
+*/ |
|
7 |
+package admission |
0 | 8 |
deleted file mode 100644 |
... | ... |
@@ -1,134 +0,0 @@ |
1 |
-package httpproxy |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "fmt" |
|
5 |
- "io" |
|
6 |
- "io/ioutil" |
|
7 |
- "reflect" |
|
8 |
- |
|
9 |
- "k8s.io/kubernetes/pkg/admission" |
|
10 |
- kapi "k8s.io/kubernetes/pkg/api" |
|
11 |
- kclient "k8s.io/kubernetes/pkg/client/unversioned" |
|
12 |
- |
|
13 |
- buildapi "github.com/openshift/origin/pkg/build/api" |
|
14 |
- configlatest "github.com/openshift/origin/pkg/cmd/server/api/latest" |
|
15 |
-) |
|
16 |
- |
|
17 |
-func init() { |
|
18 |
- admission.RegisterPlugin("BuildHTTPProxy", func(c kclient.Interface, config io.Reader) (admission.Interface, error) { |
|
19 |
- proxyConfig, err := readConfig(config) |
|
20 |
- if err != nil { |
|
21 |
- return nil, err |
|
22 |
- } |
|
23 |
- |
|
24 |
- return NewBuildHTTPProxy(proxyConfig), nil |
|
25 |
- }) |
|
26 |
-} |
|
27 |
- |
|
28 |
-func readConfig(reader io.Reader) (*ProxyConfig, error) { |
|
29 |
- if reader == nil || reflect.ValueOf(reader).IsNil() { |
|
30 |
- return nil, nil |
|
31 |
- } |
|
32 |
- |
|
33 |
- configBytes, err := ioutil.ReadAll(reader) |
|
34 |
- if err != nil { |
|
35 |
- return nil, err |
|
36 |
- } |
|
37 |
- config := &ProxyConfig{} |
|
38 |
- err = configlatest.ReadYAML(configBytes, config) |
|
39 |
- if err != nil { |
|
40 |
- return nil, err |
|
41 |
- } |
|
42 |
- return config, nil |
|
43 |
-} |
|
44 |
- |
|
45 |
-type buildHTTPProxy struct { |
|
46 |
- *admission.Handler |
|
47 |
- proxyConfig *ProxyConfig |
|
48 |
-} |
|
49 |
- |
|
50 |
-// NewBuildHTTPProxy returns an admission control for builds that checks |
|
51 |
-// on policy based on the build strategy type |
|
52 |
-func NewBuildHTTPProxy(proxyConfig *ProxyConfig) admission.Interface { |
|
53 |
- return &buildHTTPProxy{ |
|
54 |
- Handler: admission.NewHandler(admission.Create, admission.Update), |
|
55 |
- proxyConfig: proxyConfig, |
|
56 |
- } |
|
57 |
-} |
|
58 |
- |
|
59 |
-func (a *buildHTTPProxy) Admit(attributes admission.Attributes) error { |
|
60 |
- if a.proxyConfig == nil { |
|
61 |
- return nil |
|
62 |
- } |
|
63 |
- if attributes.GetResource() != "buildconfigs" { |
|
64 |
- return nil |
|
65 |
- } |
|
66 |
- if len(attributes.GetSubresource()) != 0 { |
|
67 |
- return nil |
|
68 |
- } |
|
69 |
- |
|
70 |
- buildConfig, ok := attributes.GetObject().(*buildapi.BuildConfig) |
|
71 |
- if !ok { |
|
72 |
- return admission.NewForbidden(attributes, fmt.Errorf("unrecognized request object %#v", attributes.GetObject())) |
|
73 |
- } |
|
74 |
- |
|
75 |
- if len(a.proxyConfig.HTTPProxy) != 0 { |
|
76 |
- var envVars *[]kapi.EnvVar |
|
77 |
- switch { |
|
78 |
- case buildConfig.Spec.Strategy.DockerStrategy != nil: |
|
79 |
- envVars = &buildConfig.Spec.Strategy.DockerStrategy.Env |
|
80 |
- case buildConfig.Spec.Strategy.SourceStrategy != nil: |
|
81 |
- envVars = &buildConfig.Spec.Strategy.SourceStrategy.Env |
|
82 |
- case buildConfig.Spec.Strategy.CustomStrategy != nil: |
|
83 |
- envVars = &buildConfig.Spec.Strategy.CustomStrategy.Env |
|
84 |
- } |
|
85 |
- |
|
86 |
- found := false |
|
87 |
- for i := range *envVars { |
|
88 |
- if (*envVars)[i].Name == "HTTP_PROXY" { |
|
89 |
- found = true |
|
90 |
- } |
|
91 |
- } |
|
92 |
- if !found { |
|
93 |
- *envVars = append(*envVars, kapi.EnvVar{Name: "HTTP_PROXY", Value: a.proxyConfig.HTTPProxy}) |
|
94 |
- } |
|
95 |
- |
|
96 |
- if buildConfig.Spec.Source.Git != nil { |
|
97 |
- if buildConfig.Spec.Source.Git.HTTPProxy == nil { |
|
98 |
- t := a.proxyConfig.HTTPProxy |
|
99 |
- buildConfig.Spec.Source.Git.HTTPProxy = &t |
|
100 |
- } |
|
101 |
- } |
|
102 |
- } |
|
103 |
- |
|
104 |
- if len(a.proxyConfig.HTTPSProxy) != 0 { |
|
105 |
- var envVars *[]kapi.EnvVar |
|
106 |
- switch { |
|
107 |
- case buildConfig.Spec.Strategy.DockerStrategy != nil: |
|
108 |
- envVars = &buildConfig.Spec.Strategy.DockerStrategy.Env |
|
109 |
- case buildConfig.Spec.Strategy.SourceStrategy != nil: |
|
110 |
- envVars = &buildConfig.Spec.Strategy.SourceStrategy.Env |
|
111 |
- case buildConfig.Spec.Strategy.CustomStrategy != nil: |
|
112 |
- envVars = &buildConfig.Spec.Strategy.CustomStrategy.Env |
|
113 |
- } |
|
114 |
- |
|
115 |
- found := false |
|
116 |
- for i := range *envVars { |
|
117 |
- if (*envVars)[i].Name == "HTTPS_PROXY" { |
|
118 |
- found = true |
|
119 |
- } |
|
120 |
- } |
|
121 |
- if !found { |
|
122 |
- *envVars = append(*envVars, kapi.EnvVar{Name: "HTTPS_PROXY", Value: a.proxyConfig.HTTPSProxy}) |
|
123 |
- } |
|
124 |
- |
|
125 |
- if buildConfig.Spec.Source.Git != nil { |
|
126 |
- if buildConfig.Spec.Source.Git.HTTPSProxy == nil { |
|
127 |
- t := a.proxyConfig.HTTPSProxy |
|
128 |
- buildConfig.Spec.Source.Git.HTTPSProxy = &t |
|
129 |
- } |
|
130 |
- } |
|
131 |
- } |
|
132 |
- |
|
133 |
- return nil |
|
134 |
-} |
135 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,65 +0,0 @@ |
1 |
-package httpproxy |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "testing" |
|
5 |
- |
|
6 |
- "k8s.io/kubernetes/pkg/admission" |
|
7 |
- |
|
8 |
- buildapi "github.com/openshift/origin/pkg/build/api" |
|
9 |
-) |
|
10 |
- |
|
11 |
-func TestSubstitution(t *testing.T) { |
|
12 |
- proxyConfig := &ProxyConfig{ |
|
13 |
- HTTPProxy: "http", |
|
14 |
- HTTPSProxy: "https", |
|
15 |
- } |
|
16 |
- |
|
17 |
- admitter := NewBuildHTTPProxy(proxyConfig) |
|
18 |
- |
|
19 |
- bc := &buildapi.BuildConfig{ |
|
20 |
- Spec: buildapi.BuildConfigSpec{ |
|
21 |
- BuildSpec: buildapi.BuildSpec{ |
|
22 |
- Source: buildapi.BuildSource{ |
|
23 |
- Git: &buildapi.GitBuildSource{}, |
|
24 |
- }, |
|
25 |
- Strategy: buildapi.BuildStrategy{ |
|
26 |
- DockerStrategy: &buildapi.DockerBuildStrategy{}, |
|
27 |
- }, |
|
28 |
- }, |
|
29 |
- }, |
|
30 |
- } |
|
31 |
- |
|
32 |
- attributes := admission.NewAttributesRecord(bc, "BuildConfig", "default", "name", "buildconfigs", "", admission.Create, nil) |
|
33 |
- err := admitter.Admit(attributes) |
|
34 |
- if err != nil { |
|
35 |
- t.Fatalf("unexpected error: %v", err) |
|
36 |
- } |
|
37 |
- |
|
38 |
- foundHTTP := false |
|
39 |
- for _, envVar := range bc.Spec.Strategy.DockerStrategy.Env { |
|
40 |
- if envVar.Name == "HTTP_PROXY" && envVar.Value == "http" { |
|
41 |
- foundHTTP = true |
|
42 |
- } |
|
43 |
- } |
|
44 |
- if !foundHTTP { |
|
45 |
- t.Errorf("failed to find http proxy in %v", bc.Spec.Strategy.DockerStrategy.Env) |
|
46 |
- } |
|
47 |
- |
|
48 |
- foundHTTPS := false |
|
49 |
- for _, envVar := range bc.Spec.Strategy.DockerStrategy.Env { |
|
50 |
- if envVar.Name == "HTTPS_PROXY" && envVar.Value == "https" { |
|
51 |
- foundHTTPS = true |
|
52 |
- } |
|
53 |
- } |
|
54 |
- if !foundHTTPS { |
|
55 |
- t.Errorf("failed to find https proxy in %v", bc.Spec.Strategy.DockerStrategy.Env) |
|
56 |
- } |
|
57 |
- |
|
58 |
- if bc.Spec.Source.Git.HTTPProxy == nil || len(*bc.Spec.Source.Git.HTTPProxy) == 0 || *bc.Spec.Source.Git.HTTPProxy != "http" { |
|
59 |
- t.Errorf("failed to find http proxy in git source") |
|
60 |
- } |
|
61 |
- if bc.Spec.Source.Git.HTTPSProxy == nil || len(*bc.Spec.Source.Git.HTTPSProxy) == 0 || *bc.Spec.Source.Git.HTTPSProxy != "https" { |
|
62 |
- t.Errorf("failed to find http proxy in git source") |
|
63 |
- } |
|
64 |
- |
|
65 |
-} |
6 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,14 +0,0 @@ |
1 |
-package httpproxy |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- _ "github.com/openshift/origin/pkg/build/admission/httpproxy/latest" |
|
5 |
- "github.com/openshift/origin/pkg/cmd/server/api" |
|
6 |
-) |
|
7 |
- |
|
8 |
-func init() { |
|
9 |
- api.Scheme.AddKnownTypes("", |
|
10 |
- &ProxyConfig{}, |
|
11 |
- ) |
|
12 |
-} |
|
13 |
- |
|
14 |
-func (*ProxyConfig) IsAnAPIObject() {} |
15 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,16 +0,0 @@ |
1 |
-package httpproxy |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "k8s.io/kubernetes/pkg/api/unversioned" |
|
5 |
-) |
|
6 |
- |
|
7 |
-// ProxyConfig controls the proxy information for BuildConfigs |
|
8 |
-type ProxyConfig struct { |
|
9 |
- unversioned.TypeMeta |
|
10 |
- |
|
11 |
- // HTTPProxy is the location of the HTTPProxy |
|
12 |
- HTTPProxy string |
|
13 |
- |
|
14 |
- // HTTPSProxy is the location of the HTTPSProxy |
|
15 |
- HTTPSProxy string |
|
16 |
-} |
14 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,16 +0,0 @@ |
1 |
-package v1 |
|
2 |
- |
|
3 |
-import ( |
|
4 |
- "k8s.io/kubernetes/pkg/api/unversioned" |
|
5 |
-) |
|
6 |
- |
|
7 |
-// ProxyConfig controls the proxy information for BuildConfigs |
|
8 |
-type ProxyConfig struct { |
|
9 |
- unversioned.TypeMeta |
|
10 |
- |
|
11 |
- // HTTPProxy is the location of the HTTPProxy |
|
12 |
- HTTPProxy string `json:"httpProxy",description:"location of the global http proxy"` |
|
13 |
- |
|
14 |
- // HTTPSProxy is the location of the HTTPSProxy |
|
15 |
- HTTPSProxy string `json:"httpsProxy",description:"location of the global https proxy"` |
|
16 |
-} |
17 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,98 @@ |
0 |
+package overrides |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "io" |
|
4 |
+ |
|
5 |
+ "github.com/golang/glog" |
|
6 |
+ "k8s.io/kubernetes/pkg/admission" |
|
7 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
8 |
+ kclient "k8s.io/kubernetes/pkg/client/unversioned" |
|
9 |
+ |
|
10 |
+ buildadmission "github.com/openshift/origin/pkg/build/admission" |
|
11 |
+) |
|
12 |
+ |
|
13 |
+func init() { |
|
14 |
+ admission.RegisterPlugin("BuildOverrides", func(c kclient.Interface, config io.Reader) (admission.Interface, error) { |
|
15 |
+ overridesConfig, err := getConfig(config) |
|
16 |
+ if err != nil { |
|
17 |
+ return nil, err |
|
18 |
+ } |
|
19 |
+ |
|
20 |
+ glog.V(4).Infof("Initializing BuildOverrides plugin with config: %#v", overridesConfig) |
|
21 |
+ return NewBuildOverrides(overridesConfig), nil |
|
22 |
+ }) |
|
23 |
+} |
|
24 |
+ |
|
25 |
+func getConfig(in io.Reader) (*BuildOverridesConfig, error) { |
|
26 |
+ overridesConfig := &BuildOverridesConfig{} |
|
27 |
+ err := buildadmission.ReadPluginConfig(in, overridesConfig) |
|
28 |
+ if err != nil { |
|
29 |
+ return nil, err |
|
30 |
+ } |
|
31 |
+ return overridesConfig, nil |
|
32 |
+} |
|
33 |
+ |
|
34 |
+type buildOverrides struct { |
|
35 |
+ *admission.Handler |
|
36 |
+ overridesConfig *BuildOverridesConfig |
|
37 |
+} |
|
38 |
+ |
|
39 |
+// NewBuildOverrides returns an admission control for builds that overrides |
|
40 |
+// settings on builds |
|
41 |
+func NewBuildOverrides(overridesConfig *BuildOverridesConfig) admission.Interface { |
|
42 |
+ return &buildOverrides{ |
|
43 |
+ Handler: admission.NewHandler(admission.Create, admission.Update), |
|
44 |
+ overridesConfig: overridesConfig, |
|
45 |
+ } |
|
46 |
+} |
|
47 |
+ |
|
48 |
+// Admit appplies configured overrides to a build in a build pod |
|
49 |
+func (a *buildOverrides) Admit(attributes admission.Attributes) error { |
|
50 |
+ if a.overridesConfig == nil { |
|
51 |
+ return nil |
|
52 |
+ } |
|
53 |
+ if !buildadmission.IsBuildPod(attributes) { |
|
54 |
+ return nil |
|
55 |
+ } |
|
56 |
+ return a.applyOverrides(attributes) |
|
57 |
+} |
|
58 |
+ |
|
59 |
+func (a *buildOverrides) applyOverrides(attributes admission.Attributes) error { |
|
60 |
+ if !a.overridesConfig.ForcePull { |
|
61 |
+ return nil |
|
62 |
+ } |
|
63 |
+ build, version, err := buildadmission.GetBuild(attributes) |
|
64 |
+ if err != nil { |
|
65 |
+ return err |
|
66 |
+ } |
|
67 |
+ glog.V(4).Infof("Handling build %s/%s", build.Namespace, build.Name) |
|
68 |
+ if build.Spec.Strategy.DockerStrategy != nil { |
|
69 |
+ glog.V(5).Infof("Setting docker strategy ForcePull to true in build %s/%s", build.Namespace, build.Name) |
|
70 |
+ build.Spec.Strategy.DockerStrategy.ForcePull = true |
|
71 |
+ } |
|
72 |
+ if build.Spec.Strategy.SourceStrategy != nil { |
|
73 |
+ glog.V(5).Infof("Setting source strategy ForcePull to true in build %s/%s", build.Namespace, build.Name) |
|
74 |
+ build.Spec.Strategy.SourceStrategy.ForcePull = true |
|
75 |
+ } |
|
76 |
+ if build.Spec.Strategy.CustomStrategy != nil { |
|
77 |
+ err := applyForcePullToPod(attributes) |
|
78 |
+ if err != nil { |
|
79 |
+ return err |
|
80 |
+ } |
|
81 |
+ glog.V(5).Infof("Setting custom strategy ForcePull to true in build %s/%s", build.Namespace, build.Name) |
|
82 |
+ build.Spec.Strategy.CustomStrategy.ForcePull = true |
|
83 |
+ } |
|
84 |
+ return buildadmission.SetBuild(attributes, build, version) |
|
85 |
+} |
|
86 |
+ |
|
87 |
+func applyForcePullToPod(attributes admission.Attributes) error { |
|
88 |
+ pod, err := buildadmission.GetPod(attributes) |
|
89 |
+ if err != nil { |
|
90 |
+ return err |
|
91 |
+ } |
|
92 |
+ for i := range pod.Spec.Containers { |
|
93 |
+ glog.V(5).Infof("Setting ImagePullPolicy to PullAlways on container %s of pod %s/%s", pod.Spec.Containers[i].Name, pod.Namespace, pod.Name) |
|
94 |
+ pod.Spec.Containers[i].ImagePullPolicy = kapi.PullAlways |
|
95 |
+ } |
|
96 |
+ return nil |
|
97 |
+} |
0 | 98 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,62 @@ |
0 |
+package overrides |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "testing" |
|
4 |
+ |
|
5 |
+ "k8s.io/kubernetes/pkg/admission" |
|
6 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
7 |
+ |
|
8 |
+ u "github.com/openshift/origin/pkg/build/admission/testutil" |
|
9 |
+ buildapi "github.com/openshift/origin/pkg/build/api" |
|
10 |
+) |
|
11 |
+ |
|
12 |
+func TestBuildOverrideForcePull(t *testing.T) { |
|
13 |
+ tests := []struct { |
|
14 |
+ name string |
|
15 |
+ build *buildapi.Build |
|
16 |
+ }{ |
|
17 |
+ { |
|
18 |
+ name: "build - custom", |
|
19 |
+ build: u.Build().WithCustomStrategy().AsBuild(), |
|
20 |
+ }, |
|
21 |
+ { |
|
22 |
+ name: "build - docker", |
|
23 |
+ build: u.Build().WithDockerStrategy().AsBuild(), |
|
24 |
+ }, |
|
25 |
+ { |
|
26 |
+ name: "build - source", |
|
27 |
+ build: u.Build().WithSourceStrategy().AsBuild(), |
|
28 |
+ }, |
|
29 |
+ } |
|
30 |
+ |
|
31 |
+ ops := []admission.Operation{admission.Create, admission.Update} |
|
32 |
+ for _, test := range tests { |
|
33 |
+ for _, op := range ops { |
|
34 |
+ overrides := NewBuildOverrides(&BuildOverridesConfig{ForcePull: true}) |
|
35 |
+ pod := u.Pod().WithBuild(t, test.build, "v1") |
|
36 |
+ err := overrides.Admit(pod.ToAttributes()) |
|
37 |
+ if err != nil { |
|
38 |
+ t.Errorf("%s: unexpected error: %v", test.name, err) |
|
39 |
+ } |
|
40 |
+ build := pod.GetBuild(t) |
|
41 |
+ strategy := build.Spec.Strategy |
|
42 |
+ switch { |
|
43 |
+ case strategy.CustomStrategy != nil: |
|
44 |
+ if strategy.CustomStrategy.ForcePull == false { |
|
45 |
+ t.Errorf("%s (%s): force pull was false", test.name, op) |
|
46 |
+ } |
|
47 |
+ if pod.Spec.Containers[0].ImagePullPolicy != kapi.PullAlways { |
|
48 |
+ t.Errorf("%s (%s): image pull policy is not PullAlways", test.name, op) |
|
49 |
+ } |
|
50 |
+ case strategy.DockerStrategy != nil: |
|
51 |
+ if strategy.DockerStrategy.ForcePull == false { |
|
52 |
+ t.Errorf("%s (%s): force pull was false", test.name, op) |
|
53 |
+ } |
|
54 |
+ case strategy.SourceStrategy != nil: |
|
55 |
+ if strategy.SourceStrategy.ForcePull == false { |
|
56 |
+ t.Errorf("%s (%s): force pull was false", test.name, op) |
|
57 |
+ } |
|
58 |
+ } |
|
59 |
+ } |
|
60 |
+ } |
|
61 |
+} |
0 | 62 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,14 @@ |
0 |
+/* |
|
1 |
+Package overrides contains the BuildOverrides admission control plugin. |
|
2 |
+ |
|
3 |
+The plugin allows overriding settings on builds via the build pod. |
|
4 |
+ |
|
5 |
+Configuration |
|
6 |
+ |
|
7 |
+Configuration is done via a BuildOverridesConfig object: |
|
8 |
+ |
|
9 |
+ apiVersion: v1 |
|
10 |
+ kind: BuildOverridesConfig |
|
11 |
+ forcePull: true |
|
12 |
+*/ |
|
13 |
+package overrides |
0 | 5 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,29 @@ |
0 |
+package overrides |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "k8s.io/kubernetes/pkg/api/unversioned" |
|
4 |
+ |
|
5 |
+ _ "github.com/openshift/origin/pkg/build/admission/overrides/latest" |
|
6 |
+ "github.com/openshift/origin/pkg/cmd/server/api" |
|
7 |
+) |
|
8 |
+ |
|
9 |
+// SchemeGroupVersion is group version used to register these objects |
|
10 |
+var SchemeGroupVersion = unversioned.GroupVersion{Group: "", Version: ""} |
|
11 |
+ |
|
12 |
+// Kind takes an unqualified kind and returns back a Group qualified GroupKind |
|
13 |
+func Kind(kind string) unversioned.GroupKind { |
|
14 |
+ return SchemeGroupVersion.WithKind(kind).GroupKind() |
|
15 |
+} |
|
16 |
+ |
|
17 |
+// Resource takes an unqualified resource and returns back a Group qualified GroupResource |
|
18 |
+func Resource(resource string) unversioned.GroupResource { |
|
19 |
+ return SchemeGroupVersion.WithResource(resource).GroupResource() |
|
20 |
+} |
|
21 |
+ |
|
22 |
+func init() { |
|
23 |
+ api.Scheme.AddKnownTypes(SchemeGroupVersion, |
|
24 |
+ &BuildOverridesConfig{}, |
|
25 |
+ ) |
|
26 |
+} |
|
27 |
+ |
|
28 |
+func (*BuildOverridesConfig) IsAnAPIObject() {} |
0 | 29 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,13 @@ |
0 |
+package overrides |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "k8s.io/kubernetes/pkg/api/unversioned" |
|
4 |
+) |
|
5 |
+ |
|
6 |
+// BuildOverridesConfig controls override settings for builds |
|
7 |
+type BuildOverridesConfig struct { |
|
8 |
+ unversioned.TypeMeta |
|
9 |
+ |
|
10 |
+ // ForcePull indicates whether the build strategy should always be set to ForcePull=true |
|
11 |
+ ForcePull bool |
|
12 |
+} |
0 | 13 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,18 @@ |
0 |
+package v1 |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "k8s.io/kubernetes/pkg/api/unversioned" |
|
4 |
+ |
|
5 |
+ "github.com/openshift/origin/pkg/cmd/server/api" |
|
6 |
+) |
|
7 |
+ |
|
8 |
+// SchemeGroupVersion is group version used to register these objects |
|
9 |
+var SchemeGroupVersion = unversioned.GroupVersion{Group: "", Version: "v1"} |
|
10 |
+ |
|
11 |
+func init() { |
|
12 |
+ api.Scheme.AddKnownTypes(SchemeGroupVersion, |
|
13 |
+ &BuildOverridesConfig{}, |
|
14 |
+ ) |
|
15 |
+} |
|
16 |
+ |
|
17 |
+func (*BuildOverridesConfig) IsAnAPIObject() {} |
0 | 18 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,13 @@ |
0 |
+package v1 |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "k8s.io/kubernetes/pkg/api/unversioned" |
|
4 |
+) |
|
5 |
+ |
|
6 |
+// BuildOverridesConfig controls override settings for builds |
|
7 |
+type BuildOverridesConfig struct { |
|
8 |
+ unversioned.TypeMeta |
|
9 |
+ |
|
10 |
+ // ForcePull indicates whether the build strategy should always be set to ForcePull=true |
|
11 |
+ ForcePull bool `json:"forcePull",description:"if true, will always set ForcePull to true on builds"` |
|
12 |
+} |
0 | 13 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,42 @@ |
0 |
+package test |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ buildapi "github.com/openshift/origin/pkg/build/api" |
|
4 |
+) |
|
5 |
+ |
|
6 |
+type TestBuild buildapi.Build |
|
7 |
+ |
|
8 |
+func Build() *TestBuild { |
|
9 |
+ b := (*TestBuild)(&buildapi.Build{}) |
|
10 |
+ b.Name = "TestBuild" |
|
11 |
+ b.Spec.Strategy.DockerStrategy = &buildapi.DockerBuildStrategy{} |
|
12 |
+ b.Spec.Source.Git = &buildapi.GitBuildSource{ |
|
13 |
+ URI: "http://test.build/source", |
|
14 |
+ } |
|
15 |
+ return b |
|
16 |
+} |
|
17 |
+ |
|
18 |
+func (b *TestBuild) WithDockerStrategy() *TestBuild { |
|
19 |
+ b.Spec.Strategy.DockerStrategy = &buildapi.DockerBuildStrategy{} |
|
20 |
+ return b |
|
21 |
+} |
|
22 |
+ |
|
23 |
+func (b *TestBuild) WithSourceStrategy() *TestBuild { |
|
24 |
+ strategy := &buildapi.SourceBuildStrategy{} |
|
25 |
+ strategy.From.Name = "builder/image" |
|
26 |
+ strategy.From.Kind = "DockerImage" |
|
27 |
+ b.Spec.Strategy.SourceStrategy = strategy |
|
28 |
+ return b |
|
29 |
+} |
|
30 |
+ |
|
31 |
+func (b *TestBuild) WithCustomStrategy() *TestBuild { |
|
32 |
+ strategy := &buildapi.CustomBuildStrategy{} |
|
33 |
+ strategy.From.Name = "builder/image" |
|
34 |
+ strategy.From.Kind = "DockerImage" |
|
35 |
+ b.Spec.Strategy.CustomStrategy = strategy |
|
36 |
+ return b |
|
37 |
+} |
|
38 |
+ |
|
39 |
+func (b *TestBuild) AsBuild() *buildapi.Build { |
|
40 |
+ return (*buildapi.Build)(b) |
|
41 |
+} |
0 | 8 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,79 @@ |
0 |
+package test |
|
1 |
+ |
|
2 |
+import ( |
|
3 |
+ "testing" |
|
4 |
+ |
|
5 |
+ "k8s.io/kubernetes/pkg/admission" |
|
6 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
7 |
+ |
|
8 |
+ buildapi "github.com/openshift/origin/pkg/build/api" |
|
9 |
+) |
|
10 |
+ |
|
11 |
+type TestPod kapi.Pod |
|
12 |
+ |
|
13 |
+func Pod() *TestPod { |
|
14 |
+ return (*TestPod)(&kapi.Pod{}) |
|
15 |
+} |
|
16 |
+ |
|
17 |
+func (p *TestPod) WithAnnotation(name, value string) *TestPod { |
|
18 |
+ if p.Annotations == nil { |
|
19 |
+ p.Annotations = map[string]string{} |
|
20 |
+ } |
|
21 |
+ p.Annotations[name] = value |
|
22 |
+ return p |
|
23 |
+} |
|
24 |
+ |
|
25 |
+func (p *TestPod) WithEnvVar(name, value string) *TestPod { |
|
26 |
+ if len(p.Spec.Containers) == 0 { |
|
27 |
+ p.Spec.Containers = append(p.Spec.Containers, kapi.Container{}) |
|
28 |
+ } |
|
29 |
+ p.Spec.Containers[0].Env = append(p.Spec.Containers[0].Env, kapi.EnvVar{Name: name, Value: value}) |
|
30 |
+ return p |
|
31 |
+} |
|
32 |
+ |
|
33 |
+func (p *TestPod) WithBuild(t *testing.T, build *buildapi.Build, version string) *TestPod { |
|
34 |
+ encodedBuild, err := kapi.Scheme.EncodeToVersion(build, version) |
|
35 |
+ if err != nil { |
|
36 |
+ t.Fatalf("%v", err) |
|
37 |
+ } |
|
38 |
+ return p.WithAnnotation(buildapi.BuildAnnotation, build.Name).WithEnvVar("BUILD", string(encodedBuild)) |
|
39 |
+} |
|
40 |
+ |
|
41 |
+func (p *TestPod) EnvValue(name string) string { |
|
42 |
+ if len(p.Spec.Containers) == 0 { |
|
43 |
+ return "" |
|
44 |
+ } |
|
45 |
+ for _, ev := range p.Spec.Containers[0].Env { |
|
46 |
+ if ev.Name == name { |
|
47 |
+ return ev.Value |
|
48 |
+ } |
|
49 |
+ } |
|
50 |
+ return "" |
|
51 |
+} |
|
52 |
+ |
|
53 |
+func (p *TestPod) GetBuild(t *testing.T) *buildapi.Build { |
|
54 |
+ obj, err := kapi.Scheme.Decode([]byte(p.EnvValue("BUILD"))) |
|
55 |
+ if err != nil { |
|
56 |
+ t.Fatalf("Could not decode build: %v", err) |
|
57 |
+ } |
|
58 |
+ build, ok := obj.(*buildapi.Build) |
|
59 |
+ if !ok { |
|
60 |
+ t.Fatalf("Not a build object: %#v", obj) |
|
61 |
+ } |
|
62 |
+ return build |
|
63 |
+} |
|
64 |
+ |
|
65 |
+func (p *TestPod) ToAttributes() admission.Attributes { |
|
66 |
+ return admission.NewAttributesRecord((*kapi.Pod)(p), |
|
67 |
+ kapi.Kind("Pod"), |
|
68 |
+ "default", |
|
69 |
+ "TestPod", |
|
70 |
+ kapi.Resource("pods"), |
|
71 |
+ "", |
|
72 |
+ admission.Create, |
|
73 |
+ nil) |
|
74 |
+} |
|
75 |
+ |
|
76 |
+func (p *TestPod) AsPod() *kapi.Pod { |
|
77 |
+ return (*kapi.Pod)(p) |
|
78 |
+} |
... | ... |
@@ -213,13 +213,13 @@ func validateGitSource(git *buildapi.GitBuildSource, fldPath *field.Path) field. |
213 | 213 |
allErrs := field.ErrorList{} |
214 | 214 |
if len(git.URI) == 0 { |
215 | 215 |
allErrs = append(allErrs, field.Required(fldPath.Child("uri"))) |
216 |
- } else if !isValidURL(git.URI) { |
|
216 |
+ } else if !IsValidURL(git.URI) { |
|
217 | 217 |
allErrs = append(allErrs, field.Invalid(fldPath.Child("uri"), git.URI, "uri is not a valid url")) |
218 | 218 |
} |
219 |
- if git.HTTPProxy != nil && len(*git.HTTPProxy) != 0 && !isValidURL(*git.HTTPProxy) { |
|
219 |
+ if git.HTTPProxy != nil && len(*git.HTTPProxy) != 0 && !IsValidURL(*git.HTTPProxy) { |
|
220 | 220 |
allErrs = append(allErrs, field.Invalid(fldPath.Child("httpproxy"), *git.HTTPProxy, "proxy is not a valid url")) |
221 | 221 |
} |
222 |
- if git.HTTPSProxy != nil && len(*git.HTTPSProxy) != 0 && !isValidURL(*git.HTTPSProxy) { |
|
222 |
+ if git.HTTPSProxy != nil && len(*git.HTTPSProxy) != 0 && !IsValidURL(*git.HTTPSProxy) { |
|
223 | 223 |
allErrs = append(allErrs, field.Invalid(fldPath.Child("httpsproxy"), *git.HTTPSProxy, "proxy is not a valid url")) |
224 | 224 |
} |
225 | 225 |
if hasProxy(git) && !isHTTPScheme(git.URI) { |
... | ... |
@@ -432,6 +432,8 @@ func validateDockerStrategy(strategy *buildapi.DockerBuildStrategy, fldPath *fie |
432 | 432 |
} |
433 | 433 |
} |
434 | 434 |
|
435 |
+ allErrs = append(allErrs, ValidateStrategyEnv(strategy.Env, fldPath.Child("env"))...) |
|
436 |
+ |
|
435 | 437 |
return allErrs |
436 | 438 |
} |
437 | 439 |
|
... | ... |
@@ -439,6 +441,7 @@ func validateSourceStrategy(strategy *buildapi.SourceBuildStrategy, fldPath *fie |
439 | 439 |
allErrs := field.ErrorList{} |
440 | 440 |
allErrs = append(allErrs, validateFromImageReference(&strategy.From, fldPath.Child("from"))...) |
441 | 441 |
allErrs = append(allErrs, validateSecretRef(strategy.PullSecret, fldPath.Child("pullSecret"))...) |
442 |
+ allErrs = append(allErrs, ValidateStrategyEnv(strategy.Env, fldPath.Child("env"))...) |
|
442 | 443 |
return allErrs |
443 | 444 |
} |
444 | 445 |
|
... | ... |
@@ -446,6 +449,7 @@ func validateCustomStrategy(strategy *buildapi.CustomBuildStrategy, fldPath *fie |
446 | 446 |
allErrs := field.ErrorList{} |
447 | 447 |
allErrs = append(allErrs, validateFromImageReference(&strategy.From, fldPath.Child("from"))...) |
448 | 448 |
allErrs = append(allErrs, validateSecretRef(strategy.PullSecret, fldPath.Child("pullSecret"))...) |
449 |
+ allErrs = append(allErrs, ValidateStrategyEnv(strategy.Env, fldPath.Child("env"))...) |
|
449 | 450 |
return allErrs |
450 | 451 |
} |
451 | 452 |
|
... | ... |
@@ -503,7 +507,7 @@ func validateWebHook(webHook *buildapi.WebHookTrigger, fldPath *field.Path) fiel |
503 | 503 |
return allErrs |
504 | 504 |
} |
505 | 505 |
|
506 |
-func isValidURL(uri string) bool { |
|
506 |
+func IsValidURL(uri string) bool { |
|
507 | 507 |
_, err := url.Parse(uri) |
508 | 508 |
return err == nil |
509 | 509 |
} |
... | ... |
@@ -525,3 +529,22 @@ func ValidateBuildLogOptions(opts *buildapi.BuildLogOptions) field.ErrorList { |
525 | 525 |
} |
526 | 526 |
return allErrs |
527 | 527 |
} |
528 |
+ |
|
529 |
+const cIdentifierErrorMsg string = `must be a C identifier (matching regex ` + kvalidation.CIdentifierFmt + `): e.g. "my_name" or "MyName"` |
|
530 |
+ |
|
531 |
+func ValidateStrategyEnv(vars []kapi.EnvVar, fldPath *field.Path) field.ErrorList { |
|
532 |
+ allErrs := field.ErrorList{} |
|
533 |
+ |
|
534 |
+ for i, ev := range vars { |
|
535 |
+ idxPath := fldPath.Index(i) |
|
536 |
+ if len(ev.Name) == 0 { |
|
537 |
+ allErrs = append(allErrs, field.Required(idxPath.Child("name"))) |
|
538 |
+ } else if !kvalidation.IsCIdentifier(ev.Name) { |
|
539 |
+ allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), ev.Name, cIdentifierErrorMsg)) |
|
540 |
+ } |
|
541 |
+ if ev.ValueFrom != nil { |
|
542 |
+ allErrs = append(allErrs, field.Invalid(idxPath.Child("valueFrom"), ev.ValueFrom, "valueFrom is not supported in build strategy environment variables")) |
|
543 |
+ } |
|
544 |
+ } |
|
545 |
+ return allErrs |
|
546 |
+} |
... | ... |
@@ -207,6 +207,7 @@ func TestValidateBuildUpdate(t *testing.T) { |
207 | 207 |
} |
208 | 208 |
|
209 | 209 |
func TestBuildConfigGitSourceWithProxyFailure(t *testing.T) { |
210 |
+ proxyAddress := "127.0.0.1:3128" |
|
210 | 211 |
buildConfig := &buildapi.BuildConfig{ |
211 | 212 |
ObjectMeta: kapi.ObjectMeta{Name: "config-id", Namespace: "namespace"}, |
212 | 213 |
Spec: buildapi.BuildConfigSpec{ |
... | ... |
@@ -214,8 +215,8 @@ func TestBuildConfigGitSourceWithProxyFailure(t *testing.T) { |
214 | 214 |
Source: buildapi.BuildSource{ |
215 | 215 |
Git: &buildapi.GitBuildSource{ |
216 | 216 |
URI: "git://github.com/my/repository", |
217 |
- HTTPProxy: "127.0.0.1:3128", |
|
218 |
- HTTPSProxy: "127.0.0.1:3128", |
|
217 |
+ HTTPProxy: &proxyAddress, |
|
218 |
+ HTTPSProxy: &proxyAddress, |
|
219 | 219 |
}, |
220 | 220 |
}, |
221 | 221 |
Strategy: buildapi.BuildStrategy{ |
... | ... |
@@ -624,6 +625,7 @@ func TestValidateBuildRequest(t *testing.T) { |
624 | 624 |
|
625 | 625 |
func TestValidateSource(t *testing.T) { |
626 | 626 |
dockerfile := "FROM something" |
627 |
+ invalidProxyAddress := "some!@#$%^&*()url" |
|
627 | 628 |
errorCases := []struct { |
628 | 629 |
t field.ErrorType |
629 | 630 |
path string |
... | ... |
@@ -757,7 +759,7 @@ func TestValidateSource(t *testing.T) { |
757 | 757 |
source: &buildapi.BuildSource{ |
758 | 758 |
Git: &buildapi.GitBuildSource{ |
759 | 759 |
URI: "https://example.com/repo.git", |
760 |
- HTTPProxy: "some!@#$%^&*()url", |
|
760 |
+ HTTPProxy: &invalidProxyAddress, |
|
761 | 761 |
}, |
762 | 762 |
ContextDir: "contextDir", |
763 | 763 |
}, |
... | ... |
@@ -769,7 +771,7 @@ func TestValidateSource(t *testing.T) { |
769 | 769 |
source: &buildapi.BuildSource{ |
770 | 770 |
Git: &buildapi.GitBuildSource{ |
771 | 771 |
URI: "https://example.com/repo.git", |
772 |
- HTTPSProxy: "some!@#$%^&*()url", |
|
772 |
+ HTTPSProxy: &invalidProxyAddress, |
|
773 | 773 |
}, |
774 | 774 |
ContextDir: "contextDir", |
775 | 775 |
}, |
... | ... |
@@ -1727,3 +1729,84 @@ func TestValidateToImageReference(t *testing.T) { |
1727 | 1727 |
t.Errorf("Error on wrong field, expected %s, got %s", "namespace", err.Field) |
1728 | 1728 |
} |
1729 | 1729 |
} |
1730 |
+ |
|
1731 |
+func TestValidateStrategyEnvVars(t *testing.T) { |
|
1732 |
+ tests := []struct { |
|
1733 |
+ env []kapi.EnvVar |
|
1734 |
+ errExpected bool |
|
1735 |
+ errField string |
|
1736 |
+ errType field.ErrorType |
|
1737 |
+ }{ |
|
1738 |
+ // 0: missing Env variable name |
|
1739 |
+ { |
|
1740 |
+ env: []kapi.EnvVar{ |
|
1741 |
+ { |
|
1742 |
+ Name: "", |
|
1743 |
+ Value: "test", |
|
1744 |
+ }, |
|
1745 |
+ }, |
|
1746 |
+ errExpected: true, |
|
1747 |
+ errField: "env[0].name", |
|
1748 |
+ errType: field.ErrorTypeRequired, |
|
1749 |
+ }, |
|
1750 |
+ // 1: invalid Env variable name |
|
1751 |
+ { |
|
1752 |
+ env: []kapi.EnvVar{ |
|
1753 |
+ { |
|
1754 |
+ Name: " invalid,name", |
|
1755 |
+ Value: "test", |
|
1756 |
+ }, |
|
1757 |
+ }, |
|
1758 |
+ errExpected: true, |
|
1759 |
+ errField: "env[0].name", |
|
1760 |
+ errType: field.ErrorTypeInvalid, |
|
1761 |
+ }, |
|
1762 |
+ // 2: valueFrom present in env var |
|
1763 |
+ { |
|
1764 |
+ env: []kapi.EnvVar{ |
|
1765 |
+ { |
|
1766 |
+ Name: "name", |
|
1767 |
+ Value: "test", |
|
1768 |
+ ValueFrom: &kapi.EnvVarSource{}, |
|
1769 |
+ }, |
|
1770 |
+ }, |
|
1771 |
+ errExpected: true, |
|
1772 |
+ errField: "env[0].valueFrom", |
|
1773 |
+ errType: field.ErrorTypeInvalid, |
|
1774 |
+ }, |
|
1775 |
+ // 3: valid env |
|
1776 |
+ { |
|
1777 |
+ env: []kapi.EnvVar{ |
|
1778 |
+ { |
|
1779 |
+ Name: "VAR1", |
|
1780 |
+ Value: "value1", |
|
1781 |
+ }, |
|
1782 |
+ { |
|
1783 |
+ Name: "VAR2", |
|
1784 |
+ Value: "value2", |
|
1785 |
+ }, |
|
1786 |
+ }, |
|
1787 |
+ }, |
|
1788 |
+ } |
|
1789 |
+ |
|
1790 |
+ for i, tc := range tests { |
|
1791 |
+ errs := ValidateStrategyEnv(tc.env, field.NewPath("env")) |
|
1792 |
+ if !tc.errExpected { |
|
1793 |
+ if len(errs) > 0 { |
|
1794 |
+ t.Errorf("%d: unexpected error: %v", i, errs.ToAggregate()) |
|
1795 |
+ } |
|
1796 |
+ continue |
|
1797 |
+ } |
|
1798 |
+ if tc.errExpected && len(errs) == 0 { |
|
1799 |
+ t.Errorf("%d: expected error. Got none.", i) |
|
1800 |
+ continue |
|
1801 |
+ } |
|
1802 |
+ err := errs[0] |
|
1803 |
+ if err.Field != tc.errField { |
|
1804 |
+ t.Errorf("%d: unexpected error field: %s", i, err.Field) |
|
1805 |
+ } |
|
1806 |
+ if err.Type != tc.errType { |
|
1807 |
+ t.Errorf("%d: unexpected error type: %s", i, err.Type) |
|
1808 |
+ } |
|
1809 |
+ } |
|
1810 |
+} |
... | ... |
@@ -41,7 +41,7 @@ import ( |
41 | 41 |
) |
42 | 42 |
|
43 | 43 |
// AdmissionPlugins is the full list of admission control plugins to enable in the order they must run |
44 |
-var AdmissionPlugins = []string{"NamespaceLifecycle", "OriginPodNodeEnvironment", "LimitRanger", "ServiceAccount", "SecurityContextConstraint", "ResourceQuota", "SCCExecRestrictions"} |
|
44 |
+var AdmissionPlugins = []string{"NamespaceLifecycle", "OriginPodNodeEnvironment", "LimitRanger", "ServiceAccount", "SecurityContextConstraint", "BuildDefaults", "BuildOverrides", "ResourceQuota", "SCCExecRestrictions"} |
|
45 | 45 |
|
46 | 46 |
// MasterConfig defines the required values to start a Kubernetes master |
47 | 47 |
type MasterConfig struct { |
... | ... |
@@ -169,7 +169,7 @@ func BuildMasterConfig(options configapi.MasterConfig) (*MasterConfig, error) { |
169 | 169 |
kubeletClientConfig := configapi.GetKubeletClientConfig(options) |
170 | 170 |
|
171 | 171 |
// in-order list of plug-ins that should intercept admission decisions (origin only intercepts) |
172 |
- admissionControlPluginNames := []string{"OriginNamespaceLifecycle", "BuildByStrategy", "BuildHTTPProxy"} |
|
172 |
+ admissionControlPluginNames := []string{"OriginNamespaceLifecycle", "BuildByStrategy"} |
|
173 | 173 |
if len(options.AdmissionConfig.PluginOrderOverride) > 0 { |
174 | 174 |
admissionControlPluginNames = options.AdmissionConfig.PluginOrderOverride |
175 | 175 |
} |
... | ... |
@@ -22,7 +22,8 @@ var admissionPluginsNotUsedByKube = sets.NewString( |
22 | 22 |
"DenyEscalatingExec", // from kube, it denies exec to pods that have certain privileges. This is superceded in origin by SCCExecRestrictions that checks against SCC rules. |
23 | 23 |
|
24 | 24 |
"BuildByStrategy", // from origin, only needed for managing builds, not kubernetes resources |
25 |
- "BuildHTTPProxy", // from origin, only needed for managing builds, not kubernetes resources |
|
25 |
+ "BuildDefaults", // from origin, only needed for managing builds, not kubernetes resources |
|
26 |
+ "BuildOverrides", // from origin, only needed for managing builds, not kubernetes resources |
|
26 | 27 |
"OriginNamespaceLifecycle", // from origin, only needed for rejecting openshift resources, so not needed by kube |
27 | 28 |
"ProjectRequestLimit", // from origin, used for limiting project requests by user (online use case) |
28 | 29 |
|
... | ... |
@@ -3,7 +3,8 @@ package start |
3 | 3 |
import ( |
4 | 4 |
|
5 | 5 |
// Admission control plug-ins used by OpenShift |
6 |
- _ "github.com/openshift/origin/pkg/build/admission/httpproxy" |
|
6 |
+ _ "github.com/openshift/origin/pkg/build/admission/defaults" |
|
7 |
+ _ "github.com/openshift/origin/pkg/build/admission/overrides" |
|
7 | 8 |
_ "github.com/openshift/origin/pkg/build/admission/strategyrestrictions" |
8 | 9 |
_ "github.com/openshift/origin/pkg/project/admission/lifecycle" |
9 | 10 |
_ "github.com/openshift/origin/pkg/project/admission/nodeenv" |
10 | 11 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,214 @@ |
0 |
+// +build integration,etcd |
|
1 |
+ |
|
2 |
+package integration |
|
3 |
+ |
|
4 |
+import ( |
|
5 |
+ "reflect" |
|
6 |
+ "testing" |
|
7 |
+ "time" |
|
8 |
+ |
|
9 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
10 |
+ kclient "k8s.io/kubernetes/pkg/client/unversioned" |
|
11 |
+ "k8s.io/kubernetes/pkg/fields" |
|
12 |
+ "k8s.io/kubernetes/pkg/runtime" |
|
13 |
+ watchapi "k8s.io/kubernetes/pkg/watch" |
|
14 |
+ |
|
15 |
+ "github.com/openshift/origin/pkg/build/admission/defaults" |
|
16 |
+ "github.com/openshift/origin/pkg/build/admission/overrides" |
|
17 |
+ buildtestutil "github.com/openshift/origin/pkg/build/admission/testutil" |
|
18 |
+ buildapi "github.com/openshift/origin/pkg/build/api" |
|
19 |
+ buildutil "github.com/openshift/origin/pkg/build/util" |
|
20 |
+ "github.com/openshift/origin/pkg/client" |
|
21 |
+ configapi "github.com/openshift/origin/pkg/cmd/server/api" |
|
22 |
+ "github.com/openshift/origin/pkg/cmd/server/bootstrappolicy" |
|
23 |
+ testutil "github.com/openshift/origin/test/util" |
|
24 |
+ testserver "github.com/openshift/origin/test/util/server" |
|
25 |
+) |
|
26 |
+ |
|
27 |
+var buildPodAdmissionTestTimeout time.Duration = 10 * time.Second |
|
28 |
+ |
|
29 |
+func TestBuildDefaultGitHTTPProxy(t *testing.T) { |
|
30 |
+ httpProxy := "http://my.test.proxy:12345" |
|
31 |
+ oclient, kclient := setupBuildDefaultsAdmissionTest(t, &defaults.BuildDefaultsConfig{ |
|
32 |
+ GitHTTPProxy: httpProxy, |
|
33 |
+ }) |
|
34 |
+ build, _ := runBuildPodAdmissionTest(t, oclient, kclient, buildPodAdmissionTestDockerBuild()) |
|
35 |
+ if actual := build.Spec.Source.Git.HTTPProxy; actual == nil || *actual != httpProxy { |
|
36 |
+ t.Errorf("Resulting build did not get expected HTTP proxy: %v", actual) |
|
37 |
+ } |
|
38 |
+} |
|
39 |
+ |
|
40 |
+func TestBuildDefaultGitHTTPSProxy(t *testing.T) { |
|
41 |
+ httpsProxy := "https://my.test.proxy:12345" |
|
42 |
+ oclient, kclient := setupBuildDefaultsAdmissionTest(t, &defaults.BuildDefaultsConfig{ |
|
43 |
+ GitHTTPSProxy: httpsProxy, |
|
44 |
+ }) |
|
45 |
+ build, _ := runBuildPodAdmissionTest(t, oclient, kclient, buildPodAdmissionTestDockerBuild()) |
|
46 |
+ if actual := build.Spec.Source.Git.HTTPSProxy; actual == nil || *actual != httpsProxy { |
|
47 |
+ t.Errorf("Resulting build did not get expected HTTPS proxy: %v", actual) |
|
48 |
+ } |
|
49 |
+} |
|
50 |
+ |
|
51 |
+func TestBuildDefaultEnvironment(t *testing.T) { |
|
52 |
+ env := []kapi.EnvVar{ |
|
53 |
+ { |
|
54 |
+ Name: "VAR1", |
|
55 |
+ Value: "VALUE1", |
|
56 |
+ }, |
|
57 |
+ { |
|
58 |
+ Name: "VAR2", |
|
59 |
+ Value: "VALUE2", |
|
60 |
+ }, |
|
61 |
+ } |
|
62 |
+ oclient, kclient := setupBuildDefaultsAdmissionTest(t, &defaults.BuildDefaultsConfig{ |
|
63 |
+ Env: env, |
|
64 |
+ }) |
|
65 |
+ build, _ := runBuildPodAdmissionTest(t, oclient, kclient, buildPodAdmissionTestDockerBuild()) |
|
66 |
+ if actual := build.Spec.Strategy.DockerStrategy.Env; !reflect.DeepEqual(env, actual) { |
|
67 |
+ t.Errorf("Resulting build did not get expected environment: %v", actual) |
|
68 |
+ } |
|
69 |
+} |
|
70 |
+ |
|
71 |
+func TestBuildOverrideForcePull(t *testing.T) { |
|
72 |
+ oclient, kclient := setupBuildOverridesAdmissionTest(t, &overrides.BuildOverridesConfig{ |
|
73 |
+ ForcePull: true, |
|
74 |
+ }) |
|
75 |
+ build, _ := runBuildPodAdmissionTest(t, oclient, kclient, buildPodAdmissionTestDockerBuild()) |
|
76 |
+ if !build.Spec.Strategy.DockerStrategy.ForcePull { |
|
77 |
+ t.Errorf("ForcePull was not set on resulting build") |
|
78 |
+ } |
|
79 |
+} |
|
80 |
+ |
|
81 |
+func TestBuildOverrideForcePullCustomStrategy(t *testing.T) { |
|
82 |
+ oclient, kclient := setupBuildOverridesAdmissionTest(t, &overrides.BuildOverridesConfig{ |
|
83 |
+ ForcePull: true, |
|
84 |
+ }) |
|
85 |
+ build, pod := runBuildPodAdmissionTest(t, oclient, kclient, buildPodAdmissionTestCustomBuild()) |
|
86 |
+ if pod.Spec.Containers[0].ImagePullPolicy != kapi.PullAlways { |
|
87 |
+ t.Errorf("Pod ImagePullPolicy is not PullAlways") |
|
88 |
+ } |
|
89 |
+ if !build.Spec.Strategy.CustomStrategy.ForcePull { |
|
90 |
+ t.Errorf("ForcePull was not set on resulting build") |
|
91 |
+ } |
|
92 |
+} |
|
93 |
+ |
|
94 |
+func buildPodAdmissionTestCustomBuild() *buildapi.Build { |
|
95 |
+ build := &buildapi.Build{} |
|
96 |
+ build.Name = "test-custom-build" |
|
97 |
+ build.Spec.Source.Git = &buildapi.GitBuildSource{URI: "http://test/src"} |
|
98 |
+ build.Spec.Strategy.CustomStrategy = &buildapi.CustomBuildStrategy{} |
|
99 |
+ build.Spec.Strategy.CustomStrategy.From.Kind = "DockerImage" |
|
100 |
+ build.Spec.Strategy.CustomStrategy.From.Name = "test/image" |
|
101 |
+ return build |
|
102 |
+} |
|
103 |
+ |
|
104 |
+func buildPodAdmissionTestDockerBuild() *buildapi.Build { |
|
105 |
+ build := &buildapi.Build{} |
|
106 |
+ build.Name = "test-build" |
|
107 |
+ build.Spec.Source.Git = &buildapi.GitBuildSource{URI: "http://test/src"} |
|
108 |
+ build.Spec.Strategy.DockerStrategy = &buildapi.DockerBuildStrategy{} |
|
109 |
+ return build |
|
110 |
+} |
|
111 |
+ |
|
112 |
+func runBuildPodAdmissionTest(t *testing.T, client *client.Client, kclient *kclient.Client, build *buildapi.Build) (*buildapi.Build, *kapi.Pod) { |
|
113 |
+ |
|
114 |
+ ns := testutil.Namespace() |
|
115 |
+ _, err := client.Builds(ns).Create(build) |
|
116 |
+ if err != nil { |
|
117 |
+ t.Fatalf("%v", err) |
|
118 |
+ } |
|
119 |
+ |
|
120 |
+ watchOpt := kapi.ListOptions{ |
|
121 |
+ FieldSelector: fields.OneTermEqualSelector( |
|
122 |
+ "metadata.name", |
|
123 |
+ buildutil.GetBuildPodName(build), |
|
124 |
+ ), |
|
125 |
+ } |
|
126 |
+ podWatch, err := kclient.Pods(ns).Watch(watchOpt) |
|
127 |
+ if err != nil { |
|
128 |
+ t.Fatalf("%v", err) |
|
129 |
+ } |
|
130 |
+ type resultObjs struct { |
|
131 |
+ build *buildapi.Build |
|
132 |
+ pod *kapi.Pod |
|
133 |
+ } |
|
134 |
+ result := make(chan resultObjs) |
|
135 |
+ defer podWatch.Stop() |
|
136 |
+ go func() { |
|
137 |
+ for e := range podWatch.ResultChan() { |
|
138 |
+ if e.Type == watchapi.Added { |
|
139 |
+ pod, ok := e.Object.(*kapi.Pod) |
|
140 |
+ if !ok { |
|
141 |
+ t.Fatalf("unexpected object: %v", e.Object) |
|
142 |
+ } |
|
143 |
+ build := (*buildtestutil.TestPod)(pod).GetBuild(t) |
|
144 |
+ result <- resultObjs{build: build, pod: pod} |
|
145 |
+ } |
|
146 |
+ } |
|
147 |
+ }() |
|
148 |
+ |
|
149 |
+ select { |
|
150 |
+ case <-time.After(buildPodAdmissionTestTimeout): |
|
151 |
+ t.Fatalf("timed out after %v", buildPodAdmissionTestTimeout) |
|
152 |
+ case objs := <-result: |
|
153 |
+ return objs.build, objs.pod |
|
154 |
+ } |
|
155 |
+ return nil, nil |
|
156 |
+} |
|
157 |
+ |
|
158 |
+func setupBuildDefaultsAdmissionTest(t *testing.T, defaultsConfig *defaults.BuildDefaultsConfig) (*client.Client, *kclient.Client) { |
|
159 |
+ return setupBuildPodAdmissionTest(t, map[string]configapi.AdmissionPluginConfig{ |
|
160 |
+ "BuildDefaults": { |
|
161 |
+ Configuration: runtime.EmbeddedObject{Object: defaultsConfig}, |
|
162 |
+ }, |
|
163 |
+ }) |
|
164 |
+} |
|
165 |
+ |
|
166 |
+func setupBuildOverridesAdmissionTest(t *testing.T, overridesConfig *overrides.BuildOverridesConfig) (*client.Client, *kclient.Client) { |
|
167 |
+ return setupBuildPodAdmissionTest(t, map[string]configapi.AdmissionPluginConfig{ |
|
168 |
+ "BuildOverrides": { |
|
169 |
+ Configuration: runtime.EmbeddedObject{Object: overridesConfig}, |
|
170 |
+ }, |
|
171 |
+ }) |
|
172 |
+} |
|
173 |
+ |
|
174 |
+func setupBuildPodAdmissionTest(t *testing.T, pluginConfig map[string]configapi.AdmissionPluginConfig) (*client.Client, *kclient.Client) { |
|
175 |
+ master, err := testserver.DefaultMasterOptions() |
|
176 |
+ if err != nil { |
|
177 |
+ t.Fatalf("%v", err) |
|
178 |
+ } |
|
179 |
+ master.KubernetesMasterConfig.AdmissionConfig.PluginConfig = pluginConfig |
|
180 |
+ clusterAdminKubeConfig, err := testserver.StartConfiguredMaster(master) |
|
181 |
+ if err != nil { |
|
182 |
+ t.Fatalf("%v", err) |
|
183 |
+ } |
|
184 |
+ clusterAdminClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig) |
|
185 |
+ if err != nil { |
|
186 |
+ t.Fatalf("%v", err) |
|
187 |
+ } |
|
188 |
+ |
|
189 |
+ clusterAdminKubeClient, err := testutil.GetClusterAdminKubeClient(clusterAdminKubeConfig) |
|
190 |
+ if err != nil { |
|
191 |
+ t.Fatalf("%v", err) |
|
192 |
+ } |
|
193 |
+ |
|
194 |
+ _, err = clusterAdminKubeClient.Namespaces().Create(&kapi.Namespace{ |
|
195 |
+ ObjectMeta: kapi.ObjectMeta{Name: testutil.Namespace()}, |
|
196 |
+ }) |
|
197 |
+ if err != nil { |
|
198 |
+ t.Fatalf("%v", err) |
|
199 |
+ } |
|
200 |
+ |
|
201 |
+ err = testserver.WaitForServiceAccounts( |
|
202 |
+ clusterAdminKubeClient, |
|
203 |
+ testutil.Namespace(), |
|
204 |
+ []string{ |
|
205 |
+ bootstrappolicy.BuilderServiceAccountName, |
|
206 |
+ bootstrappolicy.DefaultServiceAccountName, |
|
207 |
+ }) |
|
208 |
+ if err != nil { |
|
209 |
+ t.Fatalf("%v", err) |
|
210 |
+ } |
|
211 |
+ |
|
212 |
+ return clusterAdminClient, clusterAdminKubeClient |
|
213 |
+} |