Browse code

Preventing build from inheriting master log level

jupierce authored on 2016/07/14 06:18:06
Showing 20 changed files
... ...
@@ -56,10 +56,49 @@ func SetBuild(a admission.Attributes, build *buildapi.Build, groupVersion unvers
56 56
 	if err != nil {
57 57
 		return err
58 58
 	}
59
+
59 60
 	err = setBuildInPod(build, pod, groupVersion)
60 61
 	if err != nil {
61 62
 		return admission.NewForbidden(a, fmt.Errorf("unable to set build in pod: %v", err))
62 63
 	}
64
+
65
+	return nil
66
+}
67
+
68
+// SetBuildLogLevel extracts BUILD_LOGLEVEL from the Build environment
69
+// and feeds it as an argument to the Pod's entrypoint. The BUILD_LOGLEVEL
70
+// environment variable may have been set in multiple ways: a default value,
71
+// by a BuildConfig, or by the BuildDefaults admission plugin. In this method
72
+// we finally act on the value by injecting it into the Pod.
73
+func SetBuildLogLevel(attributes admission.Attributes, build *buildapi.Build) error {
74
+	pod, err := GetPod(attributes)
75
+	if err != nil {
76
+		return err
77
+	}
78
+
79
+	var envs []kapi.EnvVar
80
+
81
+	// Check whether the build strategy supports --loglevel parameter.
82
+	switch {
83
+	case build.Spec.Strategy.DockerStrategy != nil:
84
+		envs = build.Spec.Strategy.DockerStrategy.Env
85
+	case build.Spec.Strategy.SourceStrategy != nil:
86
+		envs = build.Spec.Strategy.SourceStrategy.Env
87
+	default:
88
+		// The build strategy does not support --loglevel
89
+		return nil
90
+	}
91
+
92
+	buildLogLevel := "0" // The ultimate default for the build pod's loglevel if no actor sets BUILD_LOGLEVEL in the Build
93
+	for i := range envs {
94
+		env := envs[i]
95
+		if env.Name == "BUILD_LOGLEVEL" {
96
+			buildLogLevel = env.Value
97
+			break
98
+		}
99
+	}
100
+	c := &pod.Spec.Containers[0]
101
+	c.Args = append(c.Args, "--loglevel="+buildLogLevel)
63 102
 	return nil
64 103
 }
65 104
 
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"reflect"
5 5
 	"testing"
6 6
 
7
+	kapi "k8s.io/kubernetes/pkg/api"
7 8
 	"k8s.io/kubernetes/pkg/api/unversioned"
8 9
 
9 10
 	u "github.com/openshift/origin/pkg/build/admission/testutil"
... ...
@@ -78,3 +79,27 @@ func TestSetBuild(t *testing.T) {
78 78
 		}
79 79
 	}
80 80
 }
81
+
82
+func TestSetBuildLogLevel(t *testing.T) {
83
+	build := u.Build().WithSourceStrategy()
84
+	pod := u.Pod().WithEnvVar("BUILD", "foo")
85
+	SetBuildLogLevel(pod.ToAttributes(), build.AsBuild())
86
+
87
+	if len(pod.Spec.Containers[0].Args) == 0 {
88
+		t.Errorf("Builds pod loglevel was not set")
89
+	}
90
+
91
+	if pod.Spec.Containers[0].Args[0] != "--loglevel=0" {
92
+		t.Errorf("Default build pod loglevel was not set to 0")
93
+	}
94
+
95
+	build = u.Build().WithSourceStrategy()
96
+	pod = u.Pod().WithEnvVar("BUILD", "foo")
97
+	build.Spec.Strategy.SourceStrategy.Env = []kapi.EnvVar{{"BUILD_LOGLEVEL", "7", nil}}
98
+	SetBuildLogLevel(pod.ToAttributes(), build.AsBuild())
99
+
100
+	if pod.Spec.Containers[0].Args[0] != "--loglevel=7" {
101
+		t.Errorf("Build pod loglevel was not transferred from BUILD_LOGLEVEL environment variable: %#v", pod)
102
+	}
103
+
104
+}
... ...
@@ -72,6 +72,11 @@ func (a *buildDefaults) Admit(attributes admission.Attributes) error {
72 72
 
73 73
 	a.applyBuildDefaults(build)
74 74
 
75
+	err = buildadmission.SetBuildLogLevel(attributes, build)
76
+	if err != nil {
77
+		return err
78
+	}
79
+
75 80
 	return buildadmission.SetBuild(attributes, build, version)
76 81
 }
77 82
 
... ...
@@ -9,19 +9,30 @@ type TestBuild buildapi.Build
9 9
 func Build() *TestBuild {
10 10
 	b := (*TestBuild)(&buildapi.Build{})
11 11
 	b.Name = "TestBuild"
12
-	b.Spec.Strategy.DockerStrategy = &buildapi.DockerBuildStrategy{}
12
+	b.WithDockerStrategy()
13 13
 	b.Spec.Source.Git = &buildapi.GitBuildSource{
14 14
 		URI: "http://test.build/source",
15 15
 	}
16 16
 	return b
17 17
 }
18 18
 
19
+// clearStrategy nil all strategies in the Spec since it is a
20
+// common pattern to detect strategy by testing for non-nil.
21
+func (b *TestBuild) clearStrategy() {
22
+	b.Spec.Strategy.DockerStrategy = nil
23
+	b.Spec.Strategy.SourceStrategy = nil
24
+	b.Spec.Strategy.CustomStrategy = nil
25
+	b.Spec.Strategy.JenkinsPipelineStrategy = nil
26
+}
27
+
19 28
 func (b *TestBuild) WithDockerStrategy() *TestBuild {
29
+	b.clearStrategy()
20 30
 	b.Spec.Strategy.DockerStrategy = &buildapi.DockerBuildStrategy{}
21 31
 	return b
22 32
 }
23 33
 
