Browse code

Set Build.Status.Pushspec to resolved pushspec

Rodolfo Carvalho authored on 2015/09/25 21:27:55
Showing 12 changed files
... ...
@@ -14501,6 +14501,10 @@
14501 14501
       "$ref": "time.Duration",
14502 14502
       "description": "amount of time the build has been running"
14503 14503
      },
14504
+     "outputDockerImageReference": {
14505
+      "type": "string",
14506
+      "description": "reference to the Docker image built by this build, computed from build.spec.output.to, and can be used to push and pull the image"
14507
+     },
14504 14508
      "config": {
14505 14509
       "$ref": "v1.ObjectReference",
14506 14510
       "description": "reference to build config from which this build was derived"
... ...
@@ -935,6 +935,7 @@ func deepCopy_api_BuildStatus(in buildapi.BuildStatus, out *buildapi.BuildStatus
935 935
 		out.CompletionTimestamp = nil
936 936
 	}
937 937
 	out.Duration = in.Duration
938
+	out.OutputDockerImageReference = in.OutputDockerImageReference
938 939
 	if in.Config != nil {
939 940
 		if newVal, err := c.DeepCopy(in.Config); err != nil {
940 941
 			return err
... ...
@@ -357,9 +357,6 @@ func roundTrip(t *testing.T, codec runtime.Codec, originalItem runtime.Object) {
357 357
 var skipStandardVersions = map[string][]string{
358 358
 	"DockerImage": {"pre012", "1.0"},
359 359
 }
360
-var skipV1beta1 = map[string]struct{}{}
361
-var skipV1beta3 = map[string]struct{}{}
362
-var skipV1 = map[string]struct{}{}
363 360
 
364 361
 const fuzzIters = 20
365 362
 
... ...
@@ -408,14 +405,10 @@ func TestTypes(t *testing.T) {
408 408
 			}
409 409
 			fuzzInternalObject(t, "", item, seed)
410 410
 			roundTrip(t, osapi.Codec, item)
411
-			if _, ok := skipV1beta3[kind]; !ok {
412
-				fuzzInternalObject(t, "v1beta3", item, seed)
413
-				roundTrip(t, v1beta3.Codec, item)
414
-			}
415
-			if _, ok := skipV1[kind]; !ok {
416
-				fuzzInternalObject(t, "v1", item, seed)
417
-				roundTrip(t, v1.Codec, item)
418
-			}
411
+			fuzzInternalObject(t, "v1beta3", item, seed)
412
+			roundTrip(t, v1beta3.Codec, item)
413
+			fuzzInternalObject(t, "v1", item, seed)
414
+			roundTrip(t, v1.Codec, item)
419 415
 		}
420 416
 	}
421 417
 }
... ...
@@ -796,6 +796,7 @@ func convert_api_BuildStatus_To_v1_BuildStatus(in *buildapi.BuildStatus, out *ap
796 796
 		out.CompletionTimestamp = nil
797 797
 	}
798 798
 	out.Duration = in.Duration
799
+	out.OutputDockerImageReference = in.OutputDockerImageReference
799 800
 	if in.Config != nil {
800 801
 		out.Config = new(pkgapiv1.ObjectReference)
801 802
 		if err := convert_api_ObjectReference_To_v1_ObjectReference(in.Config, out.Config, s); err != nil {
... ...
@@ -1183,6 +1184,7 @@ func convert_v1_BuildStatus_To_api_BuildStatus(in *apiv1.BuildStatus, out *build
1183 1183
 		out.CompletionTimestamp = nil
1184 1184
 	}
1185 1185
 	out.Duration = in.Duration
1186
+	out.OutputDockerImageReference = in.OutputDockerImageReference
1186 1187
 	if in.Config != nil {
1187 1188
 		out.Config = new(pkgapi.ObjectReference)
1188 1189
 		if err := convert_v1_ObjectReference_To_api_ObjectReference(in.Config, out.Config, s); err != nil {
... ...
@@ -960,6 +960,7 @@ func deepCopy_v1_BuildStatus(in apiv1.BuildStatus, out *apiv1.BuildStatus, c *co
960 960
 		out.CompletionTimestamp = nil
961 961
 	}
962 962
 	out.Duration = in.Duration
963
+	out.OutputDockerImageReference = in.OutputDockerImageReference
963 964
 	if in.Config != nil {
964 965
 		if newVal, err := c.DeepCopy(in.Config); err != nil {
965 966
 			return err
... ...
@@ -834,6 +834,7 @@ func convert_api_BuildStatus_To_v1beta3_BuildStatus(in *buildapi.BuildStatus, ou
834 834
 		out.CompletionTimestamp = nil
835 835
 	}
836 836
 	out.Duration = in.Duration
837
+	out.OutputDockerImageReference = in.OutputDockerImageReference
837 838
 	if in.Config != nil {
838 839
 		out.Config = new(pkgapiv1beta3.ObjectReference)
839 840
 		if err := convert_api_ObjectReference_To_v1beta3_ObjectReference(in.Config, out.Config, s); err != nil {
... ...
@@ -1221,6 +1222,7 @@ func convert_v1beta3_BuildStatus_To_api_BuildStatus(in *apiv1beta3.BuildStatus,
1221 1221
 		out.CompletionTimestamp = nil
1222 1222
 	}
1223 1223
 	out.Duration = in.Duration
1224
+	out.OutputDockerImageReference = in.OutputDockerImageReference
1224 1225
 	if in.Config != nil {
1225 1226
 		out.Config = new(pkgapi.ObjectReference)
1226 1227
 		if err := convert_v1beta3_ObjectReference_To_api_ObjectReference(in.Config, out.Config, s); err != nil {
... ...
@@ -968,6 +968,7 @@ func deepCopy_v1beta3_BuildStatus(in apiv1beta3.BuildStatus, out *apiv1beta3.Bui
968 968
 		out.CompletionTimestamp = nil
969 969
 	}
970 970
 	out.Duration = in.Duration
971
+	out.OutputDockerImageReference = in.OutputDockerImageReference
971 972
 	if in.Config != nil {
972 973
 		if newVal, err := c.DeepCopy(in.Config); err != nil {
973 974
 			return err
... ...
@@ -84,6 +84,12 @@ type BuildStatus struct {
84 84
 	// Duration contains time.Duration object describing build time.
85 85
 	Duration time.Duration
86 86
 
87
+	// OutputDockerImageReference contains a reference to the Docker image that
88
+	// will be built by this build. It's value is computed from
89
+	// Build.Spec.Output.To, and should include the registry address, so that
90
+	// it can be used to push and pull the image.
91
+	OutputDockerImageReference string
92
+
87 93
 	// Config is an ObjectReference to the BuildConfig this Build is based on.
88 94
 	Config *kapi.ObjectReference
89 95
 }
... ...
@@ -69,6 +69,12 @@ type BuildStatus struct {
69 69
 	// Duration contains time.Duration object describing build time.
70 70
 	Duration time.Duration `json:"duration,omitempty" description:"amount of time the build has been running"`
71 71
 
72
+	// OutputDockerImageReference contains a reference to the Docker image that
73
+	// will be built by this build. It's value is computed from
74
+	// Build.Spec.Output.To, and should include the registry address, so that
75
+	// it can be used to push and pull the image.
76
+	OutputDockerImageReference string `json:"outputDockerImageReference,omitempty" description:"reference to the Docker image built by this build, computed from build.spec.output.to, and can be used to push and pull the image"`
77
+
72 78
 	// Config is an ObjectReference to the BuildConfig this Build is based on.
73 79
 	Config *kapi.ObjectReference `json:"config,omitempty" description:"reference to build config from which this build was derived"`
74 80
 }
... ...
@@ -69,6 +69,12 @@ type BuildStatus struct {
69 69
 	// Duration contains time.Duration object describing build time.
70 70
 	Duration time.Duration `json:"duration,omitempty"`
71 71
 
72
+	// OutputDockerImageReference contains a reference to the Docker image that
73
+	// will be built by this build. It's value is computed from
74
+	// Build.Spec.Output.To, and should include the registry address, so that
75
+	// it can be used to push and pull the image.
76
+	OutputDockerImageReference string `json:"outputDockerImageReference,omitempty" description:"reference to the Docker image built by this build, computed from build.spec.output.to, and can be used to push and pull the image"`
77
+
72 78
 	// Config is an ObjectReference to the BuildConfig this Build is based on.
73 79
 	Config *kapi.ObjectReference `json:"config,omitempty"`
74 80
 }
... ...
@@ -2,9 +2,10 @@ package controller
2 2
 
3 3
 import (
4 4
 	"fmt"
5
-	"github.com/golang/glog"
6 5
 	"strings"
7 6
 
7
+	"github.com/golang/glog"
8
+
8 9
 	kapi "k8s.io/kubernetes/pkg/api"
9 10
 	errors "k8s.io/kubernetes/pkg/api/errors"
10 11
 	"k8s.io/kubernetes/pkg/client/cache"
... ...
@@ -115,61 +116,38 @@ func (bc *BuildController) nextBuildPhase(build *buildapi.Build) error {
115 115
 		return nil
116 116
 	}
117 117
 
118
-	// lookup the destination from the referenced image repository
119
-	var spec string
120
-	if ref := build.Spec.Output.To; ref != nil && len(ref.Name) != 0 {
121
-		switch {
122
-		case ref.Kind == "DockerImage":
123
-			spec = ref.Name
124
-		case ref.Kind == "ImageStream" || ref.Kind == "ImageStreamTag":
125
-			// TODO: security, ensure that the reference image stream is actually visible
126
-			namespace := ref.Namespace
127
-			if len(namespace) == 0 {
128
-				namespace = build.Namespace
129
-			}
130
-
131
-			var tag string
132
-			streamName := ref.Name
133
-			if ref.Kind == "ImageStreamTag" {
134
-				bits := strings.Split(ref.Name, ":")
135
-				streamName = bits[0]
136
-				tag = ":" + bits[1]
137
-			}
138
-			stream, err := bc.ImageStreamClient.GetImageStream(namespace, streamName)
139
-			if err != nil {
140
-				if errors.IsNotFound(err) {
141
-					return fmt.Errorf("the referenced output ImageStream %s/%s does not exist", namespace, streamName)
142
-				}
143
-				return fmt.Errorf("the referenced output ImageStream %s/%s could not be found by Build %s/%s: %v", namespace, streamName, build.Namespace, build.Name, err)
144
-			}
145
-			if len(stream.Status.DockerImageRepository) == 0 {
146
-				e := fmt.Errorf("the ImageStream %s/%s cannot be used as the output for Build %s/%s because the integrated Docker registry is not configured, or the user forgot to set a valid external registry", namespace, ref.Name, build.Namespace, build.Name)
147
-				bc.Recorder.Eventf(build, "invalidOutput", "Error starting build: %v", e)
148
-				return e
149
-			}
150
-			spec = fmt.Sprintf("%s%s", stream.Status.DockerImageRepository, tag)
151
-		}
118
+	// Set the output Docker image reference.
119
+	ref, err := bc.resolveOutputDockerImageReference(build)
120
+	if err != nil {
121
+		return err
152 122
 	}
123
+	build.Status.OutputDockerImageReference = ref
153 124
 
154
-	// set the expected build parameters, which will be saved if no error occurs
125
+	// Set the build phase, which will be persisted if no error occurs.
155 126
 	build.Status.Phase = buildapi.BuildPhasePending
156 127
 
157
-	// Make a copy to avoid mutating the build from this point on
128
+	// Make a copy to avoid mutating the build from this point on.
158 129
 	copy, err := kapi.Scheme.Copy(build)
159 130
 	if err != nil {
160 131
 		return fmt.Errorf("unable to copy Build: %v", err)
161 132
 	}
162 133
 	buildCopy := copy.(*buildapi.Build)
163 134
 
164
-	// override the Output to be a DockerImage type in the strategy for the copy we send to the build pod
135
+	// TODO(rhcarvalho)
136
+	// The S2I and Docker builders expect build.Spec.Output.To to contain a
137
+	// resolved reference to a Docker image. Since build.Spec is immutable, we
138
+	// change a copy (that is never persisted) and pass it to
139
+	// bc.BuildStrategy.CreateBuildPod. We should make the builders use
140
+	// build.Status.OutputDockerImageReference, what will make copying the build
141
+	// unnecessary.
165 142
 	if build.Spec.Output.To != nil && len(build.Spec.Output.To.Name) != 0 {
166 143
 		buildCopy.Spec.Output.To = &kapi.ObjectReference{
167 144
 			Kind: "DockerImage",
168
-			Name: spec,
145
+			Name: ref,
169 146
 		}
170 147
 	}
171 148
 
172
-	// invoke the strategy to get a build pod
149
+	// Invoke the strategy to get a build pod.
173 150
 	podSpec, err := bc.BuildStrategy.CreateBuildPod(buildCopy)
174 151
 	if err != nil {
175 152
 		return fmt.Errorf("the strategy failed to create a build pod for Build %s/%s: %v", build.Namespace, build.Name, err)
... ...
@@ -181,7 +159,7 @@ func (bc *BuildController) nextBuildPhase(build *buildapi.Build) error {
181 181
 			glog.V(4).Infof("Build pod already existed: %#v", podSpec)
182 182
 			return nil
183 183
 		}
184
-		// log an event if the pod is not created (most likely due to quota denial)
184
+		// Log an event if the pod is not created (most likely due to quota denial).
185 185
 		bc.Recorder.Eventf(build, "failedCreate", "Error creating: %v", err)
186 186
 		return fmt.Errorf("failed to create pod for Build %s/%s: %v", build.Namespace, build.Name, err)
187 187
 	}
... ...
@@ -190,6 +168,48 @@ func (bc *BuildController) nextBuildPhase(build *buildapi.Build) error {
190 190
 	return nil
191 191
 }
192 192
 
193
+// resolveOutputDockerImageReference returns a reference to a Docker image
194
+// computed from the buid.Spec.Output.To reference.
195
+func (bc *BuildController) resolveOutputDockerImageReference(build *buildapi.Build) (string, error) {
196
+	outputTo := build.Spec.Output.To
197
+	if outputTo == nil || outputTo.Name == "" {
198
+		return "", nil
199
+	}
200
+	var ref string
201
+	switch outputTo.Kind {
202
+	case "DockerImage":
203
+		ref = outputTo.Name
204
+	case "ImageStream", "ImageStreamTag":
205
+		// TODO(smarterclayton): security, ensure that the reference image stream is actually visible
206
+		namespace := outputTo.Namespace
207
+		if len(namespace) == 0 {
208
+			namespace = build.Namespace
209
+		}
210
+
211
+		var tag string
212
+		streamName := outputTo.Name
213
+		if outputTo.Kind == "ImageStreamTag" {
214
+			bits := strings.Split(outputTo.Name, ":")
215
+			streamName = bits[0]
216
+			tag = ":" + bits[1]
217
+		}
218
+		stream, err := bc.ImageStreamClient.GetImageStream(namespace, streamName)
219
+		if err != nil {
220
+			if errors.IsNotFound(err) {
221
+				return "", fmt.Errorf("the referenced output ImageStream %s/%s does not exist", namespace, streamName)
222
+			}
223
+			return "", fmt.Errorf("the referenced output ImageStream %s/%s could not be found by Build %s/%s: %v", namespace, streamName, build.Namespace, build.Name, err)
224
+		}
225
+		if len(stream.Status.DockerImageRepository) == 0 {
226
+			e := fmt.Errorf("the ImageStream %s/%s cannot be used as the output for Build %s/%s because the integrated Docker registry is not configured and no external registry was defined", namespace, outputTo.Name, build.Namespace, build.Name)
227
+			bc.Recorder.Eventf(build, "invalidOutput", "Error starting build: %v", e)
228
+			return "", e
229
+		}
230
+		ref = fmt.Sprintf("%s%s", stream.Status.DockerImageRepository, tag)
231
+	}
232
+	return ref, nil
233
+}
234
+
193 235
 // BuildPodController watches pods running builds and manages the build state
194 236
 type BuildPodController struct {
195 237
 	BuildStore   cache.Store
... ...
@@ -395,6 +395,9 @@ func TestHandleBuild(t *testing.T) {
395 395
 			if build.Spec.Output.To.Name != tc.outputSpec {
396 396
 				t.Errorf("(%d) expected build sent to strategy to have docker spec %s, got %s", i, tc.outputSpec, build.Spec.Output.To.Name)
397 397
 			}
398
+			if build.Status.OutputDockerImageReference != tc.outputSpec {
399
+				t.Errorf("(%d) expected build status to have OutputDockerImageReference %s, got %s", i, tc.outputSpec, build.Status.OutputDockerImageReference)
400
+			}
398 401
 		}
399 402
 	}
400 403
 }