24 34
 func (b *TestBuild) WithSourceStrategy() *TestBuild {
35
+	b.clearStrategy()
25 36
 	strategy := &buildapi.SourceBuildStrategy{}
26 37
 	strategy.From.Name = "builder/image"
27 38
 	strategy.From.Kind = "DockerImage"
... ...
@@ -30,6 +41,7 @@ func (b *TestBuild) WithSourceStrategy() *TestBuild {
30 30
 }
31 31
 
32 32
 func (b *TestBuild) WithCustomStrategy() *TestBuild {
33
+	b.clearStrategy()
33 34
 	strategy := &buildapi.CustomBuildStrategy{}
34 35
 	strategy.From.Name = "builder/image"
35 36
 	strategy.From.Kind = "DockerImage"
... ...
@@ -215,7 +215,7 @@ func RunDockerBuild(out io.Writer) error {
215 215
 	return runBuild(out, dockerBuilder{})
216 216
 }
217 217
 
218
-// RunSTIBuild creates a STI builder and runs its build
219
-func RunSTIBuild(out io.Writer) error {
218
+// RunS2IBuild creates a S2I builder and runs its build
219
+func RunS2IBuild(out io.Writer) error {
220 220
 	return runBuild(out, s2iBuilder{})
221 221
 }
... ...
@@ -7,7 +7,6 @@ import (
7 7
 	"k8s.io/kubernetes/pkg/runtime"
8 8
 
9 9
 	buildapi "github.com/openshift/origin/pkg/build/api"
10
-	cmdutil "github.com/openshift/origin/pkg/cmd/util"
11 10
 )
12 11
 
13 12
 // DockerBuildStrategy creates a Docker build using a Docker builder image.
... ...
@@ -32,7 +31,6 @@ func (bs *DockerBuildStrategy) CreateBuildPod(build *buildapi.Build) (*kapi.Pod,
32 32
 
33 33
 	containerEnv := []kapi.EnvVar{
34 34
 		{Name: "BUILD", Value: string(data)},
35
-		{Name: "BUILD_LOGLEVEL", Value: fmt.Sprintf("%d", cmdutil.GetLogLevel())},
36 35
 	}
37 36
 
38 37
 	addSourceEnvVars(build.Spec.Source, &containerEnv)
... ...
@@ -55,7 +53,7 @@ func (bs *DockerBuildStrategy) CreateBuildPod(build *buildapi.Build) (*kapi.Pod,
55 55
 					Name:  "docker-build",
56 56
 					Image: bs.Image,
57 57
 					Env:   containerEnv,
58
-					Args:  []string{"--loglevel=" + getContainerVerbosity(containerEnv)},
58
+					Args:  []string{},
59 59
 					// TODO: run unprivileged https://github.com/openshift/origin/issues/662
60 60
 					SecurityContext: &kapi.SecurityContext{
61 61
 						Privileged: &privileged,
... ...
@@ -11,7 +11,6 @@ import (
11 11
 	"k8s.io/kubernetes/pkg/serviceaccount"
12 12
 
13 13
 	buildapi "github.com/openshift/origin/pkg/build/api"
14
-	cmdutil "github.com/openshift/origin/pkg/cmd/util"
15 14
 )
16 15
 
17 16
 // SourceBuildStrategy creates STI(source to image) builds
... ...
@@ -43,7 +42,6 @@ func (bs *SourceBuildStrategy) CreateBuildPod(build *buildapi.Build) (*kapi.Pod,
43 43
 
44 44
 	containerEnv := []kapi.EnvVar{
45 45
 		{Name: "BUILD", Value: string(data)},
46
-		{Name: "BUILD_LOGLEVEL", Value: fmt.Sprintf("%d", cmdutil.GetLogLevel())},
47 46
 	}
48 47
 
49 48
 	addSourceEnvVars(build.Spec.Source, &containerEnv)
... ...
@@ -82,7 +80,7 @@ func (bs *SourceBuildStrategy) CreateBuildPod(build *buildapi.Build) (*kapi.Pod,
82 82
 					SecurityContext: &kapi.SecurityContext{
83 83
 						Privileged: &privileged,
84 84
 					},
85
-					Args: []string{"--loglevel=" + getContainerVerbosity(containerEnv)},
85
+					Args: []string{},
86 86
 				},
87 87
 			},
88 88
 			RestartPolicy: kapi.RestartPolicyNever,
... ...
@@ -12,7 +12,7 @@ import (
12 12
 )
13 13
 
14 14
 const (
15
-	stiBuilderLong = `
15
+	s2iBuilderLong = `
16 16
 Perform a Source-to-Image build
17 17
 
18 18
 This command executes a Source-to-Image build using arguments passed via the environment.
... ...
@@ -25,14 +25,14 @@ This command executes a Docker build using arguments passed via the environment.
25 25
 It expects to be run inside of a container.`
26 26
 )
27 27
 
28
-// NewCommandSTIBuilder provides a CLI handler for STI build type
29
-func NewCommandSTIBuilder(name string) *cobra.Command {
28
+// NewCommandS2IBuilder provides a CLI handler for S2I build type
29
+func NewCommandS2IBuilder(name string) *cobra.Command {
30 30
 	cmd := &cobra.Command{
31 31
 		Use:   name,
32 32
 		Short: "Run a Source-to-Image build",
33
-		Long:  stiBuilderLong,
33
+		Long:  s2iBuilderLong,
34 34
 		Run: func(c *cobra.Command, args []string) {
35
-			err := cmd.RunSTIBuild(c.Out())
35
+			err := cmd.RunS2IBuild(c.Out())
36 36
 			kcmdutil.CheckErr(err)
37 37
 		},
38 38
 	}
... ...
@@ -63,7 +63,7 @@ func CommandFor(basename string) *cobra.Command {
63 63
 	case "openshift-recycle":
64 64
 		cmd = recycle.NewCommandRecycle(basename, out)
65 65
 	case "openshift-sti-build":
66
-		cmd = builder.NewCommandSTIBuilder(basename)
66
+		cmd = builder.NewCommandS2IBuilder(basename)
67 67
 	case "openshift-docker-build":
68 68
 		cmd = builder.NewCommandDockerBuilder(basename)
69 69
 	case "oc", "osc":
... ...
@@ -131,7 +131,7 @@ func NewCommandOpenShift(name string) *cobra.Command {
131 131
 		irouter.NewCommandF5Router("f5-router"),
132 132
 		deployer.NewCommandDeployer("deploy"),
133 133
 		recycle.NewCommandRecycle("recycle", out),
134
-		builder.NewCommandSTIBuilder("sti-build"),
134
+		builder.NewCommandS2IBuilder("sti-build"),
135 135
 		builder.NewCommandDockerBuilder("docker-build"),
136 136
 		diagnostics.NewCommandPodDiagnostics("diagnostic-pod", out),
137 137
 	)
... ...
@@ -53,7 +53,7 @@ var _ = g.Describe("[builds][Slow] s2i extended build", func() {
53 53
 			})
54 54
 
55 55
 			g.By("running the build")
56
-			out, err := oc.Run("start-build").Args(buildConfigName).Output()
56
+			out, err := oc.Run("start-build").Args("--build-loglevel=5", buildConfigName).Output()
57 57
 			if err != nil {
58 58
 				fmt.Fprintf(g.GinkgoWriter, "\nstart-build output:\n%s\n", out)
59 59
 			}
... ...
@@ -95,7 +95,7 @@ var _ = g.Describe("[builds][Slow] s2i extended build", func() {
95 95
 			o.Expect(err).NotTo(o.HaveOccurred())
96 96
 
97 97
 			g.By("running the build")
98
-			out, err := oc.Run("start-build").Args(buildConfigName).Output()
98
+			out, err := oc.Run("start-build").Args("--build-loglevel=5", buildConfigName).Output()
99 99
 			if err != nil {
100 100
 				fmt.Fprintf(g.GinkgoWriter, "\nstart-build output:\n%s\n", out)
101 101
 			}
... ...
@@ -137,7 +137,7 @@ var _ = g.Describe("[builds][Slow] s2i extended build", func() {
137 137
 			o.Expect(err).NotTo(o.HaveOccurred())
138 138
 
139 139
 			g.By("running the build")
140
-			out, err := oc.Run("start-build").Args(buildConfigName).Output()
140
+			out, err := oc.Run("start-build").Args("--build-loglevel=5", buildConfigName).Output()
141 141
 			if err != nil {
142 142
 				fmt.Fprintf(g.GinkgoWriter, "\nstart-build output:\n%s\n", out)
143 143
 			}
... ...
@@ -90,26 +90,48 @@ var _ = g.Describe("[builds][Slow] starting a build using CLI", func() {
90 90
 			o.Expect(err).NotTo(o.HaveOccurred())
91 91
 		})
92 92
 
93
-		g.It("should allow to change build log level", func() {
94
-			g.By("starting the build with --build-loglevel=1")
95
-			out, err := oc.Run("start-build").Args("sample-build", "--build-loglevel=1").Output()
93
+		g.It("BUILD_LOGLEVEL in buildconfig should create verbose output", func() {
94
+			g.By("starting the build with buildconfig strategy env BUILD_LOGLEVEL=5")
95
+			out, err := oc.Run("start-build").Args("sample-verbose-build").Output()
96 96
 			fmt.Fprintf(g.GinkgoWriter, "\nstart-build output:\n%s\n", out)
97 97
 			o.Expect(err).NotTo(o.HaveOccurred())
98 98
 
99 99
 			g.By("waiting for the build to complete")
100
-			err = exutil.WaitForABuild(oc.REST().Builds(oc.Namespace()), "sample-build-1", exutil.CheckBuildSuccessFn, exutil.CheckBuildFailedFn)
100
+			err = exutil.WaitForABuild(oc.REST().Builds(oc.Namespace()), "sample-verbose-build-1", exutil.CheckBuildSuccessFn, exutil.CheckBuildFailedFn)
101 101
 			if err != nil {
102
-				exutil.DumpBuildLogs("sample-build", oc)
102
+				exutil.DumpBuildLogs("sample-verbose-build", oc)
103 103
 			}
104 104
 
105 105
 			g.By("verifying the build output")
106
-			buildLog, err := oc.Run("logs").Args("-f", "bc/sample-build").Output()
106
+			buildLog, err := oc.Run("logs").Args("-f", "bc/sample-verbose-build").Output()
107
+			fmt.Fprintf(g.GinkgoWriter, "\nbuild log:\n%s\n", buildLog)
108
+			o.Expect(err).NotTo(o.HaveOccurred())
109
+
110
+			g.By(fmt.Sprintf("verifying the build output is verbose"))
111
+			o.Expect(buildLog).To(o.ContainSubstring("Creating a new S2I builder"))
112
+		})
113
+
114
+		g.It("BUILD_LOGLEVEL in buildconfig can be overridden by build-loglevel", func() {
115
+			g.By("starting the build with buildconfig strategy env BUILD_LOGLEVEL=5 but build-loglevel=1")
116
+			out, err := oc.Run("start-build").Args("sample-verbose-build", "--build-loglevel=1").Output()
117
+			fmt.Fprintf(g.GinkgoWriter, "\nstart-build output:\n%s\n", out)
118
+			o.Expect(err).NotTo(o.HaveOccurred())
119
+
120
+			g.By("waiting for the build to complete")
121
+			err = exutil.WaitForABuild(oc.REST().Builds(oc.Namespace()), "sample-verbose-build-1", exutil.CheckBuildSuccessFn, exutil.CheckBuildFailedFn)
122
+			if err != nil {
123
+				exutil.DumpBuildLogs("sample-verbose-build", oc)
124
+			}
125
+
126
+			g.By("verifying the build output")
127
+			buildLog, err := oc.Run("logs").Args("-f", "bc/sample-verbose-build").Output()
107 128
 			fmt.Fprintf(g.GinkgoWriter, "\nbuild log:\n%s\n", buildLog)
108 129
 			o.Expect(err).NotTo(o.HaveOccurred())
109 130
 
110 131
 			g.By(fmt.Sprintf("verifying the build output is not verbose"))
111 132
 			o.Expect(buildLog).NotTo(o.ContainSubstring("Creating a new S2I builder"))
112 133
 		})
134
+
113 135
 	})
114 136
 
115 137
 	g.Describe("binary builds", func() {
... ...
@@ -1,48 +1,51 @@
1 1
 {
2
-  "kind":"BuildConfig",
3
-  "apiVersion":"v1",
4
-  "metadata":{
5
-    "name":"test",
6
-    "labels":{
7
-      "name":"test"
2
+  "kind": "BuildConfig",
3
+  "apiVersion": "v1",
4
+  "metadata": {
5
+    "name": "test",
6
+    "labels": {
7
+      "name": "test"
8 8
     }
9 9
   },
10
-  "spec":{
11
-    "triggers":[],
12
-    "source":{
13
-      "type":"Binary",
14
-      "binary": {
15
-      },
10
+  "spec": {
11
+    "triggers": [],
12
+    "source": {
13
+      "type": "Binary",
14
+      "binary": {},
16 15
       "secrets": [
17 16
         {
18
-          "secret": { "name": "testsecret" },
17
+          "secret": {
18
+            "name": "testsecret"
19
+          },
19 20
           "destinationDir": "secret-dir"
20 21
         },
21 22
         {
22
-          "secret": { "name": "testsecret2" }
23
+          "secret": {
24
+            "name": "testsecret2"
25
+          }
23 26
         }
24 27
       ]
25 28
     },
26
-    "strategy":{
27
-      "type":"Docker",
28
-      "env": [
29
-        {
30
-          "name": "BUILD_LOGLEVEL",
31
-          "value": "5"
32
-        }
33
-      ],
34
-      "dockerStrategy":{
35
-        "from":{
36
-          "kind":"DockerImage",
37
-          "name":"centos/ruby-22-centos7"
38
-        }
29
+    "strategy": {
30
+      "type": "Docker",
31
+      "dockerStrategy": {
32
+        "from": {
33
+          "kind": "DockerImage",
34
+          "name": "centos/ruby-22-centos7"
35
+        },
36
+        "env": [
37
+          {
38
+            "name": "BUILD_LOGLEVEL",
39
+            "value": "5"
40
+          }
41
+        ]
39 42
       }
40 43
     },
41
-    "output":{
42
-      "to":{
43
-        "kind":"ImageStreamTag",
44
-        "name":"test:latest"
44
+    "output": {
45
+      "to": {
46
+        "kind": "ImageStreamTag",
47
+        "name": "test:latest"
45 48
       }
46 49
     }
47 50
   }
48
-}
51
+}
49 52
\ No newline at end of file
... ...
@@ -11,8 +11,7 @@
11 11
     "triggers": [],
12 12
     "source": {
13 13
       "type": "Binary",
14
-      "binary": {
15
-      },
14
+      "binary": {},
16 15
       "secrets": [
17 16
         {
18 17
           "secret": {
... ...
@@ -29,17 +28,17 @@
29 29
     },
30 30
     "strategy": {
31 31
       "type": "Source",
32
-      "env": [
33
-        {
34
-          "name": "BUILD_LOGLEVEL",
35
-          "value": "5"
36
-        }
37
-      ],
38 32
       "sourceStrategy": {
39 33
         "from": {
40 34
           "kind": "DockerImage",
41 35
           "name": "centos/ruby-22-centos7"
42
-        }
36
+        },
37
+        "env": [
38
+          {
39
+            "name": "BUILD_LOGLEVEL",
40
+            "value": "5"
41
+          }
42
+        ]
43 43
       }
44 44
     },
45 45
     "output": {
... ...
@@ -1,58 +1,56 @@
1 1
 {
2
-    "kind": "List",
3
-    "apiVersion": "v1",
4
-    "metadata": {},
5
-    "items": [
6
-	{
7
-    
8
-	    "kind": "ImageStream",
9
-	    "apiVersion": "v1",
10
-	    "metadata": {
11
-		"name": "forcepull-extended-test-builder",
12
-		"creationTimestamp": null
13
-	    },
14
-	    "spec": {},
15
-	    "status": {
16
-		"dockerImageRepository": ""
17
-	    }
18
-    
19
-	},
20
-	{
21
-	    "kind": "BuildConfig",
22
-	    "apiVersion": "v1",
23
-	    "metadata": {
24
-		"name": "forcepull-bldr",
25
-		"creationTimestamp": null,
26
-		"labels": {
27
-		    "name": "forcepull-bldr"
28
-		}
29
-	    },
30
-	    "spec": {
31
-		"triggers": [],
32
-		"source": {
33
-		    "type": "Git",
34
-		    "git": {
35
-			"uri": "https://github.com/gabemontero/forcepull-extended-test-builder.git"
36
-		    }
37
-		},
38
-		"strategy": {
39
-		    "type": "Docker",
40
-		    "dockerStrategy": {
41
-			"env": [
42
-			    {
43
-				"name": "BUILD_LOGLEVEL",
44
-				"value": "5" 
45
-			    }
46
-			]
47
-		    }
2
+	"kind": "List",
3
+	"apiVersion": "v1",
4
+	"metadata": {},
5
+	"items": [
6
+		{
7
+			"kind": "ImageStream",
8
+			"apiVersion": "v1",
9
+			"metadata": {
10
+				"name": "forcepull-extended-test-builder",
11
+				"creationTimestamp": null
12
+			},
13
+			"spec": {},
14
+			"status": {
15
+				"dockerImageRepository": ""
16
+			}
48 17
 		},
49
-		"output":{
50
-		    "to":{
51
-			"kind":"ImageStreamTag",
52
-			"name":"forcepull-extended-test-builder:latest"
53
-		    }
18
+		{
19
+			"kind": "BuildConfig",
20
+			"apiVersion": "v1",
21
+			"metadata": {
22
+				"name": "forcepull-bldr",
23
+				"creationTimestamp": null,
24
+				"labels": {
25
+					"name": "forcepull-bldr"
26
+				}
27
+			},
28
+			"spec": {
29
+				"triggers": [],
30
+				"source": {
31
+					"type": "Git",
32
+					"git": {
33
+						"uri": "https://github.com/gabemontero/forcepull-extended-test-builder.git"
34
+					}
35
+				},
36
+				"strategy": {
37
+					"type": "Docker",
38
+					"dockerStrategy": {
39
+						"env": [
40
+							{
41
+								"name": "BUILD_LOGLEVEL",
42
+								"value": "5"
43
+							}
44
+						]
45
+					}
46
+				},
47
+				"output": {
48
+					"to": {
49
+						"kind": "ImageStreamTag",
50
+						"name": "forcepull-extended-test-builder:latest"
51
+					}
52
+				}
53
+			}
54 54
 		}
55
-	    }
56
-	}
57
-    ]
58
-}
55
+	]
56
+}
59 57
\ No newline at end of file
... ...
@@ -1,234 +1,233 @@
1 1
 {
2
-    "kind": "List",
3
-    "apiVersion": "v1",
4
-    "metadata": {},
5
-    "items": [
6
-	{
7
-	    "kind": "BuildConfig",
8
-	    "apiVersion": "v1",
9
-	    "metadata": {
10
-		"name": "ruby-sample-build-fc",
11
-		"creationTimestamp": null,
12
-		"labels": {
13
-		    "name": "ruby-sample-build-fc"
14
-		}
15
-	    },
16
-	    "spec": {
17
-		"triggers": [],
18
-		"source": {
19
-		    "type": "Git",
20
-		    "git": {
21
-			"uri": "https://github.com/openshift/ruby-hello-world.git"
22
-		    }
23
-		},
24
-		"strategy": {
25
-		    "type": "Custom",
26
-		    "customStrategy": {
27
-			"from": {
28
-			    "kind": "DockerImage",
29
-			    "name": "SERVICE_REGISTRY_IP/forcepull-extended-test-builder"
2
+	"kind": "List",
3
+	"apiVersion": "v1",
4
+	"metadata": {},
5
+	"items": [
6
+		{
7
+			"kind": "BuildConfig",
8
+			"apiVersion": "v1",
9
+			"metadata": {
10
+				"name": "ruby-sample-build-fc",
11
+				"creationTimestamp": null,
12
+				"labels": {
13
+					"name": "ruby-sample-build-fc"
14
+				}
30 15
 			},
31
-			"env": [
32
-			    {
33
-				"name": "OPENSHIFT_CUSTOM_BUILD_BASE_IMAGE",
34
-				"value": "SERVICE_REGISTRY_IP/forcepull-extended-test-builder"
35
-			    },
36
-			    {
37
-				"name": "BUILD_LOGLEVEL",
38
-				"value": "5" 
39
-			    }
40
-			],
41
-			"exposeDockerSocket": true,
42
-			"forcePull":false
43
-		    }
44
-		}
45
-	    }
46
-	},
47
-	{
48
-	    "kind": "BuildConfig",
49
-	    "apiVersion": "v1",
50
-	    "metadata": {
51
-		"name": "ruby-sample-build-fd",
52
-		"creationTimestamp": null,
53
-		"labels": {
54
-		    "name": "ruby-sample-build-fd"
55
-		}
56
-	    },
57
-	    "spec": {
58
-		"triggers": [],
59
-		"source": {
60
-		    "type": "Git",
61
-		    "git": {
62
-			"uri": "https://github.com/openshift/ruby-hello-world.git"
63
-		    }
16
+			"spec": {
17
+				"triggers": [],
18
+				"source": {
19
+					"type": "Git",
20
+					"git": {
21
+						"uri": "https://github.com/openshift/ruby-hello-world.git"
22
+					}
23
+				},
24
+				"strategy": {
25
+					"type": "Custom",
26
+					"customStrategy": {
27
+						"from": {
28
+							"kind": "DockerImage",
29
+							"name": "SERVICE_REGISTRY_IP/forcepull-extended-test-builder"
30
+						},
31
+						"env": [
32
+							{
33
+								"name": "OPENSHIFT_CUSTOM_BUILD_BASE_IMAGE",
34
+								"value": "SERVICE_REGISTRY_IP/forcepull-extended-test-builder"
35
+							},
36
+							{
37
+								"name": "BUILD_LOGLEVEL",
38
+								"value": "5"
39
+							}
40
+						],
41
+						"exposeDockerSocket": true,
42
+						"forcePull": false
43
+					}
44
+				}
45
+			}
64 46
 		},
65
-		"strategy": {
66
-		    "type": "Docker",
67
-		    "dockerStrategy": {
68
-			"from": {
69
-			    "kind": "DockerImage",
70
-			    "name": "SERVICE_REGISTRY_IP/forcepull-extended-test-builder"
47
+		{
48
+			"kind": "BuildConfig",
49
+			"apiVersion": "v1",
50
+			"metadata": {
51
+				"name": "ruby-sample-build-fd",
52
+				"creationTimestamp": null,
53
+				"labels": {
54
+					"name": "ruby-sample-build-fd"
55
+				}
71 56
 			},
72
-			"env": [
73
-			    {
74
-				"name": "BUILD_LOGLEVEL",
75
-				"value": "5" 
76
-			    }
77
-			],
78
-			"forcePull": false
79
-		    }
80
-		}
81
-	    }
82
-	},
83
-	{
84
-	    "kind": "BuildConfig",
85
-	    "apiVersion": "v1",
86
-	    "metadata": {
87
-		"name": "ruby-sample-build-fs",
88
-		"creationTimestamp": null,
89
-		"labels": {
90
-		    "name": "ruby-sample-build-fs"
91
-		}
92
-	    },
93
-	    "spec": {
94
-		"triggers": [],
95
-		"source": {
96
-		    "type": "Git",
97
-		    "git": {
98
-			"uri": "https://github.com/openshift/ruby-hello-world.git"
99
-		    }
57
+			"spec": {
58
+				"triggers": [],
59
+				"source": {
60
+					"type": "Git",
61
+					"git": {
62
+						"uri": "https://github.com/openshift/ruby-hello-world.git"
63
+					}
64
+				},
65
+				"strategy": {
66
+					"type": "Docker",
67
+					"dockerStrategy": {
68
+						"from": {
69
+							"kind": "DockerImage",
70
+							"name": "SERVICE_REGISTRY_IP/forcepull-extended-test-builder"
71
+						},
72
+						"env": [
73
+							{
74
+								"name": "BUILD_LOGLEVEL",
75
+								"value": "5"
76
+							}
77
+						],
78
+						"forcePull": false
79
+					}
80
+				}
81
+			}
100 82
 		},
101
-		"strategy": {
102
-		    "type": "Source",
103
-		    "sourceStrategy": {
104
-			"from": {
105
-			    "kind": "DockerImage",
106
-			    "name": "SERVICE_REGISTRY_IP/forcepull-extended-test-builder"
83
+		{
84
+			"kind": "BuildConfig",
85
+			"apiVersion": "v1",
86
+			"metadata": {
87
+				"name": "ruby-sample-build-fs",
88
+				"creationTimestamp": null,
89
+				"labels": {
90
+					"name": "ruby-sample-build-fs"
91
+				}
107 92
 			},
108
-			"env": [
109
-			    {
110
-				"name": "BUILD_LOGLEVEL",
111
-				"value": "5" 
112
-			    }
113
-			],
114
-			"forcePull": false
115
-		    }
116
-		}
117
-	    }
118
-	},
119
-	{
120
-	    "kind": "BuildConfig",
121
-	    "apiVersion": "v1",
122
-	    "metadata": {
123
-		"name": "ruby-sample-build-tc",
124
-		"creationTimestamp": null,
125
-		"labels": {
126
-		    "name": "ruby-sample-build-tc"
127
-		}
128
-	    },
129
-	    "spec": {
130
-		"triggers": [],
131
-		"source": {
132
-		    "type": "Git",
133
-		    "git": {
134
-			"uri": "https://github.com/openshift/ruby-hello-world.git"
135
-		    }
93
+			"spec": {
94
+				"triggers": [],
95
+				"source": {
96
+					"type": "Git",
97
+					"git": {
98
+						"uri": "https://github.com/openshift/ruby-hello-world.git"
99
+					}
100
+				},
101
+				"strategy": {
102
+					"type": "Source",
103
+					"sourceStrategy": {
104
+						"from": {
105
+							"kind": "DockerImage",
106
+							"name": "SERVICE_REGISTRY_IP/forcepull-extended-test-builder"
107
+						},
108
+						"env": [
109
+							{
110
+								"name": "BUILD_LOGLEVEL",
111
+								"value": "5"
112
+							}
113
+						],
114
+						"forcePull": false
115
+					}
116
+				}
117
+			}
136 118
 		},
137
-		"strategy": {
138
-		    "type": "Custom",
139
-		    "customStrategy": {
140
-			"from": {
141
-			    "kind": "DockerImage",
142
-			    "name": "SERVICE_REGISTRY_IP/forcepull-extended-test-builder"
119
+		{
120
+			"kind": "BuildConfig",
121
+			"apiVersion": "v1",
122
+			"metadata": {
123
+				"name": "ruby-sample-build-tc",
124
+				"creationTimestamp": null,
125
+				"labels": {
126
+					"name": "ruby-sample-build-tc"
127
+				}
143 128
 			},
144
-			"env": [
145
-			    {
146
-				"name": "OPENSHIFT_CUSTOM_BUILD_BASE_IMAGE",
147
-				"value": "SERVICE_REGISTRY_IP/forcepull-extended-test-builder"
148
-			    },
149
-			    {
150
-				"name": "BUILD_LOGLEVEL",
151
-				"value": "5" 
152
-			    }
153
-			],
154
-			"exposeDockerSocket": true,
155
-			"forcePull":true
156
-		    }
157
-		}
158
-	    }
159
-	},
160
-	{
161
-	    "kind": "BuildConfig",
162
-	    "apiVersion": "v1",
163
-	    "metadata": {
164
-		"name": "ruby-sample-build-td",
165
-		"creationTimestamp": null,
166
-		"labels": {
167
-		    "name": "ruby-sample-build-td"
168
-		}
169
-	    },
170
-	    "spec": {
171
-		"triggers": [],
172
-		"source": {
173
-		    "type": "Git",
174
-		    "git": {
175
-			"uri": "https://github.com/openshift/ruby-hello-world.git"
176
-		    }
129
+			"spec": {
130
+				"triggers": [],
131
+				"source": {
132
+					"type": "Git",
133
+					"git": {
134
+						"uri": "https://github.com/openshift/ruby-hello-world.git"
135
+					}
136
+				},
137
+				"strategy": {
138
+					"type": "Custom",
139
+					"customStrategy": {
140
+						"from": {
141
+							"kind": "DockerImage",
142
+							"name": "SERVICE_REGISTRY_IP/forcepull-extended-test-builder"
143
+						},
144
+						"env": [
145
+							{
146
+								"name": "OPENSHIFT_CUSTOM_BUILD_BASE_IMAGE",
147
+								"value": "SERVICE_REGISTRY_IP/forcepull-extended-test-builder"
148
+							},
149
+							{
150
+								"name": "BUILD_LOGLEVEL",
151
+								"value": "5"
152
+							}
153
+						],
154
+						"exposeDockerSocket": true,
155
+						"forcePull": true
156
+					}
157
+				}
158
+			}
177 159
 		},
178
-		"strategy": {
179
-		    "type": "Docker",
180
-		    "dockerStrategy": {
181
-			"from": {
182
-			    "kind": "DockerImage",
183
-			    "name": "SERVICE_REGISTRY_IP/forcepull-extended-test-builder"
160
+		{
161
+			"kind": "BuildConfig",
162
+			"apiVersion": "v1",
163
+			"metadata": {
164
+				"name": "ruby-sample-build-td",
165
+				"creationTimestamp": null,
166
+				"labels": {
167
+					"name": "ruby-sample-build-td"
168
+				}
184 169
 			},
185
-			"env": [
186
-			    {
187
-				"name": "BUILD_LOGLEVEL",
188
-				"value": "5" 
189
-			    }
190
-			],
191
-			"forcePull": true
192
-		    }
193
-		}
194
-	    }
195
-	},
196
-	{
197
-	    "kind": "BuildConfig",
198
-	    "apiVersion": "v1",
199
-	    "metadata": {
200
-		"name": "ruby-sample-build-ts",
201
-		"creationTimestamp": null,
202
-		"labels": {
203
-		    "name": "ruby-sample-build-ts"
204
-		}
205
-	    },
206
-	    "spec": {
207
-		"triggers": [],
208
-		"source": {
209
-		    "type": "Git",
210
-		    "git": {
211
-			"uri": "https://github.com/openshift/ruby-hello-world.git"
212
-		    }
170
+			"spec": {
171
+				"triggers": [],
172
+				"source": {
173
+					"type": "Git",
174
+					"git": {
175
+						"uri": "https://github.com/openshift/ruby-hello-world.git"
176
+					}
177
+				},
178
+				"strategy": {
179
+					"type": "Docker",
180
+					"dockerStrategy": {
181
+						"from": {
182
+							"kind": "DockerImage",
183
+							"name": "SERVICE_REGISTRY_IP/forcepull-extended-test-builder"
184
+						},
185
+						"env": [
186
+							{
187
+								"name": "BUILD_LOGLEVEL",
188
+								"value": "5"
189
+							}
190
+						],
191
+						"forcePull": true
192
+					}
193
+				}
194
+			}
213 195
 		},
214
-		"strategy": {
215
-		    "type": "Source",
216
-		    "sourceStrategy": {
217
-			"from": {
218
-			    "kind": "DockerImage",
219
-			    "name": "SERVICE_REGISTRY_IP/forcepull-extended-test-builder"
196
+		{
197
+			"kind": "BuildConfig",
198
+			"apiVersion": "v1",
199
+			"metadata": {
200
+				"name": "ruby-sample-build-ts",
201
+				"creationTimestamp": null,
202
+				"labels": {
203
+					"name": "ruby-sample-build-ts"
204
+				}
220 205
 			},
221
-			"env": [
222
-			    {
223
-				"name": "BUILD_LOGLEVEL",
224
-				"value": "5" 
225
-			    }
226
-			],
227
-			"forcePull": true
228
-		    }
206
+			"spec": {
207
+				"triggers": [],
208
+				"source": {
209
+					"type": "Git",
210
+					"git": {
211
+						"uri": "https://github.com/openshift/ruby-hello-world.git"
212
+					}
213
+				},
214
+				"strategy": {
215
+					"type": "Source",
216
+					"sourceStrategy": {
217
+						"from": {
218
+							"kind": "DockerImage",
219
+							"name": "SERVICE_REGISTRY_IP/forcepull-extended-test-builder"
220
+						},
221
+						"env": [
222
+							{
223
+								"name": "BUILD_LOGLEVEL",
224
+								"value": "5"
225
+							}
226
+						],
227
+						"forcePull": true
228
+					}
229
+				}
230
+			}
229 231
 		}
230
-	    }
231
-	}	
232
-
233
-    ]
234
-}
232
+	]
233
+}
235 234
\ No newline at end of file
... ...
@@ -39,13 +39,13 @@
39 39
         },
40 40
         "strategy": {
41 41
           "type": "Source",
42
-          "env": [
43
-            {
44
-              "name": "BUILD_LOGLEVEL",
45
-              "value": "5"
46
-            }
47
-          ],
48 42
           "sourceStrategy": {
43
+            "env": [
44
+              {
45
+                "name": "BUILD_LOGLEVEL",
46
+                "value": "5"
47
+              }
48
+            ],
49 49
             "from": {
50 50
               "kind": "DockerImage",
51 51
               "name": "centos/ruby-22-centos7:latest"
... ...
@@ -83,13 +83,13 @@
83 83
         },
84 84
         "strategy": {
85 85
           "type": "Source",
86
-          "env": [
87
-            {
88
-              "name": "BUILD_LOGLEVEL",
89
-              "value": "5"
90
-            }
91
-          ],
92 86
           "sourceStrategy": {
87
+            "env": [
88
+              {
89
+                "name": "BUILD_LOGLEVEL",
90
+                "value": "5"
91
+              }
92
+            ],
93 93
             "from": {
94 94
               "kind": "ImageStreamTag",
95 95
               "name": "internal-image:latest"
... ...
@@ -105,11 +105,9 @@
105 105
         }
106 106
       }
107 107
     }
108
-
109
-  ],
110
-  "parameters": [
111 108
   ],
109
+  "parameters": [],
112 110
   "labels": {
113 111
     "template": "application-template-stibuild"
114 112
   }
115
-}
113
+}
116 114
\ No newline at end of file
... ...
@@ -40,7 +40,48 @@
40 40
           "sourceStrategy": {
41 41
             "env": [
42 42
               { "name": "FOO", "value": "test" },
43
-              { "name": "BAR", "value": "test" }
43
+              { "name": "BAR", "value": "test" },
44
+              { "name": "BUILD_LOGLEVEL", "value": "5" }
45
+            ],
46
+            "from": {
47
+              "kind": "DockerImage",
48
+              "name": "centos/ruby-22-centos7"
49
+            }
50
+          }
51
+        },
52
+        "resources": {}
53
+      },
54
+      "status": {
55
+        "lastVersion": 0
56
+      }
57
+    },
58
+    {
59
+      "kind": "BuildConfig",
60
+      "apiVersion": "v1",
61
+      "metadata": {
62
+        "name": "sample-verbose-build",
63
+        "creationTimestamp": null
64
+      },
65
+      "spec": {
66
+        "triggers": [
67
+          {
68
+            "type": "imageChange",
69
+            "imageChange": {}
70
+          }
71
+        ],
72
+        "source": {
73
+          "type": "Git",
74
+          "git": {
75
+            "uri": "git://github.com/openshift/ruby-hello-world.git"
76
+          }
77
+        },
78
+        "strategy": {
79
+          "type": "Source",
80
+          "sourceStrategy": {
81
+            "env": [
82
+              { "name": "FOO", "value": "test" },
83
+              { "name": "BAR", "value": "test" },
84
+              { "name": "BUILD_LOGLEVEL", "value": "5" }
44 85
             ],
45 86
             "from": {
46 87
               "kind": "DockerImage",
... ...
@@ -77,7 +118,8 @@
77 77
           "dockerStrategy": {
78 78
             "env": [
79 79
               { "name": "FOO", "value": "test" },
80
-              { "name": "BAR", "value": "test" }
80
+              { "name": "BAR", "value": "test" },
81
+              { "name": "BUILD_LOGLEVEL", "value": "5" }
81 82
             ],
82 83
             "from": {
83 84
               "kind": "DockerImage",
... ...
@@ -1,34 +1,34 @@
1 1
 {
2
-  "kind":"BuildConfig",
3
-  "apiVersion":"v1",
4
-  "metadata":{
5
-    "name":"test-docker",
6
-    "labels":{
7
-      "name":"test-docker"
2
+  "kind": "BuildConfig",
3
+  "apiVersion": "v1",
4
+  "metadata": {
5
+    "name": "test-docker",
6
+    "labels": {
7
+      "name": "test-docker"
8 8
     }
9 9
   },
10
-  "spec":{
11
-    "triggers":[],
12
-    "source":{
13
-      "type":"Git",
14
-      "git":{
15
-        "uri":"https://github.com/openshift/ruby-hello-world"
10
+  "spec": {
11
+    "triggers": [],
12
+    "source": {
13
+      "type": "Git",
14
+      "git": {
15
+        "uri": "https://github.com/openshift/ruby-hello-world"
16 16
       }
17 17
     },
18
-    "strategy":{
19
-      "type":"Docker",
20
-      "env": [
21
-        {
22
-          "name": "BUILD_LOGLEVEL",
23
-          "value": "5"
24
-        }
25
-      ],
26
-      "dockerStrategy":{
27
-        "from":{
28
-          "kind":"DockerImage",
29
-          "name":"centos/ruby-22-centos7"
18
+    "strategy": {
19
+      "type": "Docker",
20
+      "dockerStrategy": {
21
+        "env": [
22
+          {
23
+            "name": "BUILD_LOGLEVEL",
24
+            "value": "5"
25
+          }
26
+        ],
27
+        "from": {
28
+          "kind": "DockerImage",
29
+          "name": "centos/ruby-22-centos7"
30 30
         }
31 31
       }
32 32
     }
33 33
   }
34
-}
34
+}
35 35
\ No newline at end of file
... ...
@@ -1,41 +1,41 @@
1 1
 {
2
-  "kind":"BuildConfig",
3
-  "apiVersion":"v1",
4
-  "metadata":{
5
-    "name":"test",
6
-    "labels":{
7
-      "name":"test"
2
+  "kind": "BuildConfig",
3
+  "apiVersion": "v1",
4
+  "metadata": {
5
+    "name": "test",
6
+    "labels": {
7
+      "name": "test"
8 8
     }
9 9
   },
10
-  "spec":{
11
-    "triggers":[],
12
-    "source":{
13
-      "type":"Git",
14
-      "git":{
15
-        "uri":"https://github.com/openshift/origin"
10
+  "spec": {
11
+    "triggers": [],
12
+    "source": {
13
+      "type": "Git",
14
+      "git": {
15
+        "uri": "https://github.com/openshift/origin"
16 16
       },
17
-      "contextDir":"test/extended/testdata/test-build-app"
17
+      "contextDir": "test/extended/testdata/test-build-app"
18 18
     },
19
-    "strategy":{
20
-      "type":"Source",
21
-      "env": [
22
-        {
23
-          "name": "BUILD_LOGLEVEL",
24
-          "value": "5"
25
-        }
26
-      ],
27
-      "sourceStrategy":{
28
-        "from":{
29
-          "kind":"DockerImage",
30
-          "name":"centos/ruby-22-centos7"
19
+    "strategy": {
20
+      "type": "Source",
21
+      "sourceStrategy": {
22
+        "env": [
23
+          {
24
+            "name": "BUILD_LOGLEVEL",
25
+            "value": "5"
26
+          }
27
+        ],
28
+        "from": {
29
+          "kind": "DockerImage",
30
+          "name": "centos/ruby-22-centos7"
31 31
         }
32 32
       }
33 33
     },
34
-    "output":{
35
-      "to":{
36
-        "kind":"ImageStreamTag",
37
-        "name":"test:latest"
34
+    "output": {
35
+      "to": {
36
+        "kind": "ImageStreamTag",
37
+        "name": "test:latest"
38 38
       }
39 39
     }
40 40
   }
41
-}
41
+}
42 42
\ No newline at end of file
... ...
@@ -1,34 +1,34 @@
1 1
 {
2
-"kind":"BuildConfig",
3
-  "apiVersion":"v1",
4
-  "metadata":{
5
-    "name":"test-sti",
6
-    "labels":{
7
-      "name":"test-sti"
2
+  "kind": "BuildConfig",
3
+  "apiVersion": "v1",
4
+  "metadata": {
5
+    "name": "test-sti",
6
+    "labels": {
7
+      "name": "test-sti"
8 8
     }
9 9
   },
10
-  "spec":{
11
-    "triggers":[],
12
-    "source":{
13
-      "type":"Git",
14
-      "git":{
15
-        "uri":"https://github.com/openshift/ruby-hello-world"
10
+  "spec": {
11
+    "triggers": [],
12
+    "source": {
13
+      "type": "Git",
14
+      "git": {
15
+        "uri": "https://github.com/openshift/ruby-hello-world"
16 16
       }
17 17
     },
18
-    "strategy":{
19
-      "type":"Source",
20
-      "env": [
21
-        {
22
-          "name": "BUILD_LOGLEVEL",
23
-          "value": "5"
24
-        }
25
-      ],
26
-      "sourceStrategy":{
27
-        "from":{
28
-          "kind":"DockerImage",
29
-          "name":"centos/ruby-22-centos7"
18
+    "strategy": {
19
+      "type": "Source",
20
+      "sourceStrategy": {
21
+        "env": [
22
+          {
23
+            "name": "BUILD_LOGLEVEL",
24
+            "value": "5"
25
+          }
26
+        ],
27
+        "from": {
28
+          "kind": "DockerImage",
29
+          "name": "centos/ruby-22-centos7"
30 30
         }
31 31
       }
32 32
     }
33 33
   }
34
-}
34
+}
35 35
\ No newline at end of file