| ... | ... |
@@ -87,6 +87,7 @@ func TestExampleObjectSchemas(t *testing.T) {
|
| 87 | 87 |
"test-route": &routeapi.Route{},
|
| 88 | 88 |
"test-service": &kapi.Service{},
|
| 89 | 89 |
"test-buildcli": &kapi.List{},
|
| 90 |
+ "test-buildcli-beta2": &kapi.List{},
|
|
| 90 | 91 |
}, |
| 91 | 92 |
"../test/templates/fixtures": {
|
| 92 | 93 |
"crunchydata-pod": nil, // Explicitly fails validation, but should pass transformation |
| ... | ... |
@@ -177,18 +177,25 @@ This section covers how to perform all the steps of building, deploying, and upd |
| 177 | 177 |
|
| 178 | 178 |
8. Confirm the registry is accessible (you may need to run this more than once): |
| 179 | 179 |
|
| 180 |
- $ curl `osc get service docker-registry --template="{{ .portalIP}}:{{ .port }}"`
|
|
| 180 |
+ $ export DOCKER_REGISTRY=`osc get service docker-registry --template="{{ .portalIP}}:{{ .port }}"`
|
|
| 181 |
+ $ curl $DOCKER_REGISTRY |
|
| 181 | 182 |
|
| 182 | 183 |
You should see: |
| 183 | 184 |
|
| 184 | 185 |
"docker-registry server (dev) (v0.9.0)" |
| 185 | 186 |
|
| 186 | 187 |
|
| 187 |
-9. Create a new project in OpenShift. This creates a namespace `test` to contain the builds and app that we will generate below. |
|
| 188 |
+9. Push builder image to private docker-registry: |
|
| 189 |
+ |
|
| 190 |
+ $ docker pull openshift/ruby-20-centos7:latest |
|
| 191 |
+ $ docker tag -f openshift/ruby-20-centos7:latest ${DOCKER_REGISTRY}/test/ruby-20-centos7:latest
|
|
| 192 |
+ $ docker push ${DOCKER_REGISTRY}/test/ruby-20-centos7:latest
|
|
| 193 |
+ |
|
| 194 |
+10. Create a new project in OpenShift. This creates a namespace `test` to contain the builds and app that we will generate below. |
|
| 188 | 195 |
|
| 189 | 196 |
$ openshift ex new-project test --display-name="OpenShift 3 Sample" --description="This is an example project to demonstrate OpenShift v3" --admin=anypassword:test-admin |
| 190 | 197 |
|
| 191 |
-10. *Optional:* View the OpenShift web console in your browser by browsing to `https://<host>:8444`. Login using the user `test-admin` and any password. |
|
| 198 |
+11. *Optional:* View the OpenShift web console in your browser by browsing to `https://<host>:8444`. Login using the user `test-admin` and any password. |
|
| 192 | 199 |
|
| 193 | 200 |
* You will need to have the browser accept the certificate at |
| 194 | 201 |
`https://<host>:8443` before the console can consult the OpenShift |
| ... | ... |
@@ -199,7 +206,7 @@ This section covers how to perform all the steps of building, deploying, and upd |
| 199 | 199 |
and run builds. |
| 200 | 200 |
|
| 201 | 201 |
|
| 202 |
-11. *Optional:* Fork the [ruby sample repository](https://github.com/openshift/ruby-hello-world) |
|
| 202 |
+12. *Optional:* Fork the [ruby sample repository](https://github.com/openshift/ruby-hello-world) |
|
| 203 | 203 |
to an OpenShift-visible git account that you control, preferably |
| 204 | 204 |
somewhere that can also reach your OpenShift server with a webhook. |
| 205 | 205 |
A github.com account is an obvious place for this, but an in-house |
| ... | ... |
@@ -212,7 +219,7 @@ This section covers how to perform all the steps of building, deploying, and upd |
| 212 | 212 |
Without your own fork, you can still run the initial build from |
| 213 | 213 |
OpenShift's public repository, just not a changed build. |
| 214 | 214 |
|
| 215 |
-12. *Optional:* Add the following webhook under the settings in your new GitHub repository: |
|
| 215 |
+13. *Optional:* Add the following webhook under the settings in your new GitHub repository: |
|
| 216 | 216 |
|
| 217 | 217 |
$ https://<host>:8443/osapi/v1beta1/buildConfigHooks/ruby-sample-build/secret101/github?namespace=test |
| 218 | 218 |
|
| ... | ... |
@@ -223,12 +230,12 @@ This section covers how to perform all the steps of building, deploying, and upd |
| 223 | 223 |
instance as the certificate chain generated is not publicly verified. |
| 224 | 224 |
|
| 225 | 225 |
|
| 226 |
-13. Edit application-template-stibuild.json which will define the sample application |
|
| 226 |
+14. Edit application-template-stibuild.json which will define the sample application |
|
| 227 | 227 |
|
| 228 | 228 |
* Update the BuildConfig's sourceURI (git://github.com/openshift/ruby-hello-world.git) to point to your forked repository. |
| 229 | 229 |
*Note:* You can skip this step if you did not create a forked repository. |
| 230 | 230 |
|
| 231 |
-14. Submit the application template for processing (generating shared parameters requested in the template) |
|
| 231 |
+15. Submit the application template for processing (generating shared parameters requested in the template) |
|
| 232 | 232 |
and then request creation of the processed template: |
| 233 | 233 |
|
| 234 | 234 |
$ osc process -n test -f application-template-stibuild.json | osc create -n test -f - |
| ... | ... |
@@ -247,13 +254,13 @@ This section covers how to perform all the steps of building, deploying, and upd |
| 247 | 247 |
Note that no build has actually occurred yet, so at this time there |
| 248 | 248 |
is no image to deploy and no application to visit. |
| 249 | 249 |
|
| 250 |
-15. Trigger an initial build of your application |
|
| 250 |
+16. Trigger an initial build of your application |
|
| 251 | 251 |
* If you setup the GitHub webhook, push a change to app.rb in your ruby sample repository. |
| 252 | 252 |
* Otherwise you can request a new build by running: |
| 253 | 253 |
|
| 254 | 254 |
$ osc start-build -n test ruby-sample-build |
| 255 | 255 |
|
| 256 |
-16. Monitor the builds and wait for the status to go to "complete" (this can take a few minutes): |
|
| 256 |
+17. Monitor the builds and wait for the status to go to "complete" (this can take a few minutes): |
|
| 257 | 257 |
|
| 258 | 258 |
$ osc get -n test builds |
| 259 | 259 |
|
| ... | ... |
@@ -283,7 +290,7 @@ This section covers how to perform all the steps of building, deploying, and upd |
| 283 | 283 |
automatically trigger a deployment of the application, creating a |
| 284 | 284 |
pod each for the frontend (your Ruby code) and backend. |
| 285 | 285 |
|
| 286 |
-17. Wait for the application's frontend pod and database pods to be started (this can take a few minutes): |
|
| 286 |
+18. Wait for the application's frontend pod and database pods to be started (this can take a few minutes): |
|
| 287 | 287 |
|
| 288 | 288 |
$ osc get -n test pods |
| 289 | 289 |
|
| ... | ... |
@@ -294,7 +301,7 @@ This section covers how to perform all the steps of building, deploying, and upd |
| 294 | 294 |
1b978f62-605f-11e4-b0db-3c970e3bf0b7 mysql localhost.localdomain/ deploymentConfig=,deploymentID=database,name=database,replicationController=1b960e56-605f-11e4-b0db-3c970e3bf0b7,template=ruby-helloworld-sample Running |
| 295 | 295 |
4a792f55-605f-11e4-b0db-3c970e3bf0b7 172.30.17.3:5001/openshift/origin-ruby-sample:9477bdb99a409b9c747e699361ae7934fd83bb4092627e2ee35f9f0b0869885b localhost.localdomain/ deploymentConfig=frontend,deploymentID=frontend-1,name=frontend,replicationController=4a749831-605f-11e4-b0db-3c970e3bf0b7,template=ruby-helloworld-sample Running |
| 296 | 296 |
|
| 297 |
-18. Determine the IP for the frontend service: |
|
| 297 |
+19. Determine the IP for the frontend service: |
|
| 298 | 298 |
|
| 299 | 299 |
$ osc get -n test services |
| 300 | 300 |
|
| ... | ... |
@@ -310,7 +317,7 @@ This section covers how to perform all the steps of building, deploying, and upd |
| 310 | 310 |
|
| 311 | 311 |
*Note:* you can also get this information from the web console. |
| 312 | 312 |
|
| 313 |
-19. Confirm the application is now accessible via the frontend service on port 5432. Go to http://172.30.17.4:5432 (or whatever IP address was reported above) in your browser if you're running this locally; otherwise you can use curl to see the HTML, or port forward the address to your local workstation to visit it. |
|
| 313 |
+20. Confirm the application is now accessible via the frontend service on port 5432. Go to http://172.30.17.4:5432 (or whatever IP address was reported above) in your browser if you're running this locally; otherwise you can use curl to see the HTML, or port forward the address to your local workstation to visit it. |
|
| 314 | 314 |
|
| 315 | 315 |
- - - |
| 316 | 316 |
**VAGRANT USERS:** |
| ... | ... |
@@ -323,14 +330,14 @@ This section covers how to perform all the steps of building, deploying, and upd |
| 323 | 323 |
|
| 324 | 324 |
You should see a welcome page and a form that allows you to query and update key/value pairs. The keys are stored in the database container running in the database pod. |
| 325 | 325 |
|
| 326 |
-20. Make a change to your ruby sample main.html file, commit, and push it via git. |
|
| 326 |
+21. Make a change to your ruby sample main.html file, commit, and push it via git. |
|
| 327 | 327 |
|
| 328 | 328 |
* If you do not have the webhook enabled, you'll have to manually trigger another build: |
| 329 | 329 |
|
| 330 | 330 |
$ osc start-build -n test ruby-sample-build |
| 331 | 331 |
|
| 332 | 332 |
|
| 333 |
-21. Repeat step 16 (waiting for the build to complete). Once the build is complete, refreshing your browser should show your changes. |
|
| 333 |
+22. Repeat step 17 (waiting for the build to complete). Once the build is complete, refreshing your browser should show your changes. |
|
| 334 | 334 |
|
| 335 | 335 |
Congratulations, you've successfully deployed and updated an application on OpenShift. |
| 336 | 336 |
|
| ... | ... |
@@ -329,12 +329,14 @@ openshift ex new-project recreated-project --admin="anypassword:createuser2" |
| 329 | 329 |
osc describe policybinding master -n recreated-project | grep anypassword:createuser2 |
| 330 | 330 |
echo "ex new-project: ok" |
| 331 | 331 |
|
| 332 |
+# Test running a router |
|
| 332 | 333 |
[ ! "$(openshift ex router | grep 'does not exist')"] |
| 333 | 334 |
[ "$(openshift ex router -o yaml --credentials="${OPENSHIFTCONFIG}" | grep 'openshift/origin-haproxy-')" ]
|
| 334 | 335 |
openshift ex router --create --credentials="${OPENSHIFTCONFIG}"
|
| 335 | 336 |
[ "$(openshift ex router | grep 'service exists')" ] |
| 336 | 337 |
echo "ex router: ok" |
| 337 | 338 |
|
| 339 |
+# Test running a registry |
|
| 338 | 340 |
[ ! "$(openshift ex registry | grep 'does not exist')"] |
| 339 | 341 |
[ "$(openshift ex registry -o yaml --credentials="${OPENSHIFTCONFIG}" | grep 'openshift/origin-docker-registry')" ]
|
| 340 | 342 |
openshift ex registry --create --credentials="${OPENSHIFTCONFIG}"
|
| ... | ... |
@@ -232,11 +232,11 @@ echo "[INFO] Installing the registry" |
| 232 | 232 |
# TODO: add --images="${USE_IMAGES}" when the Docker registry is built alongside OpenShift
|
| 233 | 233 |
openshift ex registry --create --credentials="${CERT_DIR}/openshift-registry/.kubeconfig" --mount-host="/tmp/openshift.local.registry" --images='openshift/origin-${component}:latest'
|
| 234 | 234 |
|
| 235 |
-echo "[INFO] Pre-pulling and pushing centos7" |
|
| 236 |
-docker pull centos:centos7 |
|
| 235 |
+echo "[INFO] Pre-pulling and pushing ruby-20-centos7" |
|
| 236 |
+docker pull openshift/ruby-20-centos7:latest |
|
| 237 | 237 |
# TODO: remove after this becomes part of the build |
| 238 | 238 |
docker pull openshift/origin-docker-registry |
| 239 |
-echo "[INFO] Pulled centos7" |
|
| 239 |
+echo "[INFO] Pulled ruby-20-centos7" |
|
| 240 | 240 |
|
| 241 | 241 |
echo "[INFO] Waiting for Docker registry pod to start" |
| 242 | 242 |
# TODO: simplify when #4702 is fixed upstream |
| ... | ... |
@@ -250,9 +250,9 @@ wait_for_url_timed "http://${DOCKER_REGISTRY}" "[INFO] Docker registry says: " $
|
| 250 | 250 |
|
| 251 | 251 |
[ "$(dig @${API_HOST} "docker-registry.default.local." A)" ]
|
| 252 | 252 |
|
| 253 |
-docker tag -f centos:centos7 ${DOCKER_REGISTRY}/cached/centos:centos7
|
|
| 254 |
-docker push ${DOCKER_REGISTRY}/cached/centos:centos7
|
|
| 255 |
-echo "[INFO] Pushed centos7" |
|
| 253 |
+docker tag -f openshift/ruby-20-centos7:latest ${DOCKER_REGISTRY}/test/ruby-20-centos7:latest
|
|
| 254 |
+docker push ${DOCKER_REGISTRY}/test/ruby-20-centos7:latest
|
|
| 255 |
+echo "[INFO] Pushed ruby-20-centos7" |
|
| 256 | 256 |
|
| 257 | 257 |
# Process template and create |
| 258 | 258 |
echo "[INFO] Submitting application template json for processing..." |
| ... | ... |
@@ -48,7 +48,7 @@ type BuildParameters struct {
|
| 48 | 48 |
Revision *SourceRevision `json:"revision,omitempty"` |
| 49 | 49 |
|
| 50 | 50 |
// Strategy defines how to perform a build. |
| 51 |
- Strategy BuildStrategy `json:"strategy,omitempty"` |
|
| 51 |
+ Strategy BuildStrategy `json:"strategy"` |
|
| 52 | 52 |
|
| 53 | 53 |
// Output describes the Docker image the Strategy should produce. |
| 54 | 54 |
Output BuildOutput `json:"output,omitempty"` |
| ... | ... |
@@ -142,7 +142,7 @@ type SourceControlUser struct {
|
| 142 | 142 |
// BuildStrategy contains the details of how to perform a build. |
| 143 | 143 |
type BuildStrategy struct {
|
| 144 | 144 |
// Type is the kind of build strategy. |
| 145 |
- Type BuildStrategyType `json:"type,omitempty"` |
|
| 145 |
+ Type BuildStrategyType `json:"type"` |
|
| 146 | 146 |
|
| 147 | 147 |
// DockerStrategy holds the parameters to the Docker build strategy. |
| 148 | 148 |
DockerStrategy *DockerBuildStrategy `json:"dockerStrategy,omitempty"` |
| ... | ... |
@@ -209,8 +209,16 @@ type DockerBuildStrategy struct {
|
| 209 | 209 |
// STIBuildStrategy defines input parameters specific to an STI build. |
| 210 | 210 |
type STIBuildStrategy struct {
|
| 211 | 211 |
// Image is the image used to execute the build. |
| 212 |
+ // Only valid if From is not present. |
|
| 212 | 213 |
Image string `json:"image,omitempty"` |
| 213 | 214 |
|
| 215 |
+ // From is reference to an image repository from where the docker image should be pulled |
|
| 216 |
+ From *kapi.ObjectReference `json:"from,omitempty"` |
|
| 217 |
+ |
|
| 218 |
+ // Tag is the name of image repository tag to be used as the build image, it only |
|
| 219 |
+ // applies when From is specified. |
|
| 220 |
+ Tag string `json:"tag,omitempty` |
|
| 221 |
+ |
|
| 214 | 222 |
// Additional environment variables you want to pass into a builder container |
| 215 | 223 |
Env []kapi.EnvVar `json:"env,omitempty"` |
| 216 | 224 |
|
| ... | ... |
@@ -53,11 +53,27 @@ func init() {
|
| 53 | 53 |
func(in *newer.STIBuildStrategy, out *STIBuildStrategy, s conversion.Scope) error {
|
| 54 | 54 |
out.BuilderImage = in.Image |
| 55 | 55 |
out.Image = in.Image |
| 56 |
+ if in.From != nil {
|
|
| 57 |
+ out.From = &kapi.ObjectReference{
|
|
| 58 |
+ Name: in.From.Name, |
|
| 59 |
+ Namespace: in.From.Namespace, |
|
| 60 |
+ Kind: "ImageRepository", |
|
| 61 |
+ } |
|
| 62 |
+ } |
|
| 63 |
+ out.Tag = in.Tag |
|
| 56 | 64 |
out.Scripts = in.Scripts |
| 57 | 65 |
out.Clean = !in.Incremental |
| 58 | 66 |
return s.Convert(&in.Env, &out.Env, 0) |
| 59 | 67 |
}, |
| 60 | 68 |
func(in *STIBuildStrategy, out *newer.STIBuildStrategy, s conversion.Scope) error {
|
| 69 |
+ if in.From != nil {
|
|
| 70 |
+ out.From = &api.ObjectReference{
|
|
| 71 |
+ Name: in.From.Name, |
|
| 72 |
+ Namespace: in.From.Namespace, |
|
| 73 |
+ Kind: "ImageRepository", |
|
| 74 |
+ } |
|
| 75 |
+ } |
|
| 76 |
+ out.Tag = in.Tag |
|
| 61 | 77 |
out.Scripts = in.Scripts |
| 62 | 78 |
out.Incremental = !in.Clean |
| 63 | 79 |
if len(in.Image) != 0 {
|
| ... | ... |
@@ -26,6 +26,12 @@ func TestSTIBuildStrategyConversion(t *testing.T) {
|
| 26 | 26 |
if actual.Image != oldVersion.BuilderImage {
|
| 27 | 27 |
t.Errorf("expected %v, actual %v", oldVersion.BuilderImage, actual.Image)
|
| 28 | 28 |
} |
| 29 |
+ if actual.From != nil {
|
|
| 30 |
+ t.Errorf("expected %v, actual %v", nil, actual.From)
|
|
| 31 |
+ } |
|
| 32 |
+ if actual.Tag != oldVersion.Tag {
|
|
| 33 |
+ t.Errorf("expected %v, actual %v", oldVersion.Tag, actual.Tag)
|
|
| 34 |
+ } |
|
| 29 | 35 |
if actual.Incremental == oldVersion.Clean {
|
| 30 | 36 |
t.Errorf("expected %v, actual %v", oldVersion.Clean, actual.Incremental)
|
| 31 | 37 |
} |
| ... | ... |
@@ -48,7 +48,7 @@ type BuildParameters struct {
|
| 48 | 48 |
Revision *SourceRevision `json:"revision,omitempty"` |
| 49 | 49 |
|
| 50 | 50 |
// Strategy defines how to perform a build. |
| 51 |
- Strategy BuildStrategy `json:"strategy,omitempty"` |
|
| 51 |
+ Strategy BuildStrategy `json:"strategy"` |
|
| 52 | 52 |
|
| 53 | 53 |
// Output describes the Docker image the Strategy should produce. |
| 54 | 54 |
Output BuildOutput `json:"output,omitempty"` |
| ... | ... |
@@ -142,7 +142,7 @@ type SourceControlUser struct {
|
| 142 | 142 |
// BuildStrategy contains the details of how to perform a build. |
| 143 | 143 |
type BuildStrategy struct {
|
| 144 | 144 |
// Type is the kind of build strategy. |
| 145 |
- Type BuildStrategyType `json:"type,omitempty"` |
|
| 145 |
+ Type BuildStrategyType `json:"type"` |
|
| 146 | 146 |
|
| 147 | 147 |
// DockerStrategy holds the parameters to the Docker build strategy. |
| 148 | 148 |
DockerStrategy *DockerBuildStrategy `json:"dockerStrategy,omitempty"` |
| ... | ... |
@@ -214,8 +214,17 @@ type STIBuildStrategy struct {
|
| 214 | 214 |
BuilderImage string `json:"builderImage,omitempty"` |
| 215 | 215 |
|
| 216 | 216 |
// Image is the image used to execute the build. |
| 217 |
+ // For BuildConfigs, From takes precedence. |
|
| 217 | 218 |
Image string `json:"image,omitempty"` |
| 218 | 219 |
|
| 220 |
+ // Tag is the name of image repository tag to be used as the build image, it only |
|
| 221 |
+ // applies when From is specified. |
|
| 222 |
+ Tag string `json:"tag,omitempty"` |
|
| 223 |
+ |
|
| 224 |
+ // From is reference to an image repository from where the docker image should be pulled |
|
| 225 |
+ // Only allowed in BuildConfigs, Builds use the Image field exclusively. |
|
| 226 |
+ From *kapi.ObjectReference `json:"from,omitempty"` |
|
| 227 |
+ |
|
| 219 | 228 |
// Additional environment variables you want to pass into a builder container |
| 220 | 229 |
Env []kapi.EnvVar `json:"env,omitempty"` |
| 221 | 230 |
|
| ... | ... |
@@ -144,23 +144,22 @@ func validateBuildConfigOutput(output *buildapi.BuildOutput) errs.ValidationErro |
| 144 | 144 |
func validateStrategy(strategy *buildapi.BuildStrategy) errs.ValidationErrorList {
|
| 145 | 145 |
allErrs := errs.ValidationErrorList{}
|
| 146 | 146 |
|
| 147 |
- if len(strategy.Type) == 0 {
|
|
| 147 |
+ switch {
|
|
| 148 |
+ case len(strategy.Type) == 0: |
|
| 148 | 149 |
allErrs = append(allErrs, errs.NewFieldRequired("type"))
|
| 149 |
- } |
|
| 150 | 150 |
|
| 151 |
- switch strategy.Type {
|
|
| 152 |
- case buildapi.STIBuildStrategyType: |
|
| 151 |
+ case strategy.Type == buildapi.STIBuildStrategyType: |
|
| 153 | 152 |
if strategy.STIStrategy == nil {
|
| 154 | 153 |
allErrs = append(allErrs, errs.NewFieldRequired("stiStrategy"))
|
| 155 | 154 |
} else {
|
| 156 | 155 |
allErrs = append(allErrs, validateSTIStrategy(strategy.STIStrategy).Prefix("stiStrategy")...)
|
| 157 | 156 |
} |
| 158 |
- case buildapi.DockerBuildStrategyType: |
|
| 157 |
+ case strategy.Type == buildapi.DockerBuildStrategyType: |
|
| 159 | 158 |
// DockerStrategy is currently optional, initialize it to a default state if it's not set. |
| 160 | 159 |
if strategy.DockerStrategy == nil {
|
| 161 | 160 |
strategy.DockerStrategy = &buildapi.DockerBuildStrategy{}
|
| 162 | 161 |
} |
| 163 |
- case buildapi.CustomBuildStrategyType: |
|
| 162 |
+ case strategy.Type == buildapi.CustomBuildStrategyType: |
|
| 164 | 163 |
if strategy.CustomStrategy == nil {
|
| 165 | 164 |
allErrs = append(allErrs, errs.NewFieldRequired("customStrategy"))
|
| 166 | 165 |
} else {
|
| ... | ... |
@@ -178,8 +177,11 @@ func validateStrategy(strategy *buildapi.BuildStrategy) errs.ValidationErrorList |
| 178 | 178 |
|
| 179 | 179 |
func validateSTIStrategy(strategy *buildapi.STIBuildStrategy) errs.ValidationErrorList {
|
| 180 | 180 |
allErrs := errs.ValidationErrorList{}
|
| 181 |
- if len(strategy.Image) == 0 {
|
|
| 182 |
- allErrs = append(allErrs, errs.NewFieldRequired("image"))
|
|
| 181 |
+ if (strategy.From == nil || len(strategy.From.Name) == 0) && len(strategy.Image) == 0 {
|
|
| 182 |
+ allErrs = append(allErrs, errs.NewFieldRequired("from"))
|
|
| 183 |
+ } |
|
| 184 |
+ if (strategy.From != nil && len(strategy.From.Name) != 0) && len(strategy.Image) != 0 {
|
|
| 185 |
+ allErrs = append(allErrs, errs.NewFieldInvalid("image", strategy.Image, "only one of 'image' and 'from' may be set"))
|
|
| 183 | 186 |
} |
| 184 | 187 |
return allErrs |
| 185 | 188 |
} |
| ... | ... |
@@ -76,7 +76,9 @@ func TestBuildConfigValidationSuccess(t *testing.T) {
|
| 76 | 76 |
Type: buildapi.DockerBuildStrategyType, |
| 77 | 77 |
DockerStrategy: &buildapi.DockerBuildStrategy{},
|
| 78 | 78 |
}, |
| 79 |
- Output: buildapi.BuildOutput{},
|
|
| 79 |
+ Output: buildapi.BuildOutput{
|
|
| 80 |
+ DockerImageReference: "repository/data", |
|
| 81 |
+ }, |
|
| 80 | 82 |
}, |
| 81 | 83 |
} |
| 82 | 84 |
if result := ValidateBuildConfig(buildConfig); len(result) > 0 {
|
| ... | ... |
@@ -275,7 +277,7 @@ func TestValidateBuildParameters(t *testing.T) {
|
| 275 | 275 |
}, |
| 276 | 276 |
}, |
| 277 | 277 |
{
|
| 278 |
- string(errs.ValidationErrorTypeRequired) + "strategy.stiStrategy.image", |
|
| 278 |
+ string(errs.ValidationErrorTypeInvalid) + "strategy.type", |
|
| 279 | 279 |
&buildapi.BuildParameters{
|
| 280 | 280 |
Source: buildapi.BuildSource{
|
| 281 | 281 |
Type: buildapi.BuildSourceGit, |
| ... | ... |
@@ -283,15 +285,70 @@ func TestValidateBuildParameters(t *testing.T) {
|
| 283 | 283 |
URI: "http://github.com/my/repository", |
| 284 | 284 |
}, |
| 285 | 285 |
}, |
| 286 |
+ Strategy: buildapi.BuildStrategy{Type: "classic-joke"},
|
|
| 286 | 287 |
Output: buildapi.BuildOutput{
|
| 287 | 288 |
DockerImageReference: "repository/data", |
| 288 | 289 |
}, |
| 290 |
+ }, |
|
| 291 |
+ }, |
|
| 292 |
+ {
|
|
| 293 |
+ string(errs.ValidationErrorTypeRequired) + "strategy.type", |
|
| 294 |
+ &buildapi.BuildParameters{
|
|
| 295 |
+ Source: buildapi.BuildSource{
|
|
| 296 |
+ Type: buildapi.BuildSourceGit, |
|
| 297 |
+ Git: &buildapi.GitBuildSource{
|
|
| 298 |
+ URI: "http://github.com/my/repository", |
|
| 299 |
+ }, |
|
| 300 |
+ }, |
|
| 301 |
+ Strategy: buildapi.BuildStrategy{},
|
|
| 302 |
+ Output: buildapi.BuildOutput{
|
|
| 303 |
+ DockerImageReference: "repository/data", |
|
| 304 |
+ }, |
|
| 305 |
+ }, |
|
| 306 |
+ }, |
|
| 307 |
+ // invalid because both image and from are specified in the |
|
| 308 |
+ // sti strategy definition |
|
| 309 |
+ {
|
|
| 310 |
+ string(errs.ValidationErrorTypeInvalid) + "strategy.stiStrategy.image", |
|
| 311 |
+ &buildapi.BuildParameters{
|
|
| 312 |
+ Source: buildapi.BuildSource{
|
|
| 313 |
+ Type: buildapi.BuildSourceGit, |
|
| 314 |
+ Git: &buildapi.GitBuildSource{
|
|
| 315 |
+ URI: "http://github.com/my/repository", |
|
| 316 |
+ }, |
|
| 317 |
+ }, |
|
| 289 | 318 |
Strategy: buildapi.BuildStrategy{
|
| 290 | 319 |
Type: buildapi.STIBuildStrategyType, |
| 291 | 320 |
STIStrategy: &buildapi.STIBuildStrategy{
|
| 292 |
- Image: "", |
|
| 321 |
+ Image: "image", |
|
| 322 |
+ From: &kapi.ObjectReference{
|
|
| 323 |
+ Name: "reponame", |
|
| 324 |
+ }, |
|
| 325 |
+ }, |
|
| 326 |
+ }, |
|
| 327 |
+ Output: buildapi.BuildOutput{
|
|
| 328 |
+ DockerImageReference: "repository/data", |
|
| 329 |
+ }, |
|
| 330 |
+ }, |
|
| 331 |
+ }, |
|
| 332 |
+ // invalid because neither image nor from are specified in the |
|
| 333 |
+ // sti strategy definition |
|
| 334 |
+ {
|
|
| 335 |
+ string(errs.ValidationErrorTypeRequired) + "strategy.stiStrategy.from", |
|
| 336 |
+ &buildapi.BuildParameters{
|
|
| 337 |
+ Source: buildapi.BuildSource{
|
|
| 338 |
+ Type: buildapi.BuildSourceGit, |
|
| 339 |
+ Git: &buildapi.GitBuildSource{
|
|
| 340 |
+ URI: "http://github.com/my/repository", |
|
| 293 | 341 |
}, |
| 294 | 342 |
}, |
| 343 |
+ Strategy: buildapi.BuildStrategy{
|
|
| 344 |
+ Type: buildapi.STIBuildStrategyType, |
|
| 345 |
+ STIStrategy: &buildapi.STIBuildStrategy{},
|
|
| 346 |
+ }, |
|
| 347 |
+ Output: buildapi.BuildOutput{
|
|
| 348 |
+ DockerImageReference: "repository/data", |
|
| 349 |
+ }, |
|
| 295 | 350 |
}, |
| 296 | 351 |
}, |
| 297 | 352 |
} |
| ... | ... |
@@ -309,6 +366,61 @@ func TestValidateBuildParameters(t *testing.T) {
|
| 309 | 309 |
} |
| 310 | 310 |
} |
| 311 | 311 |
|
| 312 |
+func TestValidateBuildParametersSuccess(t *testing.T) {
|
|
| 313 |
+ testCases := []struct {
|
|
| 314 |
+ *buildapi.BuildParameters |
|
| 315 |
+ }{
|
|
| 316 |
+ {
|
|
| 317 |
+ &buildapi.BuildParameters{
|
|
| 318 |
+ Source: buildapi.BuildSource{
|
|
| 319 |
+ Type: buildapi.BuildSourceGit, |
|
| 320 |
+ Git: &buildapi.GitBuildSource{
|
|
| 321 |
+ URI: "http://github.com/my/repository", |
|
| 322 |
+ }, |
|
| 323 |
+ }, |
|
| 324 |
+ Strategy: buildapi.BuildStrategy{
|
|
| 325 |
+ Type: buildapi.STIBuildStrategyType, |
|
| 326 |
+ STIStrategy: &buildapi.STIBuildStrategy{
|
|
| 327 |
+ Image: "repository/builder-image", |
|
| 328 |
+ }, |
|
| 329 |
+ }, |
|
| 330 |
+ Output: buildapi.BuildOutput{
|
|
| 331 |
+ DockerImageReference: "repository/data", |
|
| 332 |
+ }, |
|
| 333 |
+ }, |
|
| 334 |
+ }, |
|
| 335 |
+ {
|
|
| 336 |
+ &buildapi.BuildParameters{
|
|
| 337 |
+ Source: buildapi.BuildSource{
|
|
| 338 |
+ Type: buildapi.BuildSourceGit, |
|
| 339 |
+ Git: &buildapi.GitBuildSource{
|
|
| 340 |
+ URI: "http://github.com/my/repository", |
|
| 341 |
+ }, |
|
| 342 |
+ }, |
|
| 343 |
+ Strategy: buildapi.BuildStrategy{
|
|
| 344 |
+ Type: buildapi.STIBuildStrategyType, |
|
| 345 |
+ STIStrategy: &buildapi.STIBuildStrategy{
|
|
| 346 |
+ From: &kapi.ObjectReference{
|
|
| 347 |
+ Name: "reponame", |
|
| 348 |
+ }, |
|
| 349 |
+ }, |
|
| 350 |
+ }, |
|
| 351 |
+ Output: buildapi.BuildOutput{
|
|
| 352 |
+ DockerImageReference: "repository/data", |
|
| 353 |
+ }, |
|
| 354 |
+ }, |
|
| 355 |
+ }, |
|
| 356 |
+ } |
|
| 357 |
+ |
|
| 358 |
+ for _, config := range testCases {
|
|
| 359 |
+ errors := validateBuildParameters(config.BuildParameters) |
|
| 360 |
+ if len(errors) != 0 {
|
|
| 361 |
+ t.Errorf("Unexpected validation error: %v", errors)
|
|
| 362 |
+ } |
|
| 363 |
+ } |
|
| 364 |
+ |
|
| 365 |
+} |
|
| 366 |
+ |
|
| 312 | 367 |
func TestValidateTrigger(t *testing.T) {
|
| 313 | 368 |
tests := map[string]struct {
|
| 314 | 369 |
trigger buildapi.BuildTriggerPolicy |
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache" |
| 9 | 9 |
"github.com/GoogleCloudPlatform/kubernetes/pkg/util" |
| 10 | 10 |
|
| 11 |
+ kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
|
| 11 | 12 |
buildapi "github.com/openshift/origin/pkg/build/api" |
| 12 | 13 |
buildclient "github.com/openshift/origin/pkg/build/client" |
| 13 | 14 |
buildutil "github.com/openshift/origin/pkg/build/util" |
| ... | ... |
@@ -37,7 +38,8 @@ type ImageChangeController struct {
|
| 37 | 37 |
// HandleImageRepo processes the next ImageRepository event. |
| 38 | 38 |
func (c *ImageChangeController) HandleImageRepo(repo *imageapi.ImageRepository) error {
|
| 39 | 39 |
glog.V(4).Infof("Build image change controller detected imagerepo change %s", repo.Status.DockerImageRepository)
|
| 40 |
- subs := make(map[string]string) |
|
| 40 |
+ imageSubs := make(map[string]string) |
|
| 41 |
+ repoSubs := make(map[kapi.ObjectReference]string) |
|
| 41 | 42 |
|
| 42 | 43 |
// TODO: this is inefficient |
| 43 | 44 |
for _, bc := range c.BuildConfigStore.List() {
|
| ... | ... |
@@ -73,7 +75,8 @@ func (c *ImageChangeController) HandleImageRepo(repo *imageapi.ImageRepository) |
| 73 | 73 |
next = latest.DockerImageReference |
| 74 | 74 |
} |
| 75 | 75 |
if len(last) == 0 || next != last {
|
| 76 |
- subs[change.Image] = latest.DockerImageReference |
|
| 76 |
+ imageSubs[change.Image] = latest.DockerImageReference |
|
| 77 |
+ repoSubs[change.From] = latest.DockerImageReference |
|
| 77 | 78 |
change.LastTriggeredImageID = next |
| 78 | 79 |
shouldBuild = true |
| 79 | 80 |
} |
| ... | ... |
@@ -81,7 +84,7 @@ func (c *ImageChangeController) HandleImageRepo(repo *imageapi.ImageRepository) |
| 81 | 81 |
|
| 82 | 82 |
if shouldBuild {
|
| 83 | 83 |
glog.V(4).Infof("Running build for buildConfig %s in namespace %s", config.Name, config.Namespace)
|
| 84 |
- b := buildutil.GenerateBuildFromConfig(config, nil, subs) |
|
| 84 |
+ b := buildutil.GenerateBuildFromConfig(config, nil, imageSubs, repoSubs) |
|
| 85 | 85 |
if err := c.BuildCreator.Create(config.Namespace, b); err != nil {
|
| 86 | 86 |
return fmt.Errorf("error starting build for buildConfig %s: %v", config.Name, err)
|
| 87 | 87 |
} |
| ... | ... |
@@ -255,6 +255,37 @@ func mockBuildConfig() *api.BuildConfig {
|
| 255 | 255 |
} |
| 256 | 256 |
} |
| 257 | 257 |
|
| 258 |
+func mockBuildConfigImageRef() *api.BuildConfig {
|
|
| 259 |
+ return &api.BuildConfig{
|
|
| 260 |
+ ObjectMeta: kapi.ObjectMeta{
|
|
| 261 |
+ Name: "data-build", |
|
| 262 |
+ Namespace: kapi.NamespaceDefault, |
|
| 263 |
+ Labels: map[string]string{
|
|
| 264 |
+ "name": "data-build", |
|
| 265 |
+ }, |
|
| 266 |
+ }, |
|
| 267 |
+ Parameters: api.BuildParameters{
|
|
| 268 |
+ Source: api.BuildSource{
|
|
| 269 |
+ Type: api.BuildSourceGit, |
|
| 270 |
+ Git: &api.GitBuildSource{
|
|
| 271 |
+ URI: "http://my.build.com/the/build/Dockerfile", |
|
| 272 |
+ }, |
|
| 273 |
+ }, |
|
| 274 |
+ Strategy: api.BuildStrategy{
|
|
| 275 |
+ Type: api.STIBuildStrategyType, |
|
| 276 |
+ STIStrategy: &api.STIBuildStrategy{
|
|
| 277 |
+ From: &kapi.ObjectReference{
|
|
| 278 |
+ Name: "builder/image", |
|
| 279 |
+ }, |
|
| 280 |
+ }, |
|
| 281 |
+ }, |
|
| 282 |
+ Output: api.BuildOutput{
|
|
| 283 |
+ DockerImageReference: "repository/data-build", |
|
| 284 |
+ }, |
|
| 285 |
+ }, |
|
| 286 |
+ } |
|
| 287 |
+} |
|
| 288 |
+ |
|
| 258 | 289 |
func TestUpdateBuildConfig(t *testing.T) {
|
| 259 | 290 |
mockRegistry := test.BuildConfigRegistry{}
|
| 260 | 291 |
storage := REST{&mockRegistry}
|
| ... | ... |
@@ -290,69 +321,143 @@ func TestUpdateBuildConfigError(t *testing.T) {
|
| 290 | 290 |
func TestBuildConfigRESTValidatesCreate(t *testing.T) {
|
| 291 | 291 |
mockRegistry := test.BuildConfigRegistry{}
|
| 292 | 292 |
storage := REST{&mockRegistry}
|
| 293 |
- failureCases := map[string]api.BuildConfig{
|
|
| 293 |
+ failureCases := map[string]struct {
|
|
| 294 |
+ expectSuccess bool |
|
| 295 |
+ data api.BuildConfig |
|
| 296 |
+ }{
|
|
| 294 | 297 |
"blank sourceURI": {
|
| 295 |
- ObjectMeta: kapi.ObjectMeta{Name: "abc"},
|
|
| 296 |
- Parameters: api.BuildParameters{
|
|
| 297 |
- Source: api.BuildSource{
|
|
| 298 |
- Type: api.BuildSourceGit, |
|
| 299 |
- Git: &api.GitBuildSource{
|
|
| 300 |
- URI: "", |
|
| 298 |
+ false, |
|
| 299 |
+ api.BuildConfig{
|
|
| 300 |
+ ObjectMeta: kapi.ObjectMeta{Name: "abc"},
|
|
| 301 |
+ Parameters: api.BuildParameters{
|
|
| 302 |
+ Source: api.BuildSource{
|
|
| 303 |
+ Type: api.BuildSourceGit, |
|
| 304 |
+ Git: &api.GitBuildSource{
|
|
| 305 |
+ URI: "", |
|
| 306 |
+ }, |
|
| 301 | 307 |
}, |
| 302 |
- }, |
|
| 303 |
- Strategy: api.BuildStrategy{
|
|
| 304 |
- Type: api.STIBuildStrategyType, |
|
| 305 |
- STIStrategy: &api.STIBuildStrategy{
|
|
| 306 |
- Image: "builder/image", |
|
| 308 |
+ Strategy: api.BuildStrategy{
|
|
| 309 |
+ Type: api.STIBuildStrategyType, |
|
| 310 |
+ STIStrategy: &api.STIBuildStrategy{
|
|
| 311 |
+ From: &kapi.ObjectReference{
|
|
| 312 |
+ Name: "builder/image", |
|
| 313 |
+ }, |
|
| 314 |
+ }, |
|
| 315 |
+ }, |
|
| 316 |
+ Output: api.BuildOutput{
|
|
| 317 |
+ DockerImageReference: "data/image", |
|
| 307 | 318 |
}, |
| 308 |
- }, |
|
| 309 |
- Output: api.BuildOutput{
|
|
| 310 |
- DockerImageReference: "data/image", |
|
| 311 | 319 |
}, |
| 312 | 320 |
}, |
| 313 | 321 |
}, |
| 314 | 322 |
"blank DockerImageReference": {
|
| 315 |
- ObjectMeta: kapi.ObjectMeta{Name: "abc"},
|
|
| 316 |
- Parameters: api.BuildParameters{
|
|
| 317 |
- Source: api.BuildSource{
|
|
| 318 |
- Type: api.BuildSourceGit, |
|
| 319 |
- Git: &api.GitBuildSource{
|
|
| 320 |
- URI: "http://github.com/test/source", |
|
| 323 |
+ true, |
|
| 324 |
+ api.BuildConfig{
|
|
| 325 |
+ ObjectMeta: kapi.ObjectMeta{Name: "abc"},
|
|
| 326 |
+ Parameters: api.BuildParameters{
|
|
| 327 |
+ Source: api.BuildSource{
|
|
| 328 |
+ Type: api.BuildSourceGit, |
|
| 329 |
+ Git: &api.GitBuildSource{
|
|
| 330 |
+ URI: "http://github.com/test/source", |
|
| 331 |
+ }, |
|
| 332 |
+ }, |
|
| 333 |
+ Strategy: api.BuildStrategy{
|
|
| 334 |
+ Type: api.STIBuildStrategyType, |
|
| 335 |
+ STIStrategy: &api.STIBuildStrategy{
|
|
| 336 |
+ From: &kapi.ObjectReference{
|
|
| 337 |
+ Name: "builder/image", |
|
| 338 |
+ }, |
|
| 339 |
+ }, |
|
| 340 |
+ }, |
|
| 341 |
+ Output: api.BuildOutput{
|
|
| 342 |
+ DockerImageReference: "", |
|
| 321 | 343 |
}, |
| 322 |
- }, |
|
| 323 |
- Output: api.BuildOutput{
|
|
| 324 |
- DockerImageReference: "", |
|
| 325 | 344 |
}, |
| 326 | 345 |
}, |
| 327 | 346 |
}, |
| 328 |
- "blank Image": {
|
|
| 329 |
- ObjectMeta: kapi.ObjectMeta{Name: "abc"},
|
|
| 330 |
- Parameters: api.BuildParameters{
|
|
| 331 |
- Source: api.BuildSource{
|
|
| 332 |
- Type: api.BuildSourceGit, |
|
| 333 |
- Git: &api.GitBuildSource{
|
|
| 334 |
- URI: "http://github.com/test/source", |
|
| 347 |
+ "blank From.Name and blank Image": {
|
|
| 348 |
+ false, |
|
| 349 |
+ api.BuildConfig{
|
|
| 350 |
+ ObjectMeta: kapi.ObjectMeta{Name: "abc"},
|
|
| 351 |
+ Parameters: api.BuildParameters{
|
|
| 352 |
+ Source: api.BuildSource{
|
|
| 353 |
+ Type: api.BuildSourceGit, |
|
| 354 |
+ Git: &api.GitBuildSource{
|
|
| 355 |
+ URI: "http://github.com/test/source", |
|
| 356 |
+ }, |
|
| 357 |
+ }, |
|
| 358 |
+ Strategy: api.BuildStrategy{
|
|
| 359 |
+ Type: api.STIBuildStrategyType, |
|
| 360 |
+ STIStrategy: &api.STIBuildStrategy{},
|
|
| 361 |
+ }, |
|
| 362 |
+ Output: api.BuildOutput{
|
|
| 363 |
+ DockerImageReference: "data/image", |
|
| 335 | 364 |
}, |
| 336 | 365 |
}, |
| 337 |
- Strategy: api.BuildStrategy{
|
|
| 338 |
- Type: api.STIBuildStrategyType, |
|
| 339 |
- STIStrategy: &api.STIBuildStrategy{
|
|
| 340 |
- Image: "", |
|
| 366 |
+ }, |
|
| 367 |
+ }, |
|
| 368 |
+ "blank From.Name and Image present": {
|
|
| 369 |
+ true, |
|
| 370 |
+ api.BuildConfig{
|
|
| 371 |
+ ObjectMeta: kapi.ObjectMeta{Name: "abc"},
|
|
| 372 |
+ Parameters: api.BuildParameters{
|
|
| 373 |
+ Source: api.BuildSource{
|
|
| 374 |
+ Type: api.BuildSourceGit, |
|
| 375 |
+ Git: &api.GitBuildSource{
|
|
| 376 |
+ URI: "http://github.com/test/source", |
|
| 377 |
+ }, |
|
| 378 |
+ }, |
|
| 379 |
+ Strategy: api.BuildStrategy{
|
|
| 380 |
+ Type: api.STIBuildStrategyType, |
|
| 381 |
+ STIStrategy: &api.STIBuildStrategy{
|
|
| 382 |
+ Image: "builder/image", |
|
| 383 |
+ }, |
|
| 384 |
+ }, |
|
| 385 |
+ Output: api.BuildOutput{
|
|
| 386 |
+ DockerImageReference: "data/image", |
|
| 341 | 387 |
}, |
| 342 | 388 |
}, |
| 343 |
- Output: api.BuildOutput{
|
|
| 344 |
- DockerImageReference: "data/image", |
|
| 389 |
+ }, |
|
| 390 |
+ }, |
|
| 391 |
+ "blank Image and From.Name present": {
|
|
| 392 |
+ true, |
|
| 393 |
+ api.BuildConfig{
|
|
| 394 |
+ ObjectMeta: kapi.ObjectMeta{Name: "abc"},
|
|
| 395 |
+ Parameters: api.BuildParameters{
|
|
| 396 |
+ Source: api.BuildSource{
|
|
| 397 |
+ Type: api.BuildSourceGit, |
|
| 398 |
+ Git: &api.GitBuildSource{
|
|
| 399 |
+ URI: "http://github.com/test/source", |
|
| 400 |
+ }, |
|
| 401 |
+ }, |
|
| 402 |
+ Strategy: api.BuildStrategy{
|
|
| 403 |
+ Type: api.STIBuildStrategyType, |
|
| 404 |
+ STIStrategy: &api.STIBuildStrategy{
|
|
| 405 |
+ From: &kapi.ObjectReference{
|
|
| 406 |
+ Name: "builder/image", |
|
| 407 |
+ }, |
|
| 408 |
+ }, |
|
| 409 |
+ }, |
|
| 410 |
+ Output: api.BuildOutput{
|
|
| 411 |
+ DockerImageReference: "data/image", |
|
| 412 |
+ }, |
|
| 345 | 413 |
}, |
| 346 | 414 |
}, |
| 347 | 415 |
}, |
| 348 | 416 |
} |
| 349 |
- for desc, failureCase := range failureCases {
|
|
| 350 |
- c, err := storage.Create(kapi.NewDefaultContext(), &failureCase) |
|
| 351 |
- if c != nil {
|
|
| 352 |
- t.Errorf("%s: Expected nil object", desc)
|
|
| 353 |
- } |
|
| 354 |
- if !errors.IsInvalid(err) {
|
|
| 355 |
- t.Errorf("%s: Expected to get an invalid resource error, got %v", desc, err)
|
|
| 417 |
+ for desc, testCase := range failureCases {
|
|
| 418 |
+ c, err := storage.Create(kapi.NewDefaultContext(), &testCase.data) |
|
| 419 |
+ if testCase.expectSuccess {
|
|
| 420 |
+ if c == nil {
|
|
| 421 |
+ t.Errorf("%s: Expected success, got error: %s", desc, err)
|
|
| 422 |
+ } |
|
| 423 |
+ } else {
|
|
| 424 |
+ if c != nil {
|
|
| 425 |
+ t.Errorf("%s: Expected nil object", desc)
|
|
| 426 |
+ } |
|
| 427 |
+ if !errors.IsInvalid(err) {
|
|
| 428 |
+ t.Errorf("%s: Expected to get an invalid resource error, got %v", desc, err)
|
|
| 429 |
+ } |
|
| 356 | 430 |
} |
| 357 | 431 |
} |
| 358 | 432 |
} |
| ... | ... |
@@ -360,83 +465,175 @@ func TestBuildConfigRESTValidatesCreate(t *testing.T) {
|
| 360 | 360 |
func TestBuildRESTValidatesUpdate(t *testing.T) {
|
| 361 | 361 |
mockRegistry := test.BuildConfigRegistry{}
|
| 362 | 362 |
storage := REST{&mockRegistry}
|
| 363 |
- failureCases := map[string]api.BuildConfig{
|
|
| 363 |
+ failureCases := map[string]struct {
|
|
| 364 |
+ expectSuccess bool |
|
| 365 |
+ data api.BuildConfig |
|
| 366 |
+ }{
|
|
| 364 | 367 |
"empty ID": {
|
| 365 |
- ObjectMeta: kapi.ObjectMeta{Name: ""},
|
|
| 366 |
- Parameters: api.BuildParameters{
|
|
| 367 |
- Source: api.BuildSource{
|
|
| 368 |
- Type: api.BuildSourceGit, |
|
| 369 |
- Git: &api.GitBuildSource{
|
|
| 370 |
- URI: "http://github.com/test/source", |
|
| 371 |
- }, |
|
| 368 |
+ false, |
|
| 369 |
+ api.BuildConfig{
|
|
| 370 |
+ ObjectMeta: kapi.ObjectMeta{
|
|
| 371 |
+ Name: "", |
|
| 372 |
+ Namespace: kapi.NamespaceDefault, |
|
| 372 | 373 |
}, |
| 373 |
- Output: api.BuildOutput{
|
|
| 374 |
- DockerImageReference: "data/image", |
|
| 374 |
+ Parameters: api.BuildParameters{
|
|
| 375 |
+ Source: api.BuildSource{
|
|
| 376 |
+ Type: api.BuildSourceGit, |
|
| 377 |
+ Git: &api.GitBuildSource{
|
|
| 378 |
+ URI: "http://github.com/test/source", |
|
| 379 |
+ }, |
|
| 380 |
+ }, |
|
| 381 |
+ Output: api.BuildOutput{
|
|
| 382 |
+ DockerImageReference: "data/image", |
|
| 383 |
+ }, |
|
| 375 | 384 |
}, |
| 376 | 385 |
}, |
| 377 | 386 |
}, |
| 378 | 387 |
"blank sourceURI": {
|
| 379 |
- ObjectMeta: kapi.ObjectMeta{Name: "abc"},
|
|
| 380 |
- Parameters: api.BuildParameters{
|
|
| 381 |
- Source: api.BuildSource{
|
|
| 382 |
- Type: api.BuildSourceGit, |
|
| 383 |
- Git: &api.GitBuildSource{
|
|
| 384 |
- URI: "", |
|
| 385 |
- }, |
|
| 388 |
+ false, |
|
| 389 |
+ api.BuildConfig{
|
|
| 390 |
+ ObjectMeta: kapi.ObjectMeta{
|
|
| 391 |
+ Name: "abc", |
|
| 392 |
+ Namespace: kapi.NamespaceDefault, |
|
| 386 | 393 |
}, |
| 387 |
- Strategy: api.BuildStrategy{
|
|
| 388 |
- Type: api.STIBuildStrategyType, |
|
| 389 |
- STIStrategy: &api.STIBuildStrategy{
|
|
| 390 |
- Image: "builder/image", |
|
| 394 |
+ Parameters: api.BuildParameters{
|
|
| 395 |
+ Source: api.BuildSource{
|
|
| 396 |
+ Type: api.BuildSourceGit, |
|
| 397 |
+ Git: &api.GitBuildSource{
|
|
| 398 |
+ URI: "", |
|
| 399 |
+ }, |
|
| 400 |
+ }, |
|
| 401 |
+ Strategy: api.BuildStrategy{
|
|
| 402 |
+ Type: api.STIBuildStrategyType, |
|
| 403 |
+ STIStrategy: &api.STIBuildStrategy{
|
|
| 404 |
+ From: &kapi.ObjectReference{
|
|
| 405 |
+ Name: "builder/image", |
|
| 406 |
+ }, |
|
| 407 |
+ }, |
|
| 408 |
+ }, |
|
| 409 |
+ Output: api.BuildOutput{
|
|
| 410 |
+ DockerImageReference: "data/image", |
|
| 391 | 411 |
}, |
| 392 |
- }, |
|
| 393 |
- Output: api.BuildOutput{
|
|
| 394 |
- DockerImageReference: "data/image", |
|
| 395 | 412 |
}, |
| 396 | 413 |
}, |
| 397 | 414 |
}, |
| 398 | 415 |
"blank DockerImageReference": {
|
| 399 |
- ObjectMeta: kapi.ObjectMeta{Name: "abc"},
|
|
| 400 |
- Parameters: api.BuildParameters{
|
|
| 401 |
- Source: api.BuildSource{
|
|
| 402 |
- Type: api.BuildSourceGit, |
|
| 403 |
- Git: &api.GitBuildSource{
|
|
| 404 |
- URI: "http://github.com/test/source", |
|
| 405 |
- }, |
|
| 416 |
+ false, |
|
| 417 |
+ api.BuildConfig{
|
|
| 418 |
+ ObjectMeta: kapi.ObjectMeta{
|
|
| 419 |
+ Name: "abc", |
|
| 420 |
+ Namespace: kapi.NamespaceDefault, |
|
| 406 | 421 |
}, |
| 407 |
- Output: api.BuildOutput{
|
|
| 408 |
- DockerImageReference: "", |
|
| 422 |
+ Parameters: api.BuildParameters{
|
|
| 423 |
+ Source: api.BuildSource{
|
|
| 424 |
+ Type: api.BuildSourceGit, |
|
| 425 |
+ Git: &api.GitBuildSource{
|
|
| 426 |
+ URI: "http://github.com/test/source", |
|
| 427 |
+ }, |
|
| 428 |
+ }, |
|
| 429 |
+ Output: api.BuildOutput{
|
|
| 430 |
+ DockerImageReference: "", |
|
| 431 |
+ }, |
|
| 409 | 432 |
}, |
| 410 | 433 |
}, |
| 411 | 434 |
}, |
| 412 |
- "blank Image on STIBuildType": {
|
|
| 413 |
- ObjectMeta: kapi.ObjectMeta{Name: "abc"},
|
|
| 414 |
- Parameters: api.BuildParameters{
|
|
| 415 |
- Source: api.BuildSource{
|
|
| 416 |
- Type: api.BuildSourceGit, |
|
| 417 |
- Git: &api.GitBuildSource{
|
|
| 418 |
- URI: "http://github.com/test/source", |
|
| 435 |
+ "blank From.Name and blank Image": {
|
|
| 436 |
+ false, |
|
| 437 |
+ api.BuildConfig{
|
|
| 438 |
+ ObjectMeta: kapi.ObjectMeta{
|
|
| 439 |
+ Name: "abc", |
|
| 440 |
+ Namespace: kapi.NamespaceDefault, |
|
| 441 |
+ }, |
|
| 442 |
+ Parameters: api.BuildParameters{
|
|
| 443 |
+ Source: api.BuildSource{
|
|
| 444 |
+ Type: api.BuildSourceGit, |
|
| 445 |
+ Git: &api.GitBuildSource{
|
|
| 446 |
+ URI: "http://github.com/test/source", |
|
| 447 |
+ }, |
|
| 448 |
+ }, |
|
| 449 |
+ Strategy: api.BuildStrategy{
|
|
| 450 |
+ Type: api.STIBuildStrategyType, |
|
| 451 |
+ STIStrategy: &api.STIBuildStrategy{
|
|
| 452 |
+ From: &kapi.ObjectReference{
|
|
| 453 |
+ Name: "", |
|
| 454 |
+ }, |
|
| 455 |
+ }, |
|
| 456 |
+ }, |
|
| 457 |
+ Output: api.BuildOutput{
|
|
| 458 |
+ DockerImageReference: "data/image", |
|
| 419 | 459 |
}, |
| 420 | 460 |
}, |
| 421 |
- Strategy: api.BuildStrategy{
|
|
| 422 |
- Type: api.STIBuildStrategyType, |
|
| 423 |
- STIStrategy: &api.STIBuildStrategy{
|
|
| 424 |
- Image: "", |
|
| 461 |
+ }, |
|
| 462 |
+ }, |
|
| 463 |
+ "blank From.Name and Image present": {
|
|
| 464 |
+ true, |
|
| 465 |
+ api.BuildConfig{
|
|
| 466 |
+ ObjectMeta: kapi.ObjectMeta{
|
|
| 467 |
+ Name: "abc", |
|
| 468 |
+ Namespace: kapi.NamespaceDefault, |
|
| 469 |
+ }, |
|
| 470 |
+ Parameters: api.BuildParameters{
|
|
| 471 |
+ Source: api.BuildSource{
|
|
| 472 |
+ Type: api.BuildSourceGit, |
|
| 473 |
+ Git: &api.GitBuildSource{
|
|
| 474 |
+ URI: "http://github.com/test/source", |
|
| 475 |
+ }, |
|
| 476 |
+ }, |
|
| 477 |
+ Strategy: api.BuildStrategy{
|
|
| 478 |
+ Type: api.STIBuildStrategyType, |
|
| 479 |
+ STIStrategy: &api.STIBuildStrategy{
|
|
| 480 |
+ Image: "builder/image", |
|
| 481 |
+ }, |
|
| 482 |
+ }, |
|
| 483 |
+ Output: api.BuildOutput{
|
|
| 484 |
+ DockerImageReference: "data/image", |
|
| 425 | 485 |
}, |
| 426 | 486 |
}, |
| 427 |
- Output: api.BuildOutput{
|
|
| 428 |
- DockerImageReference: "data/image", |
|
| 487 |
+ }, |
|
| 488 |
+ }, |
|
| 489 |
+ "blank Image and From.Name present": {
|
|
| 490 |
+ true, |
|
| 491 |
+ api.BuildConfig{
|
|
| 492 |
+ ObjectMeta: kapi.ObjectMeta{
|
|
| 493 |
+ Name: "abc", |
|
| 494 |
+ Namespace: kapi.NamespaceDefault, |
|
| 495 |
+ }, |
|
| 496 |
+ Parameters: api.BuildParameters{
|
|
| 497 |
+ Source: api.BuildSource{
|
|
| 498 |
+ Type: api.BuildSourceGit, |
|
| 499 |
+ Git: &api.GitBuildSource{
|
|
| 500 |
+ URI: "http://github.com/test/source", |
|
| 501 |
+ }, |
|
| 502 |
+ }, |
|
| 503 |
+ Strategy: api.BuildStrategy{
|
|
| 504 |
+ Type: api.STIBuildStrategyType, |
|
| 505 |
+ STIStrategy: &api.STIBuildStrategy{
|
|
| 506 |
+ From: &kapi.ObjectReference{
|
|
| 507 |
+ Name: "imagerepo", |
|
| 508 |
+ }, |
|
| 509 |
+ }, |
|
| 510 |
+ }, |
|
| 511 |
+ Output: api.BuildOutput{
|
|
| 512 |
+ DockerImageReference: "data/image", |
|
| 513 |
+ }, |
|
| 429 | 514 |
}, |
| 430 | 515 |
}, |
| 431 | 516 |
}, |
| 432 | 517 |
} |
| 433 |
- for desc, failureCase := range failureCases {
|
|
| 434 |
- c, created, err := storage.Update(kapi.NewDefaultContext(), &failureCase) |
|
| 435 |
- if c != nil || created {
|
|
| 436 |
- t.Errorf("%s: Expected nil object", desc)
|
|
| 437 |
- } |
|
| 438 |
- if !errors.IsInvalid(err) {
|
|
| 439 |
- t.Errorf("%s: Expected to get an invalid resource error, got %v", desc, err)
|
|
| 518 |
+ |
|
| 519 |
+ for desc, testCase := range failureCases {
|
|
| 520 |
+ c, created, err := storage.Update(kapi.NewDefaultContext(), &testCase.data) |
|
| 521 |
+ if testCase.expectSuccess {
|
|
| 522 |
+ if c == nil {
|
|
| 523 |
+ t.Errorf("%s: Expected success, error: %s", desc, err)
|
|
| 524 |
+ } |
|
| 525 |
+ } else {
|
|
| 526 |
+ if c != nil || created {
|
|
| 527 |
+ t.Errorf("%s: Expected nil object", desc)
|
|
| 528 |
+ } |
|
| 529 |
+ if !errors.IsInvalid(err) {
|
|
| 530 |
+ t.Errorf("%s: Expected to get an invalid resource error, got %v", desc, err)
|
|
| 531 |
+ } |
|
| 440 | 532 |
} |
| 441 | 533 |
} |
| 442 | 534 |
} |
| ... | ... |
@@ -485,5 +682,4 @@ func checkExpectedNamespaceError(t *testing.T, err error) {
|
| 485 | 485 |
t.Errorf("Expected '"+expectedError+"' error, got '%v'", err.Error())
|
| 486 | 486 |
} |
| 487 | 487 |
} |
| 488 |
- |
|
| 489 | 488 |
} |
| ... | ... |
@@ -110,6 +110,63 @@ func TestEtcdCreateBuild(t *testing.T) {
|
| 110 | 110 |
Strategy: api.BuildStrategy{
|
| 111 | 111 |
Type: api.STIBuildStrategyType, |
| 112 | 112 |
STIStrategy: &api.STIBuildStrategy{
|
| 113 |
+ From: &kapi.ObjectReference{
|
|
| 114 |
+ Name: "builder/image", |
|
| 115 |
+ }, |
|
| 116 |
+ }, |
|
| 117 |
+ }, |
|
| 118 |
+ Output: api.BuildOutput{
|
|
| 119 |
+ DockerImageReference: "repository/dataBuild", |
|
| 120 |
+ }, |
|
| 121 |
+ }, |
|
| 122 |
+ Status: api.BuildStatusPending, |
|
| 123 |
+ PodName: "-the-pod-id", |
|
| 124 |
+ }) |
|
| 125 |
+ if err != nil {
|
|
| 126 |
+ t.Fatalf("unexpected error: %v", err)
|
|
| 127 |
+ } |
|
| 128 |
+ |
|
| 129 |
+ resp, err := fakeClient.Get(makeTestDefaultBuildKey("foo"), false, false)
|
|
| 130 |
+ if err != nil {
|
|
| 131 |
+ t.Fatalf("Unexpected error %v", err)
|
|
| 132 |
+ } |
|
| 133 |
+ var build api.Build |
|
| 134 |
+ err = latest.Codec.DecodeInto([]byte(resp.Node.Value), &build) |
|
| 135 |
+ if err != nil {
|
|
| 136 |
+ t.Errorf("unexpected error: %v", err)
|
|
| 137 |
+ } |
|
| 138 |
+ |
|
| 139 |
+ if build.Name != "foo" {
|
|
| 140 |
+ t.Errorf("Unexpected build: %#v %s", build, resp.Node.Value)
|
|
| 141 |
+ } |
|
| 142 |
+} |
|
| 143 |
+ |
|
| 144 |
+func TestEtcdCreateBuildUsingImage(t *testing.T) {
|
|
| 145 |
+ fakeClient := tools.NewFakeEtcdClient(t) |
|
| 146 |
+ fakeClient.TestIndex = true |
|
| 147 |
+ fakeClient.Data[makeTestDefaultBuildKey("foo")] = tools.EtcdResponseWithError{
|
|
| 148 |
+ R: &etcd.Response{
|
|
| 149 |
+ Node: nil, |
|
| 150 |
+ }, |
|
| 151 |
+ E: tools.EtcdErrorNotFound, |
|
| 152 |
+ } |
|
| 153 |
+ registry := NewTestEtcd(fakeClient) |
|
| 154 |
+ err := registry.CreateBuild(kapi.NewDefaultContext(), &api.Build{
|
|
| 155 |
+ ObjectMeta: kapi.ObjectMeta{
|
|
| 156 |
+ Name: "foo", |
|
| 157 |
+ Labels: map[string]string{
|
|
| 158 |
+ "name": "dataBuild", |
|
| 159 |
+ }, |
|
| 160 |
+ }, |
|
| 161 |
+ Parameters: api.BuildParameters{
|
|
| 162 |
+ Source: api.BuildSource{
|
|
| 163 |
+ Git: &api.GitBuildSource{
|
|
| 164 |
+ URI: "http://my.build.com/the/build/Dockerfile", |
|
| 165 |
+ }, |
|
| 166 |
+ }, |
|
| 167 |
+ Strategy: api.BuildStrategy{
|
|
| 168 |
+ Type: api.STIBuildStrategyType, |
|
| 169 |
+ STIStrategy: &api.STIBuildStrategy{
|
|
| 113 | 170 |
Image: "builder/image", |
| 114 | 171 |
}, |
| 115 | 172 |
}, |
| ... | ... |
@@ -332,6 +389,61 @@ func TestEtcdCreateBuildConfig(t *testing.T) {
|
| 332 | 332 |
Strategy: api.BuildStrategy{
|
| 333 | 333 |
Type: api.STIBuildStrategyType, |
| 334 | 334 |
STIStrategy: &api.STIBuildStrategy{
|
| 335 |
+ From: &kapi.ObjectReference{
|
|
| 336 |
+ Name: "builder/image", |
|
| 337 |
+ }, |
|
| 338 |
+ }, |
|
| 339 |
+ }, |
|
| 340 |
+ Output: api.BuildOutput{
|
|
| 341 |
+ DockerImageReference: "repository/dataBuild", |
|
| 342 |
+ }, |
|
| 343 |
+ }, |
|
| 344 |
+ }) |
|
| 345 |
+ if err != nil {
|
|
| 346 |
+ t.Fatalf("unexpected error: %v", err)
|
|
| 347 |
+ } |
|
| 348 |
+ |
|
| 349 |
+ resp, err := fakeClient.Get(makeTestDefaultBuildConfigKey("foo"), false, false)
|
|
| 350 |
+ if err != nil {
|
|
| 351 |
+ t.Fatalf("Unexpected error %v", err)
|
|
| 352 |
+ } |
|
| 353 |
+ var buildConfig api.BuildConfig |
|
| 354 |
+ err = latest.Codec.DecodeInto([]byte(resp.Node.Value), &buildConfig) |
|
| 355 |
+ if err != nil {
|
|
| 356 |
+ t.Errorf("unexpected error: %v", err)
|
|
| 357 |
+ } |
|
| 358 |
+ |
|
| 359 |
+ if buildConfig.Name != "foo" {
|
|
| 360 |
+ t.Errorf("Unexpected buildConfig: %#v %s", buildConfig, resp.Node.Value)
|
|
| 361 |
+ } |
|
| 362 |
+} |
|
| 363 |
+ |
|
| 364 |
+func TestEtcdCreateBuildConfigUsingImage(t *testing.T) {
|
|
| 365 |
+ fakeClient := tools.NewFakeEtcdClient(t) |
|
| 366 |
+ fakeClient.TestIndex = true |
|
| 367 |
+ fakeClient.Data[makeTestDefaultBuildConfigKey("foo")] = tools.EtcdResponseWithError{
|
|
| 368 |
+ R: &etcd.Response{
|
|
| 369 |
+ Node: nil, |
|
| 370 |
+ }, |
|
| 371 |
+ E: tools.EtcdErrorNotFound, |
|
| 372 |
+ } |
|
| 373 |
+ registry := NewTestEtcd(fakeClient) |
|
| 374 |
+ err := registry.CreateBuildConfig(kapi.NewDefaultContext(), &api.BuildConfig{
|
|
| 375 |
+ ObjectMeta: kapi.ObjectMeta{
|
|
| 376 |
+ Name: "foo", |
|
| 377 |
+ Labels: map[string]string{
|
|
| 378 |
+ "name": "dataBuildConfig", |
|
| 379 |
+ }, |
|
| 380 |
+ }, |
|
| 381 |
+ Parameters: api.BuildParameters{
|
|
| 382 |
+ Source: api.BuildSource{
|
|
| 383 |
+ Git: &api.GitBuildSource{
|
|
| 384 |
+ URI: "http://my.build.com/the/build/Dockerfile", |
|
| 385 |
+ }, |
|
| 386 |
+ }, |
|
| 387 |
+ Strategy: api.BuildStrategy{
|
|
| 388 |
+ Type: api.STIBuildStrategyType, |
|
| 389 |
+ STIStrategy: &api.STIBuildStrategy{
|
|
| 335 | 390 |
Image: "builder/image", |
| 336 | 391 |
}, |
| 337 | 392 |
}, |
| ... | ... |
@@ -1,6 +1,7 @@ |
| 1 | 1 |
package util |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "fmt" |
|
| 4 | 5 |
"github.com/golang/glog" |
| 5 | 6 |
|
| 6 | 7 |
kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
| ... | ... |
@@ -13,7 +14,8 @@ import ( |
| 13 | 13 |
// GenerateBuildFromConfig creates a new build based on a given BuildConfig. Optionally a SourceRevision for the new |
| 14 | 14 |
// build can be specified. Also optionally a list of image names to be substituted can be supplied. Values in the BuildConfig |
| 15 | 15 |
// that have a substitution provided will be replaced in the resulting Build |
| 16 |
-func GenerateBuildFromConfig(bc *buildapi.BuildConfig, r *buildapi.SourceRevision, imageSubstitutions map[string]string) (build *buildapi.Build) {
|
|
| 16 |
+func GenerateBuildFromConfig(bc *buildapi.BuildConfig, ref *buildapi.SourceRevision, imageSubstitutions map[string]string, |
|
| 17 |
+ imageRepoSubstitutions map[kapi.ObjectReference]string) (build *buildapi.Build) {
|
|
| 17 | 18 |
// Need to copy the buildConfig here so that it doesn't share pointers with |
| 18 | 19 |
// the build object which could be (will be) modified later. |
| 19 | 20 |
obj, _ := kapi.Scheme.Copy(bc) |
| ... | ... |
@@ -24,7 +26,7 @@ func GenerateBuildFromConfig(bc *buildapi.BuildConfig, r *buildapi.SourceRevisio |
| 24 | 24 |
Source: bcCopy.Parameters.Source, |
| 25 | 25 |
Strategy: bcCopy.Parameters.Strategy, |
| 26 | 26 |
Output: bcCopy.Parameters.Output, |
| 27 |
- Revision: r, |
|
| 27 |
+ Revision: ref, |
|
| 28 | 28 |
}, |
| 29 | 29 |
ObjectMeta: kapi.ObjectMeta{
|
| 30 | 30 |
Labels: bcCopy.Labels, |
| ... | ... |
@@ -39,6 +41,14 @@ func GenerateBuildFromConfig(bc *buildapi.BuildConfig, r *buildapi.SourceRevisio |
| 39 | 39 |
glog.V(4).Infof("Substituting %s for %s", newImage, originalImage)
|
| 40 | 40 |
SubstituteImageReferences(b, originalImage, newImage) |
| 41 | 41 |
} |
| 42 |
+ for imageRepo, newImage := range imageRepoSubstitutions {
|
|
| 43 |
+ if len(imageRepo.Namespace) != 0 {
|
|
| 44 |
+ glog.V(4).Infof("Substituting repository %s for %s/%s", newImage, imageRepo.Namespace, imageRepo.Name)
|
|
| 45 |
+ } else {
|
|
| 46 |
+ glog.V(4).Infof("Substituting repository %s for %s", newImage, imageRepo.Name)
|
|
| 47 |
+ } |
|
| 48 |
+ SubstituteImageRepoReferences(b, imageRepo, newImage) |
|
| 49 |
+ } |
|
| 42 | 50 |
return b |
| 43 | 51 |
} |
| 44 | 52 |
|
| ... | ... |
@@ -62,10 +72,65 @@ func GenerateBuildFromBuild(build *buildapi.Build) *buildapi.Build {
|
| 62 | 62 |
// the image tag from the corresponding image repo rather than the image field from the buildconfig |
| 63 | 63 |
// as the base image for the build. |
| 64 | 64 |
func GenerateBuildWithImageTag(config *buildapi.BuildConfig, revision *buildapi.SourceRevision, imageRepoGetter osclient.ImageRepositoryNamespaceGetter) (*buildapi.Build, error) {
|
| 65 |
- |
|
| 66 |
- imageSubstitutions := make(map[string]string) |
|
| 65 |
+ var build *buildapi.Build |
|
| 66 |
+ var err error |
|
| 67 | 67 |
glog.V(4).Infof("Generating tagged build for config %s", config.Name)
|
| 68 | 68 |
|
| 69 |
+ switch {
|
|
| 70 |
+ case config.Parameters.Strategy.Type == buildapi.STIBuildStrategyType: |
|
| 71 |
+ if config.Parameters.Strategy.STIStrategy.From != nil && config.Parameters.Strategy.STIStrategy.From.Name != "" {
|
|
| 72 |
+ build, err = GenerateBuildUsingObjectReference(config, revision, imageRepoGetter) |
|
| 73 |
+ } else {
|
|
| 74 |
+ build, err = GenerateBuildUsingImageTriggerTag(config, revision, imageRepoGetter) |
|
| 75 |
+ } |
|
| 76 |
+ case config.Parameters.Strategy.Type == buildapi.DockerBuildStrategyType: |
|
| 77 |
+ build, err = GenerateBuildUsingImageTriggerTag(config, revision, imageRepoGetter) |
|
| 78 |
+ case config.Parameters.Strategy.Type == buildapi.CustomBuildStrategyType: |
|
| 79 |
+ build, err = GenerateBuildUsingImageTriggerTag(config, revision, imageRepoGetter) |
|
| 80 |
+ default: |
|
| 81 |
+ return nil, fmt.Errorf("Build strategy type must be set")
|
|
| 82 |
+ } |
|
| 83 |
+ return build, err |
|
| 84 |
+} |
|
| 85 |
+ |
|
| 86 |
+// GenerateBuildUsingObjectReference examines the ImageRepo referenced by the BuildConfig and resolves it to |
|
| 87 |
+// an imagespec, it then returns a Build object that uses that imagespec. |
|
| 88 |
+func GenerateBuildUsingObjectReference(config *buildapi.BuildConfig, revision *buildapi.SourceRevision, imageRepoGetter osclient.ImageRepositoryNamespaceGetter) (*buildapi.Build, error) {
|
|
| 89 |
+ imageRepoSubstitutions := make(map[kapi.ObjectReference]string) |
|
| 90 |
+ from := config.Parameters.Strategy.STIStrategy.From |
|
| 91 |
+ namespace := from.Namespace |
|
| 92 |
+ if len(namespace) == 0 {
|
|
| 93 |
+ namespace = config.Namespace |
|
| 94 |
+ } |
|
| 95 |
+ tag := config.Parameters.Strategy.STIStrategy.Tag |
|
| 96 |
+ if len(tag) == 0 {
|
|
| 97 |
+ tag = buildapi.DefaultImageTag |
|
| 98 |
+ } |
|
| 99 |
+ |
|
| 100 |
+ imageRepo, err := imageRepoGetter.GetByNamespace(namespace, from.Name) |
|
| 101 |
+ if err != nil {
|
|
| 102 |
+ return nil, err |
|
| 103 |
+ } |
|
| 104 |
+ if imageRepo == nil || imageRepo.Status.DockerImageRepository == "" {
|
|
| 105 |
+ return nil, fmt.Errorf("Docker Image Repository %s missing in namespace %s", from.Name, namespace)
|
|
| 106 |
+ } |
|
| 107 |
+ glog.V(4).Infof("Found image repo %s", imageRepo.Name)
|
|
| 108 |
+ latest, err := imageapi.LatestTaggedImage(imageRepo, tag) |
|
| 109 |
+ if err == nil {
|
|
| 110 |
+ glog.V(4).Infof("Using image %s for image repository %s in namespace %s", latest.DockerImageReference, from.Name, from.Namespace)
|
|
| 111 |
+ imageRepoSubstitutions[*from] = latest.DockerImageReference |
|
| 112 |
+ } else {
|
|
| 113 |
+ return nil, fmt.Errorf("Docker Image Repository %s has no tag %s", from.Name, tag)
|
|
| 114 |
+ } |
|
| 115 |
+ glog.V(4).Infof("Generating build from config for build config %s", config.Name)
|
|
| 116 |
+ return GenerateBuildFromConfig(config, revision, nil, imageRepoSubstitutions), nil |
|
| 117 |
+} |
|
| 118 |
+ |
|
| 119 |
+// GenerateBuildUsingTriggerTag examines the ImageChangeTriggers associated with the BuildConfig |
|
| 120 |
+// and uses them to determine the current imagespec that should be used to run this build, it then |
|
| 121 |
+// returns a Build object that uses that imagespec. |
|
| 122 |
+func GenerateBuildUsingImageTriggerTag(config *buildapi.BuildConfig, revision *buildapi.SourceRevision, imageRepoGetter osclient.ImageRepositoryNamespaceGetter) (*buildapi.Build, error) {
|
|
| 123 |
+ imageSubstitutions := make(map[string]string) |
|
| 69 | 124 |
for _, trigger := range config.Triggers {
|
| 70 | 125 |
if trigger.Type != buildapi.ImageChangeBuildTriggerType {
|
| 71 | 126 |
continue |
| ... | ... |
@@ -111,7 +176,7 @@ func GenerateBuildWithImageTag(config *buildapi.BuildConfig, revision *buildapi. |
| 111 | 111 |
imageSubstitutions[icTrigger.Image] = imageRef |
| 112 | 112 |
} |
| 113 | 113 |
glog.V(4).Infof("Generating build from config for build config %s", config.Name)
|
| 114 |
- build := GenerateBuildFromConfig(config, revision, imageSubstitutions) |
|
| 114 |
+ build := GenerateBuildFromConfig(config, revision, imageSubstitutions, nil) |
|
| 115 | 115 |
return build, nil |
| 116 | 116 |
} |
| 117 | 117 |
|
| ... | ... |
@@ -124,6 +189,7 @@ func SubstituteImageReferences(build *buildapi.Build, oldImage string, newImage |
| 124 | 124 |
build.Parameters.Strategy.DockerStrategy.Image = newImage |
| 125 | 125 |
case build.Parameters.Strategy.Type == buildapi.STIBuildStrategyType && |
| 126 | 126 |
build.Parameters.Strategy.STIStrategy != nil && |
| 127 |
+ (build.Parameters.Strategy.STIStrategy.From == nil || build.Parameters.Strategy.STIStrategy.From.Name == "") && |
|
| 127 | 128 |
build.Parameters.Strategy.STIStrategy.Image == oldImage: |
| 128 | 129 |
build.Parameters.Strategy.STIStrategy.Image = newImage |
| 129 | 130 |
case build.Parameters.Strategy.Type == buildapi.CustomBuildStrategyType: |
| ... | ... |
@@ -155,3 +221,18 @@ func SubstituteImageReferences(build *buildapi.Build, oldImage string, newImage |
| 155 | 155 |
} |
| 156 | 156 |
} |
| 157 | 157 |
} |
| 158 |
+ |
|
| 159 |
+// SubstituteImageRepoReferences uses references to an image repository to set an actual image name |
|
| 160 |
+// It also clears the ImageRepo reference from the BuildStrategy, if one was set. The imagereference |
|
| 161 |
+// field will be used explicitly. |
|
| 162 |
+func SubstituteImageRepoReferences(build *buildapi.Build, imageRepo kapi.ObjectReference, newImage string) {
|
|
| 163 |
+ switch {
|
|
| 164 |
+ case build.Parameters.Strategy.Type == buildapi.STIBuildStrategyType && |
|
| 165 |
+ build.Parameters.Strategy.STIStrategy != nil && |
|
| 166 |
+ build.Parameters.Strategy.STIStrategy.From != nil && |
|
| 167 |
+ build.Parameters.Strategy.STIStrategy.From.Name == imageRepo.Name && |
|
| 168 |
+ build.Parameters.Strategy.STIStrategy.From.Namespace == imageRepo.Namespace: |
|
| 169 |
+ build.Parameters.Strategy.STIStrategy.Image = newImage |
|
| 170 |
+ build.Parameters.Strategy.STIStrategy.From = nil |
|
| 171 |
+ } |
|
| 172 |
+} |
| ... | ... |
@@ -22,6 +22,7 @@ const ( |
| 22 | 22 |
|
| 23 | 23 |
imageRepoName = "testRepo" |
| 24 | 24 |
unmatchedImageRepoName = "unmatchedRepo" |
| 25 |
+ imageRepoNamespace = "testns" |
|
| 25 | 26 |
) |
| 26 | 27 |
|
| 27 | 28 |
func TestGenerateBuildFromConfig(t *testing.T) {
|
| ... | ... |
@@ -52,7 +53,7 @@ func TestGenerateBuildFromConfig(t *testing.T) {
|
| 52 | 52 |
Commit: "abcd", |
| 53 | 53 |
}, |
| 54 | 54 |
} |
| 55 |
- build := GenerateBuildFromConfig(bc, revision, nil) |
|
| 55 |
+ build := GenerateBuildFromConfig(bc, revision, nil, nil) |
|
| 56 | 56 |
if !reflect.DeepEqual(source, build.Parameters.Source) {
|
| 57 | 57 |
t.Errorf("Build source does not match BuildConfig source")
|
| 58 | 58 |
} |
| ... | ... |
@@ -73,7 +74,7 @@ func TestGenerateBuildFromConfig(t *testing.T) {
|
| 73 | 73 |
} |
| 74 | 74 |
} |
| 75 | 75 |
|
| 76 |
-func TestGenerateBuildWithImageTag(t *testing.T) {
|
|
| 76 |
+func TestGenerateBuildWithImageTagForDockerStrategy(t *testing.T) {
|
|
| 77 | 77 |
source := mockSource() |
| 78 | 78 |
strategy := mockDockerStrategy() |
| 79 | 79 |
strategy.DockerStrategy.Image = originalImage |
| ... | ... |
@@ -241,6 +242,82 @@ func TestGenerateBuildWithImageTagUnmatchedTag(t *testing.T) {
|
| 241 | 241 |
} |
| 242 | 242 |
} |
| 243 | 243 |
|
| 244 |
+func TestGenerateBuildWithImageTagForSTIStrategyImage(t *testing.T) {
|
|
| 245 |
+ source := mockSource() |
|
| 246 |
+ strategy := mockSTIStrategyForImage() |
|
| 247 |
+ output := mockOutput() |
|
| 248 |
+ imageRepoGetter := &mockImageRepositoryNamespaceGetter{"", imageRepoName}
|
|
| 249 |
+ |
|
| 250 |
+ bc := &buildapi.BuildConfig{
|
|
| 251 |
+ ObjectMeta: kapi.ObjectMeta{
|
|
| 252 |
+ Name: "test-build-config", |
|
| 253 |
+ }, |
|
| 254 |
+ Parameters: buildapi.BuildParameters{
|
|
| 255 |
+ Source: source, |
|
| 256 |
+ Revision: &buildapi.SourceRevision{
|
|
| 257 |
+ Type: buildapi.BuildSourceGit, |
|
| 258 |
+ Git: &buildapi.GitSourceRevision{
|
|
| 259 |
+ Commit: "1234", |
|
| 260 |
+ }, |
|
| 261 |
+ }, |
|
| 262 |
+ Strategy: strategy, |
|
| 263 |
+ Output: output, |
|
| 264 |
+ }, |
|
| 265 |
+ Triggers: []buildapi.BuildTriggerPolicy{
|
|
| 266 |
+ {
|
|
| 267 |
+ Type: buildapi.ImageChangeBuildTriggerType, |
|
| 268 |
+ ImageChange: &buildapi.ImageChangeTrigger{
|
|
| 269 |
+ Image: originalImage, |
|
| 270 |
+ From: kapi.ObjectReference{
|
|
| 271 |
+ Name: imageRepoName, |
|
| 272 |
+ }, |
|
| 273 |
+ Tag: tagName, |
|
| 274 |
+ }, |
|
| 275 |
+ }, |
|
| 276 |
+ }, |
|
| 277 |
+ } |
|
| 278 |
+ |
|
| 279 |
+ build, err := GenerateBuildWithImageTag(bc, nil, imageRepoGetter) |
|
| 280 |
+ if err != nil {
|
|
| 281 |
+ t.Errorf("Unexpected error %v", err)
|
|
| 282 |
+ } |
|
| 283 |
+ if build.Parameters.Strategy.STIStrategy.Image != newImage {
|
|
| 284 |
+ t.Errorf("STI base image value %s does not match expected value %s", build.Parameters.Strategy.STIStrategy.Image, newImage)
|
|
| 285 |
+ } |
|
| 286 |
+} |
|
| 287 |
+ |
|
| 288 |
+func TestGenerateBuildWithImageTagForSTIStrategyImageRepository(t *testing.T) {
|
|
| 289 |
+ source := mockSource() |
|
| 290 |
+ strategy := mockSTIStrategyForImageRepository() |
|
| 291 |
+ output := mockOutput() |
|
| 292 |
+ imageRepoGetter := &mockImageRepositoryNamespaceGetter{imageRepoNamespace, imageRepoName}
|
|
| 293 |
+ |
|
| 294 |
+ bc := &buildapi.BuildConfig{
|
|
| 295 |
+ ObjectMeta: kapi.ObjectMeta{
|
|
| 296 |
+ Name: "test-build-config", |
|
| 297 |
+ }, |
|
| 298 |
+ Parameters: buildapi.BuildParameters{
|
|
| 299 |
+ Source: source, |
|
| 300 |
+ Revision: &buildapi.SourceRevision{
|
|
| 301 |
+ Type: buildapi.BuildSourceGit, |
|
| 302 |
+ Git: &buildapi.GitSourceRevision{
|
|
| 303 |
+ Commit: "1234", |
|
| 304 |
+ }, |
|
| 305 |
+ }, |
|
| 306 |
+ Strategy: strategy, |
|
| 307 |
+ Output: output, |
|
| 308 |
+ }, |
|
| 309 |
+ } |
|
| 310 |
+ |
|
| 311 |
+ build, err := GenerateBuildWithImageTag(bc, nil, imageRepoGetter) |
|
| 312 |
+ if err != nil {
|
|
| 313 |
+ t.Errorf("Unexpected error %v", err)
|
|
| 314 |
+ } |
|
| 315 |
+ if build.Parameters.Strategy.STIStrategy.Image != newImage {
|
|
| 316 |
+ t.Errorf("STI base image value %s does not match expected value %s", build.Parameters.Strategy.STIStrategy.Image, newImage)
|
|
| 317 |
+ } |
|
| 318 |
+} |
|
| 319 |
+ |
|
| 244 | 320 |
func TestGenerateBuildFromBuild(t *testing.T) {
|
| 245 | 321 |
source := mockSource() |
| 246 | 322 |
strategy := mockDockerStrategy() |
| ... | ... |
@@ -276,7 +353,7 @@ func TestSubstituteImageDockerNil(t *testing.T) {
|
| 276 | 276 |
strategy := mockDockerStrategy() |
| 277 | 277 |
output := mockOutput() |
| 278 | 278 |
bc := mockBuildConfig(source, strategy, output) |
| 279 |
- build := GenerateBuildFromConfig(bc, nil, nil) |
|
| 279 |
+ build := GenerateBuildFromConfig(bc, nil, nil, nil) |
|
| 280 | 280 |
|
| 281 | 281 |
// Docker build with nil base image |
| 282 | 282 |
// base image should still be nil |
| ... | ... |
@@ -291,7 +368,7 @@ func TestSubstituteImageDockerMatch(t *testing.T) {
|
| 291 | 291 |
strategy := mockDockerStrategy() |
| 292 | 292 |
output := mockOutput() |
| 293 | 293 |
bc := mockBuildConfig(source, strategy, output) |
| 294 |
- build := GenerateBuildFromConfig(bc, nil, nil) |
|
| 294 |
+ build := GenerateBuildFromConfig(bc, nil, nil, nil) |
|
| 295 | 295 |
|
| 296 | 296 |
// Docker build with a matched base image |
| 297 | 297 |
// base image should be replaced. |
| ... | ... |
@@ -310,7 +387,7 @@ func TestSubstituteImageDockerMismatch(t *testing.T) {
|
| 310 | 310 |
strategy := mockDockerStrategy() |
| 311 | 311 |
output := mockOutput() |
| 312 | 312 |
bc := mockBuildConfig(source, strategy, output) |
| 313 |
- build := GenerateBuildFromConfig(bc, nil, nil) |
|
| 313 |
+ build := GenerateBuildFromConfig(bc, nil, nil, nil) |
|
| 314 | 314 |
|
| 315 | 315 |
// Docker build with an unmatched base image |
| 316 | 316 |
// base image should not be replaced. |
| ... | ... |
@@ -322,10 +399,10 @@ func TestSubstituteImageDockerMismatch(t *testing.T) {
|
| 322 | 322 |
|
| 323 | 323 |
func TestSubstituteImageSTIMatch(t *testing.T) {
|
| 324 | 324 |
source := mockSource() |
| 325 |
- strategy := mockSTIStrategy() |
|
| 325 |
+ strategy := mockSTIStrategyForImage() |
|
| 326 | 326 |
output := mockOutput() |
| 327 | 327 |
bc := mockBuildConfig(source, strategy, output) |
| 328 |
- build := GenerateBuildFromConfig(bc, nil, nil) |
|
| 328 |
+ build := GenerateBuildFromConfig(bc, nil, nil, nil) |
|
| 329 | 329 |
|
| 330 | 330 |
// STI build with a matched base image |
| 331 | 331 |
// base image should be replaced |
| ... | ... |
@@ -336,15 +413,33 @@ func TestSubstituteImageSTIMatch(t *testing.T) {
|
| 336 | 336 |
if bc.Parameters.Strategy.STIStrategy.Image != originalImage {
|
| 337 | 337 |
t.Errorf("STI BuildConfig was updated when Build was modified")
|
| 338 | 338 |
} |
| 339 |
+} |
|
| 340 |
+ |
|
| 341 |
+func TestSubstituteImageRepositorySTIMatch(t *testing.T) {
|
|
| 342 |
+ source := mockSource() |
|
| 343 |
+ strategy := mockSTIStrategyForImageRepository() |
|
| 344 |
+ repoRef := *strategy.STIStrategy.From |
|
| 345 |
+ output := mockOutput() |
|
| 346 |
+ bc := mockBuildConfig(source, strategy, output) |
|
| 347 |
+ build := GenerateBuildFromConfig(bc, nil, nil, nil) |
|
| 339 | 348 |
|
| 349 |
+ // STI build with a matched base image |
|
| 350 |
+ // base image should be replaced |
|
| 351 |
+ SubstituteImageRepoReferences(build, repoRef, newImage) |
|
| 352 |
+ if build.Parameters.Strategy.STIStrategy.Image != newImage {
|
|
| 353 |
+ t.Errorf("Base image name was not substituted in sti strategy")
|
|
| 354 |
+ } |
|
| 355 |
+ if bc.Parameters.Strategy.STIStrategy.Image != "" {
|
|
| 356 |
+ t.Errorf("STI BuildConfig was updated when Build was modified")
|
|
| 357 |
+ } |
|
| 340 | 358 |
} |
| 341 | 359 |
|
| 342 | 360 |
func TestSubstituteImageSTIMismatch(t *testing.T) {
|
| 343 | 361 |
source := mockSource() |
| 344 |
- strategy := mockSTIStrategy() |
|
| 362 |
+ strategy := mockSTIStrategyForImage() |
|
| 345 | 363 |
output := mockOutput() |
| 346 | 364 |
bc := mockBuildConfig(source, strategy, output) |
| 347 |
- build := GenerateBuildFromConfig(bc, nil, nil) |
|
| 365 |
+ build := GenerateBuildFromConfig(bc, nil, nil, nil) |
|
| 348 | 366 |
|
| 349 | 367 |
// STI build with an unmatched base image |
| 350 | 368 |
// base image should not be replaced |
| ... | ... |
@@ -354,12 +449,30 @@ func TestSubstituteImageSTIMismatch(t *testing.T) {
|
| 354 | 354 |
} |
| 355 | 355 |
} |
| 356 | 356 |
|
| 357 |
+func TestSubstituteImageRepositorySTIMismatch(t *testing.T) {
|
|
| 358 |
+ source := mockSource() |
|
| 359 |
+ strategy := mockSTIStrategyForImage() |
|
| 360 |
+ output := mockOutput() |
|
| 361 |
+ bc := mockBuildConfig(source, strategy, output) |
|
| 362 |
+ imageRepoRef := kapi.ObjectReference{
|
|
| 363 |
+ Name: "unmatched", |
|
| 364 |
+ } |
|
| 365 |
+ build := GenerateBuildFromConfig(bc, nil, nil, nil) |
|
| 366 |
+ |
|
| 367 |
+ // STI build with an unmatched image repository |
|
| 368 |
+ // base image should not be set |
|
| 369 |
+ SubstituteImageRepoReferences(build, imageRepoRef, "dummy") |
|
| 370 |
+ if build.Parameters.Strategy.STIStrategy.Image == "dummy" {
|
|
| 371 |
+ t.Errorf("Base image name was improperly set in STI strategy")
|
|
| 372 |
+ } |
|
| 373 |
+} |
|
| 374 |
+ |
|
| 357 | 375 |
func TestSubstituteImageCustomAllMatch(t *testing.T) {
|
| 358 | 376 |
source := mockSource() |
| 359 | 377 |
strategy := mockCustomStrategy() |
| 360 | 378 |
output := mockOutput() |
| 361 | 379 |
bc := mockBuildConfig(source, strategy, output) |
| 362 |
- build := GenerateBuildFromConfig(bc, nil, nil) |
|
| 380 |
+ build := GenerateBuildFromConfig(bc, nil, nil, nil) |
|
| 363 | 381 |
|
| 364 | 382 |
// Full custom build with a Image and a well defined environment variable image value, |
| 365 | 383 |
// both should be replaced. Additional environment variables should not be touched. |
| ... | ... |
@@ -393,7 +506,7 @@ func TestSubstituteImageCustomAllMismatch(t *testing.T) {
|
| 393 | 393 |
strategy := mockCustomStrategy() |
| 394 | 394 |
output := mockOutput() |
| 395 | 395 |
bc := mockBuildConfig(source, strategy, output) |
| 396 |
- build := GenerateBuildFromConfig(bc, nil, nil) |
|
| 396 |
+ build := GenerateBuildFromConfig(bc, nil, nil, nil) |
|
| 397 | 397 |
|
| 398 | 398 |
// Full custom build with base image that is not matched |
| 399 | 399 |
// Base image name should be unchanged |
| ... | ... |
@@ -408,7 +521,7 @@ func TestSubstituteImageCustomBaseMatchEnvMismatch(t *testing.T) {
|
| 408 | 408 |
strategy := mockCustomStrategy() |
| 409 | 409 |
output := mockOutput() |
| 410 | 410 |
bc := mockBuildConfig(source, strategy, output) |
| 411 |
- build := GenerateBuildFromConfig(bc, nil, nil) |
|
| 411 |
+ build := GenerateBuildFromConfig(bc, nil, nil, nil) |
|
| 412 | 412 |
|
| 413 | 413 |
// Full custom build with a Image and a well defined environment variable image value that does not match the new image |
| 414 | 414 |
// Only base image should be replaced. Environment variables should not be touched. |
| ... | ... |
@@ -435,7 +548,7 @@ func TestSubstituteImageCustomBaseMatchEnvMissing(t *testing.T) {
|
| 435 | 435 |
strategy := mockCustomStrategy() |
| 436 | 436 |
output := mockOutput() |
| 437 | 437 |
bc := mockBuildConfig(source, strategy, output) |
| 438 |
- build := GenerateBuildFromConfig(bc, nil, nil) |
|
| 438 |
+ build := GenerateBuildFromConfig(bc, nil, nil, nil) |
|
| 439 | 439 |
|
| 440 | 440 |
// Custom build with a base Image but no image environment variable. |
| 441 | 441 |
// base image should be replaced, new image environment variable should be added, |
| ... | ... |
@@ -462,7 +575,7 @@ func TestSubstituteImageCustomBaseMatchEnvNil(t *testing.T) {
|
| 462 | 462 |
strategy := mockCustomStrategy() |
| 463 | 463 |
output := mockOutput() |
| 464 | 464 |
bc := mockBuildConfig(source, strategy, output) |
| 465 |
- build := GenerateBuildFromConfig(bc, nil, nil) |
|
| 465 |
+ build := GenerateBuildFromConfig(bc, nil, nil, nil) |
|
| 466 | 466 |
|
| 467 | 467 |
// Custom build with a base Image but no environment variables |
| 468 | 468 |
// base image should be replaced, new image environment variable should be added |
| ... | ... |
@@ -497,7 +610,7 @@ func mockDockerStrategy() buildapi.BuildStrategy {
|
| 497 | 497 |
} |
| 498 | 498 |
} |
| 499 | 499 |
|
| 500 |
-func mockSTIStrategy() buildapi.BuildStrategy {
|
|
| 500 |
+func mockSTIStrategyForImage() buildapi.BuildStrategy {
|
|
| 501 | 501 |
return buildapi.BuildStrategy{
|
| 502 | 502 |
Type: buildapi.STIBuildStrategyType, |
| 503 | 503 |
STIStrategy: &buildapi.STIBuildStrategy{
|
| ... | ... |
@@ -506,6 +619,19 @@ func mockSTIStrategy() buildapi.BuildStrategy {
|
| 506 | 506 |
} |
| 507 | 507 |
} |
| 508 | 508 |
|
| 509 |
+func mockSTIStrategyForImageRepository() buildapi.BuildStrategy {
|
|
| 510 |
+ return buildapi.BuildStrategy{
|
|
| 511 |
+ Type: buildapi.STIBuildStrategyType, |
|
| 512 |
+ STIStrategy: &buildapi.STIBuildStrategy{
|
|
| 513 |
+ From: &kapi.ObjectReference{
|
|
| 514 |
+ Name: imageRepoName, |
|
| 515 |
+ Namespace: imageRepoNamespace, |
|
| 516 |
+ }, |
|
| 517 |
+ Tag: tagName, |
|
| 518 |
+ }, |
|
| 519 |
+ } |
|
| 520 |
+} |
|
| 521 |
+ |
|
| 509 | 522 |
func mockCustomStrategy() buildapi.BuildStrategy {
|
| 510 | 523 |
return buildapi.BuildStrategy{
|
| 511 | 524 |
Type: buildapi.CustomBuildStrategyType, |
| ... | ... |
@@ -15,13 +15,28 @@ import ( |
| 15 | 15 |
type okImageRepositoryNamespaceGetter struct{}
|
| 16 | 16 |
|
| 17 | 17 |
func (m *okImageRepositoryNamespaceGetter) GetByNamespace(namespace, name string) (*imageapi.ImageRepository, error) {
|
| 18 |
- return nil, nil |
|
| 18 |
+ return &imageapi.ImageRepository{
|
|
| 19 |
+ Status: imageapi.ImageRepositoryStatus{
|
|
| 20 |
+ DockerImageRepository: "repository/image", |
|
| 21 |
+ }, |
|
| 22 |
+ Tags: map[string]string{
|
|
| 23 |
+ "latest": "latest", |
|
| 24 |
+ }, |
|
| 25 |
+ }, nil |
|
| 19 | 26 |
} |
| 20 | 27 |
|
| 21 | 28 |
type okBuildConfigGetter struct{}
|
| 22 | 29 |
|
| 23 | 30 |
func (*okBuildConfigGetter) Get(namespace, name string) (*api.BuildConfig, error) {
|
| 24 | 31 |
return &api.BuildConfig{
|
| 32 |
+ Parameters: api.BuildParameters{
|
|
| 33 |
+ Strategy: api.BuildStrategy{
|
|
| 34 |
+ Type: "STI", |
|
| 35 |
+ STIStrategy: &api.STIBuildStrategy{
|
|
| 36 |
+ Image: "repository/builder-image", |
|
| 37 |
+ }, |
|
| 38 |
+ }, |
|
| 39 |
+ }, |
|
| 25 | 40 |
Triggers: []api.BuildTriggerPolicy{
|
| 26 | 41 |
{
|
| 27 | 42 |
Type: api.GithubWebHookBuildTriggerType, |
| ... | ... |
@@ -234,7 +249,14 @@ func (i *testBuildConfigInterface) Get(namespace, name string) (*api.BuildConfig |
| 234 | 234 |
func TestInvokeWebhookOk(t *testing.T) {
|
| 235 | 235 |
var buildRequest *api.Build |
| 236 | 236 |
buildConfig := &api.BuildConfig{
|
| 237 |
- Parameters: api.BuildParameters{},
|
|
| 237 |
+ Parameters: api.BuildParameters{
|
|
| 238 |
+ Strategy: api.BuildStrategy{
|
|
| 239 |
+ Type: "STI", |
|
| 240 |
+ STIStrategy: &api.STIBuildStrategy{
|
|
| 241 |
+ Image: "repository/builder-image", |
|
| 242 |
+ }, |
|
| 243 |
+ }, |
|
| 244 |
+ }, |
|
| 238 | 245 |
} |
| 239 | 246 |
|
| 240 | 247 |
server := httptest.NewServer(NewController( |
| ... | ... |
@@ -8,9 +8,19 @@ import ( |
| 8 | 8 |
"strings" |
| 9 | 9 |
"testing" |
| 10 | 10 |
|
| 11 |
+ kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api" |
|
| 11 | 12 |
"github.com/openshift/origin/pkg/build/api" |
| 12 | 13 |
) |
| 13 | 14 |
|
| 15 |
+var mockBuildStrategy api.BuildStrategy = api.BuildStrategy{
|
|
| 16 |
+ Type: "STI", |
|
| 17 |
+ STIStrategy: &api.STIBuildStrategy{
|
|
| 18 |
+ From: &kapi.ObjectReference{
|
|
| 19 |
+ Name: "repository/image", |
|
| 20 |
+ }, |
|
| 21 |
+ }, |
|
| 22 |
+} |
|
| 23 |
+ |
|
| 14 | 24 |
func GivenRequest(method string) *http.Request {
|
| 15 | 25 |
req, _ := http.NewRequest(method, "http://someurl.com", nil) |
| 16 | 26 |
return req |
| ... | ... |
@@ -106,7 +116,7 @@ func TestExtractWithEmptyPayload(t *testing.T) {
|
| 106 | 106 |
Ref: "master", |
| 107 | 107 |
}, |
| 108 | 108 |
}, |
| 109 |
- Strategy: api.BuildStrategy{},
|
|
| 109 |
+ Strategy: mockBuildStrategy, |
|
| 110 | 110 |
}, |
| 111 | 111 |
} |
| 112 | 112 |
plugin := New() |
| ... | ... |
@@ -140,7 +150,7 @@ func TestExtractWithUnmatchedRefGitPayload(t *testing.T) {
|
| 140 | 140 |
Ref: "asdfkasdfasdfasdfadsfkjhkhkh", |
| 141 | 141 |
}, |
| 142 | 142 |
}, |
| 143 |
- Strategy: api.BuildStrategy{},
|
|
| 143 |
+ Strategy: mockBuildStrategy, |
|
| 144 | 144 |
}, |
| 145 | 145 |
} |
| 146 | 146 |
plugin := New() |
| ... | ... |
@@ -175,7 +185,7 @@ func TestExtractWithGitPayload(t *testing.T) {
|
| 175 | 175 |
Ref: "master", |
| 176 | 176 |
}, |
| 177 | 177 |
}, |
| 178 |
- Strategy: api.BuildStrategy{},
|
|
| 178 |
+ Strategy: mockBuildStrategy, |
|
| 179 | 179 |
}, |
| 180 | 180 |
} |
| 181 | 181 |
plugin := New() |
| ... | ... |
@@ -16,7 +16,14 @@ import ( |
| 16 | 16 |
type okImageRepositoryNamespaceGetter struct{}
|
| 17 | 17 |
|
| 18 | 18 |
func (m *okImageRepositoryNamespaceGetter) GetByNamespace(namespace, name string) (*imageapi.ImageRepository, error) {
|
| 19 |
- return nil, nil |
|
| 19 |
+ return &imageapi.ImageRepository{
|
|
| 20 |
+ Status: imageapi.ImageRepositoryStatus{
|
|
| 21 |
+ DockerImageRepository: "repository/image", |
|
| 22 |
+ }, |
|
| 23 |
+ Tags: map[string]string{
|
|
| 24 |
+ "latest": "latest", |
|
| 25 |
+ }, |
|
| 26 |
+ }, nil |
|
| 20 | 27 |
} |
| 21 | 28 |
|
| 22 | 29 |
type okBuildConfigGetter struct{}
|
| ... | ... |
@@ -38,10 +45,18 @@ func (c *okBuildConfigGetter) Get(namespace, name string) (*api.BuildConfig, err |
| 38 | 38 |
URI: "git://github.com/my/repo.git", |
| 39 | 39 |
}, |
| 40 | 40 |
}, |
| 41 |
+ Strategy: mockBuildStrategy, |
|
| 41 | 42 |
}, |
| 42 | 43 |
}, nil |
| 43 | 44 |
} |
| 44 | 45 |
|
| 46 |
+var mockBuildStrategy api.BuildStrategy = api.BuildStrategy{
|
|
| 47 |
+ Type: "STI", |
|
| 48 |
+ STIStrategy: &api.STIBuildStrategy{
|
|
| 49 |
+ Image: "repository/image", |
|
| 50 |
+ }, |
|
| 51 |
+} |
|
| 52 |
+ |
|
| 45 | 53 |
type okBuildCreator struct{}
|
| 46 | 54 |
|
| 47 | 55 |
func (c *okBuildCreator) Create(namespace string, build *api.Build) error {
|
| ... | ... |
@@ -207,6 +222,7 @@ func setup(t *testing.T, filename, eventType string) *testContext {
|
| 207 | 207 |
URI: "git://github.com/my/repo.git", |
| 208 | 208 |
}, |
| 209 | 209 |
}, |
| 210 |
+ Strategy: mockBuildStrategy, |
|
| 210 | 211 |
}, |
| 211 | 212 |
}, |
| 212 | 213 |
path: "/foobar", |
| ... | ... |
@@ -78,7 +78,54 @@ func (d *BuildDescriber) DescribeUser(out *tabwriter.Writer, label string, u bui |
| 78 | 78 |
} |
| 79 | 79 |
} |
| 80 | 80 |
|
| 81 |
-func (d *BuildDescriber) DescribeParameters(p buildapi.BuildParameters, out *tabwriter.Writer) {
|
|
| 81 |
+func (d *BuildDescriber) Describe(namespace, name string) (string, error) {
|
|
| 82 |
+ c := d.Builds(namespace) |
|
| 83 |
+ build, err := c.Get(name) |
|
| 84 |
+ if err != nil {
|
|
| 85 |
+ return "", err |
|
| 86 |
+ } |
|
| 87 |
+ return tabbedString(func(out *tabwriter.Writer) error {
|
|
| 88 |
+ formatMeta(out, build.ObjectMeta) |
|
| 89 |
+ formatString(out, "Status", bold(build.Status)) |
|
| 90 |
+ if build.StartTimestamp != nil {
|
|
| 91 |
+ formatString(out, "Started", build.StartTimestamp.Time) |
|
| 92 |
+ } |
|
| 93 |
+ if build.CompletionTimestamp != nil {
|
|
| 94 |
+ formatString(out, "Finished", build.CompletionTimestamp.Time) |
|
| 95 |
+ } |
|
| 96 |
+ // Create the time object with second-level precision so we don't get |
|
| 97 |
+ // output like "duration: 1.2724395728934s" |
|
| 98 |
+ t := util.Now().Rfc3339Copy() |
|
| 99 |
+ if build.StartTimestamp != nil && build.CompletionTimestamp != nil {
|
|
| 100 |
+ // time a build ran from pod creation to build finish or cancel |
|
| 101 |
+ formatString(out, "Duration", build.CompletionTimestamp.Sub(build.StartTimestamp.Rfc3339Copy().Time)) |
|
| 102 |
+ } else if build.CompletionTimestamp != nil && build.Status == buildapi.BuildStatusCancelled {
|
|
| 103 |
+ // time a build waited for its pod before ultimately being canceled before that pod was created |
|
| 104 |
+ formatString(out, "Duration", fmt.Sprintf("waited for %s", build.CompletionTimestamp.Sub(build.CreationTimestamp.Rfc3339Copy().Time)))
|
|
| 105 |
+ } else if build.CompletionTimestamp != nil && build.Status != buildapi.BuildStatusCancelled {
|
|
| 106 |
+ // for some reason we never saw the pod enter the running state, so we don't know when it |
|
| 107 |
+ // "started", so instead print out the time from creation to completion. |
|
| 108 |
+ formatString(out, "Duration", build.CompletionTimestamp.Sub(build.CreationTimestamp.Rfc3339Copy().Time)) |
|
| 109 |
+ } else if build.StartTimestamp == nil && build.Status != buildapi.BuildStatusCancelled {
|
|
| 110 |
+ // time a new build has been waiting for its pod to be created so it can run |
|
| 111 |
+ formatString(out, "Duration", fmt.Sprintf("waiting for %s", t.Sub(build.CreationTimestamp.Rfc3339Copy().Time)))
|
|
| 112 |
+ } else if build.CompletionTimestamp == nil {
|
|
| 113 |
+ // time a still running build has been running in a pod |
|
| 114 |
+ formatString(out, "Duration", fmt.Sprintf("running for %s", t.Sub(build.StartTimestamp.Rfc3339Copy().Time)))
|
|
| 115 |
+ } |
|
| 116 |
+ formatString(out, "Build Pod", build.PodName) |
|
| 117 |
+ describeBuildParameters(build.Parameters, out) |
|
| 118 |
+ return nil |
|
| 119 |
+ }) |
|
| 120 |
+} |
|
| 121 |
+ |
|
| 122 |
+// BuildConfigDescriber generates information about a buildConfig |
|
| 123 |
+type BuildConfigDescriber struct {
|
|
| 124 |
+ client.Interface |
|
| 125 |
+ host string |
|
| 126 |
+} |
|
| 127 |
+ |
|
| 128 |
+func describeBuildParameters(p buildapi.BuildParameters, out *tabwriter.Writer) {
|
|
| 82 | 129 |
formatString(out, "Strategy", p.Strategy.Type) |
| 83 | 130 |
switch p.Strategy.Type {
|
| 84 | 131 |
case buildapi.DockerBuildStrategyType: |
| ... | ... |
@@ -89,10 +136,7 @@ func (d *BuildDescriber) DescribeParameters(p buildapi.BuildParameters, out *tab |
| 89 | 89 |
formatString(out, "Image", p.Strategy.DockerStrategy.Image) |
| 90 | 90 |
} |
| 91 | 91 |
case buildapi.STIBuildStrategyType: |
| 92 |
- formatString(out, "Image", p.Strategy.STIStrategy.Image) |
|
| 93 |
- if p.Strategy.STIStrategy.Incremental {
|
|
| 94 |
- formatString(out, "Incremental Build", "yes") |
|
| 95 |
- } |
|
| 92 |
+ describeSTIStrategy(p.Strategy.STIStrategy, out) |
|
| 96 | 93 |
case buildapi.CustomBuildStrategyType: |
| 97 | 94 |
formatString(out, "Image", p.Strategy.CustomStrategy.Image) |
| 98 | 95 |
if p.Strategy.CustomStrategy.ExposeDockerSocket {
|
| ... | ... |
@@ -122,62 +166,36 @@ func (d *BuildDescriber) DescribeParameters(p buildapi.BuildParameters, out *tab |
| 122 | 122 |
|
| 123 | 123 |
formatString(out, "Output Spec", p.Output.DockerImageReference) |
| 124 | 124 |
if p.Revision != nil && p.Revision.Type == buildapi.BuildSourceGit && p.Revision.Git != nil {
|
| 125 |
+ buildDescriber := &BuildDescriber{}
|
|
| 126 |
+ |
|
| 125 | 127 |
formatString(out, "Git Commit", p.Revision.Git.Commit) |
| 126 |
- d.DescribeUser(out, "Revision Author", p.Revision.Git.Author) |
|
| 127 |
- d.DescribeUser(out, "Revision Committer", p.Revision.Git.Committer) |
|
| 128 |
+ buildDescriber.DescribeUser(out, "Revision Author", p.Revision.Git.Author) |
|
| 129 |
+ buildDescriber.DescribeUser(out, "Revision Committer", p.Revision.Git.Committer) |
|
| 128 | 130 |
if len(p.Revision.Git.Message) > 0 {
|
| 129 | 131 |
formatString(out, "Revision Message", p.Revision.Git.Message) |
| 130 | 132 |
} |
| 131 | 133 |
} |
| 132 | 134 |
} |
| 133 | 135 |
|
| 134 |
-func (d *BuildDescriber) Describe(namespace, name string) (string, error) {
|
|
| 135 |
- c := d.Builds(namespace) |
|
| 136 |
- build, err := c.Get(name) |
|
| 137 |
- if err != nil {
|
|
| 138 |
- return "", err |
|
| 139 |
- } |
|
| 140 |
- |
|
| 141 |
- return tabbedString(func(out *tabwriter.Writer) error {
|
|
| 142 |
- formatMeta(out, build.ObjectMeta) |
|
| 143 |
- formatString(out, "Status", bold(build.Status)) |
|
| 144 |
- if build.StartTimestamp != nil {
|
|
| 145 |
- formatString(out, "Started", build.StartTimestamp.Time) |
|
| 146 |
- } |
|
| 147 |
- if build.CompletionTimestamp != nil {
|
|
| 148 |
- formatString(out, "Finished", build.CompletionTimestamp.Time) |
|
| 136 |
+func describeSTIStrategy(s *buildapi.STIBuildStrategy, out *tabwriter.Writer) {
|
|
| 137 |
+ if s.From != nil && s.From.Name != "" {
|
|
| 138 |
+ if s.From.Namespace != "" {
|
|
| 139 |
+ formatString(out, "Image Repository", fmt.Sprintf("%s/%s", s.From.Name, s.From.Namespace))
|
|
| 140 |
+ } else {
|
|
| 141 |
+ formatString(out, "Image Repository", s.From.Name) |
|
| 149 | 142 |
} |
| 150 |
- // Create the time object with second-level precision so we don't get |
|
| 151 |
- // output like "duration: 1.2724395728934s" |
|
| 152 |
- t := util.Now().Rfc3339Copy() |
|
| 153 |
- if build.StartTimestamp != nil && build.CompletionTimestamp != nil {
|
|
| 154 |
- // time a build ran from pod creation to build finish or cancel |
|
| 155 |
- formatString(out, "Duration", build.CompletionTimestamp.Sub(build.StartTimestamp.Rfc3339Copy().Time)) |
|
| 156 |
- } else if build.CompletionTimestamp != nil && build.Status == buildapi.BuildStatusCancelled {
|
|
| 157 |
- // time a build waited for its pod before ultimately being canceled before that pod was created |
|
| 158 |
- formatString(out, "Duration", fmt.Sprintf("waited for %s", build.CompletionTimestamp.Sub(build.CreationTimestamp.Rfc3339Copy().Time)))
|
|
| 159 |
- } else if build.CompletionTimestamp != nil && build.Status != buildapi.BuildStatusCancelled {
|
|
| 160 |
- // for some reason we never saw the pod enter the running state, so we don't know when it |
|
| 161 |
- // "started", so instead print out the time from creation to completion. |
|
| 162 |
- formatString(out, "Duration", build.CompletionTimestamp.Sub(build.CreationTimestamp.Rfc3339Copy().Time)) |
|
| 163 |
- } else if build.StartTimestamp == nil && build.Status != buildapi.BuildStatusCancelled {
|
|
| 164 |
- // time a new build has been waiting for its pod to be created so it can run |
|
| 165 |
- formatString(out, "Duration", fmt.Sprintf("waiting for %s", t.Sub(build.CreationTimestamp.Rfc3339Copy().Time)))
|
|
| 166 |
- } else if build.CompletionTimestamp == nil {
|
|
| 167 |
- // time a still running build has been running in a pod |
|
| 168 |
- formatString(out, "Duration", fmt.Sprintf("running for %s", t.Sub(build.StartTimestamp.Rfc3339Copy().Time)))
|
|
| 143 |
+ if s.Tag != "" {
|
|
| 144 |
+ formatString(out, "Image Repository Tag", s.Tag) |
|
| 169 | 145 |
} |
| 170 |
- |
|
| 171 |
- formatString(out, "Build Pod", build.PodName) |
|
| 172 |
- d.DescribeParameters(build.Parameters, out) |
|
| 173 |
- return nil |
|
| 174 |
- }) |
|
| 175 |
-} |
|
| 176 |
- |
|
| 177 |
-// BuildConfigDescriber generates information about a buildConfig |
|
| 178 |
-type BuildConfigDescriber struct {
|
|
| 179 |
- client.Interface |
|
| 180 |
- host string |
|
| 146 |
+ } else {
|
|
| 147 |
+ formatString(out, "Builder Image", s.Image) |
|
| 148 |
+ } |
|
| 149 |
+ if s.Scripts != "" {
|
|
| 150 |
+ formatString(out, "Scripts", s.Scripts) |
|
| 151 |
+ } |
|
| 152 |
+ if s.Incremental {
|
|
| 153 |
+ formatString(out, "Incremental Build", "yes") |
|
| 154 |
+ } |
|
| 181 | 155 |
} |
| 182 | 156 |
|
| 183 | 157 |
// DescribeTriggers generates information about the triggers associated with a buildconfig |
| ... | ... |
@@ -209,11 +227,9 @@ func (d *BuildConfigDescriber) Describe(namespace, name string) (string, error) |
| 209 | 209 |
return "", err |
| 210 | 210 |
} |
| 211 | 211 |
|
| 212 |
- buildDescriber := &BuildDescriber{}
|
|
| 213 |
- |
|
| 214 | 212 |
return tabbedString(func(out *tabwriter.Writer) error {
|
| 215 | 213 |
formatMeta(out, buildConfig.ObjectMeta) |
| 216 |
- buildDescriber.DescribeParameters(buildConfig.Parameters, out) |
|
| 214 |
+ describeBuildParameters(buildConfig.Parameters, out) |
|
| 217 | 215 |
d.DescribeTriggers(buildConfig, d.host, out) |
| 218 | 216 |
return nil |
| 219 | 217 |
}) |
| 220 | 218 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,107 @@ |
| 0 |
+{
|
|
| 1 |
+ "apiVersion": "v1beta1", |
|
| 2 |
+ "items": [ |
|
| 3 |
+ {
|
|
| 4 |
+ "apiVersion": "v1beta1", |
|
| 5 |
+ "dockerImageRepository": "openshift/ruby-20-centos", |
|
| 6 |
+ "kind": "ImageRepository", |
|
| 7 |
+ "metadata": {
|
|
| 8 |
+ "name": "ruby-20-centos-buildcli" |
|
| 9 |
+ }, |
|
| 10 |
+ "tags": {
|
|
| 11 |
+ "valid": "success" |
|
| 12 |
+ } |
|
| 13 |
+ }, |
|
| 14 |
+ {
|
|
| 15 |
+ "apiVersion": "v1beta1", |
|
| 16 |
+ "kind": "BuildConfig", |
|
| 17 |
+ "labels": {
|
|
| 18 |
+ "name": "ruby-sample-build" |
|
| 19 |
+ }, |
|
| 20 |
+ "metadata": {
|
|
| 21 |
+ "name": "ruby-sample-build-validtag" |
|
| 22 |
+ }, |
|
| 23 |
+ "parameters": {
|
|
| 24 |
+ "output": {
|
|
| 25 |
+ "to": {
|
|
| 26 |
+ "name": "origin-ruby-sample" |
|
| 27 |
+ } |
|
| 28 |
+ }, |
|
| 29 |
+ "source": {
|
|
| 30 |
+ "git": {
|
|
| 31 |
+ "uri": "git://github.com/openshift/ruby-hello-world.git" |
|
| 32 |
+ }, |
|
| 33 |
+ "type": "Git" |
|
| 34 |
+ }, |
|
| 35 |
+ "strategy": {
|
|
| 36 |
+ "stiStrategy": {
|
|
| 37 |
+ "from": {
|
|
| 38 |
+ "name": "ruby-20-centos-buildcli" |
|
| 39 |
+ }, |
|
| 40 |
+ "tag": "valid", |
|
| 41 |
+ "scripts": "https://raw.githubusercontent.com/openshift/ruby-20-centos/master/.sti/bin" |
|
| 42 |
+ }, |
|
| 43 |
+ "type": "STI" |
|
| 44 |
+ } |
|
| 45 |
+ }, |
|
| 46 |
+ "triggers": [ |
|
| 47 |
+ {
|
|
| 48 |
+ "imageChange": {
|
|
| 49 |
+ "from": {
|
|
| 50 |
+ "name": "ruby-20-centos-buildcli" |
|
| 51 |
+ }, |
|
| 52 |
+ "image": "openshift/ruby-20-centos", |
|
| 53 |
+ "tag": "valid" |
|
| 54 |
+ }, |
|
| 55 |
+ "type": "imageChange" |
|
| 56 |
+ } |
|
| 57 |
+ ] |
|
| 58 |
+ }, |
|
| 59 |
+ {
|
|
| 60 |
+ "apiVersion": "v1beta1", |
|
| 61 |
+ "kind": "BuildConfig", |
|
| 62 |
+ "labels": {
|
|
| 63 |
+ "name": "ruby-sample-build" |
|
| 64 |
+ }, |
|
| 65 |
+ "metadata": {
|
|
| 66 |
+ "name": "ruby-sample-build-invalidtag" |
|
| 67 |
+ }, |
|
| 68 |
+ "parameters": {
|
|
| 69 |
+ "output": {
|
|
| 70 |
+ "to": {
|
|
| 71 |
+ "name": "origin-ruby-sample" |
|
| 72 |
+ } |
|
| 73 |
+ }, |
|
| 74 |
+ "source": {
|
|
| 75 |
+ "git": {
|
|
| 76 |
+ "uri": "git://github.com/openshift/ruby-hello-world.git" |
|
| 77 |
+ }, |
|
| 78 |
+ "type": "Git" |
|
| 79 |
+ }, |
|
| 80 |
+ "strategy": {
|
|
| 81 |
+ "stiStrategy": {
|
|
| 82 |
+ "from": {
|
|
| 83 |
+ "name": "ruby-20-centos-buildcli" |
|
| 84 |
+ }, |
|
| 85 |
+ "tag": "invalid", |
|
| 86 |
+ "scripts": "https://raw.githubusercontent.com/openshift/ruby-20-centos/master/.sti/bin" |
|
| 87 |
+ }, |
|
| 88 |
+ "type": "STI" |
|
| 89 |
+ } |
|
| 90 |
+ }, |
|
| 91 |
+ "triggers": [ |
|
| 92 |
+ {
|
|
| 93 |
+ "imageChange": {
|
|
| 94 |
+ "from": {
|
|
| 95 |
+ "name": "ruby-20-centos-buildcli" |
|
| 96 |
+ }, |
|
| 97 |
+ "image": "openshift/ruby-20-centos", |
|
| 98 |
+ "tag": "invalid" |
|
| 99 |
+ }, |
|
| 100 |
+ "type": "imageChange" |
|
| 101 |
+ } |
|
| 102 |
+ ] |
|
| 103 |
+ } |
|
| 104 |
+ ], |
|
| 105 |
+ "kind": "List" |
|
| 106 |
+} |
| ... | ... |
@@ -106,13 +106,6 @@ func TestSimpleImageChangeBuildTrigger(t *testing.T) {
|
| 106 | 106 |
}); err != nil {
|
| 107 | 107 |
t.Fatalf("unexpected error: %v", err)
|
| 108 | 108 |
} |
| 109 |
- /* |
|
| 110 |
- // update the image tag to ref-2 in the imagerepo so we get another build event using that tag. |
|
| 111 |
- imageRepo.Tags["latest"] = "ref-2" |
|
| 112 |
- if _, err = openshift.Client.ImageRepositories(testutil.Namespace()).Update(imageRepo); err != nil {
|
|
| 113 |
- t.Fatalf("Error updating imageRepo: %v", err)
|
|
| 114 |
- } |
|
| 115 |
- */ |
|
| 116 | 109 |
event = <-watch.ResultChan() |
| 117 | 110 |
if e, a := watchapi.Added, event.Type; e != a {
|
| 118 | 111 |
t.Fatalf("expected watch event type %s, got %s", e, a)
|
| ... | ... |
@@ -135,7 +128,126 @@ func TestSimpleImageChangeBuildTrigger(t *testing.T) {
|
| 135 | 135 |
t.Fatalf("Expected build with label %s=%s from build config got %s=%s", "testlabel", "testvalue", "testlabel", newBuild.Labels["testlabel"])
|
| 136 | 136 |
} |
| 137 | 137 |
|
| 138 |
- event = <-watch2.ResultChan() |
|
| 138 |
+ <-watch2.ResultChan() |
|
| 139 |
+ updatedConfig, err = openshift.Client.BuildConfigs(testutil.Namespace()).Get(config.Name) |
|
| 140 |
+ if err != nil {
|
|
| 141 |
+ t.Fatalf("Couldn't get BuildConfig: %v", err)
|
|
| 142 |
+ } |
|
| 143 |
+ if updatedConfig.Triggers[0].ImageChange.LastTriggeredImageID != "ref-2-random" {
|
|
| 144 |
+ t.Errorf("unexpected trigger id: %#v", updatedConfig.Triggers[0].ImageChange)
|
|
| 145 |
+ } |
|
| 146 |
+} |
|
| 147 |
+ |
|
| 148 |
+func TestSimpleImageChangeBuildTriggerFromRef(t *testing.T) {
|
|
| 149 |
+ testutil.DeleteAllEtcdKeys() |
|
| 150 |
+ openshift := NewTestOpenshift(t) |
|
| 151 |
+ defer openshift.Close() |
|
| 152 |
+ |
|
| 153 |
+ imageRepo := &imageapi.ImageRepository{
|
|
| 154 |
+ ObjectMeta: kapi.ObjectMeta{Name: "test-image-trigger-repo"},
|
|
| 155 |
+ DockerImageRepository: "registry:8080/openshift/test-image-trigger", |
|
| 156 |
+ Tags: map[string]string{
|
|
| 157 |
+ "latest": "latest", |
|
| 158 |
+ }, |
|
| 159 |
+ } |
|
| 160 |
+ |
|
| 161 |
+ config := imageChangeBuildConfigFromRef() |
|
| 162 |
+ |
|
| 163 |
+ created, err := openshift.Client.BuildConfigs(testutil.Namespace()).Create(config) |
|
| 164 |
+ if err != nil {
|
|
| 165 |
+ t.Fatalf("Couldn't create BuildConfig: %v", err)
|
|
| 166 |
+ } |
|
| 167 |
+ |
|
| 168 |
+ watch, err := openshift.Client.Builds(testutil.Namespace()).Watch(labels.Everything(), fields.Everything(), created.ResourceVersion) |
|
| 169 |
+ if err != nil {
|
|
| 170 |
+ t.Fatalf("Couldn't subscribe to Builds %v", err)
|
|
| 171 |
+ } |
|
| 172 |
+ defer watch.Stop() |
|
| 173 |
+ |
|
| 174 |
+ watch2, err := openshift.Client.BuildConfigs(testutil.Namespace()).Watch(labels.Everything(), fields.Everything(), created.ResourceVersion) |
|
| 175 |
+ if err != nil {
|
|
| 176 |
+ t.Fatalf("Couldn't subscribe to BuildConfigs %v", err)
|
|
| 177 |
+ } |
|
| 178 |
+ defer watch2.Stop() |
|
| 179 |
+ |
|
| 180 |
+ imageRepo, err = openshift.Client.ImageRepositories(testutil.Namespace()).Create(imageRepo) |
|
| 181 |
+ if err != nil {
|
|
| 182 |
+ t.Fatalf("Couldn't create ImageRepository: %v", err)
|
|
| 183 |
+ } |
|
| 184 |
+ |
|
| 185 |
+ // wait for initial build event from the creation of the imagerepo with tag latest |
|
| 186 |
+ event := <-watch.ResultChan() |
|
| 187 |
+ if e, a := watchapi.Added, event.Type; e != a {
|
|
| 188 |
+ t.Fatalf("expected watch event type %s, got %s", e, a)
|
|
| 189 |
+ } |
|
| 190 |
+ newBuild := event.Object.(*buildapi.Build) |
|
| 191 |
+ if newBuild.Parameters.Strategy.STIStrategy.Image != "registry:8080/openshift/test-image-trigger:latest" {
|
|
| 192 |
+ i, _ := openshift.Client.ImageRepositories(testutil.Namespace()).Get(imageRepo.Name) |
|
| 193 |
+ bc, _ := openshift.Client.BuildConfigs(testutil.Namespace()).Get(config.Name) |
|
| 194 |
+ t.Fatalf("Expected build with base image %s, got %s\n, imagerepo is %v\ntrigger is %s\n", "registry:8080/openshift/test-image-trigger:latest", newBuild.Parameters.Strategy.STIStrategy.Image, i, bc.Triggers[0].ImageChange)
|
|
| 195 |
+ } |
|
| 196 |
+ event = <-watch.ResultChan() |
|
| 197 |
+ if e, a := watchapi.Modified, event.Type; e != a {
|
|
| 198 |
+ t.Fatalf("expected watch event type %s, got %s", e, a)
|
|
| 199 |
+ } |
|
| 200 |
+ newBuild = event.Object.(*buildapi.Build) |
|
| 201 |
+ if newBuild.Parameters.Output.DockerImageReference != "registry:8080/openshift/test-image-trigger:outputtag" {
|
|
| 202 |
+ t.Fatalf("Expected build with output image %s, got %s", "registry:8080/openshift/test-image-trigger:outputtag", newBuild.Parameters.Output.DockerImageReference)
|
|
| 203 |
+ } |
|
| 204 |
+ if newBuild.Labels["testlabel"] != "testvalue" {
|
|
| 205 |
+ t.Fatalf("Expected build with label %s=%s from build config got %s=%s", "testlabel", "testvalue", "testlabel", newBuild.Labels["testlabel"])
|
|
| 206 |
+ } |
|
| 207 |
+ |
|
| 208 |
+ // wait for build config to be updated |
|
| 209 |
+ <-watch2.ResultChan() |
|
| 210 |
+ updatedConfig, err := openshift.Client.BuildConfigs(testutil.Namespace()).Get(config.Name) |
|
| 211 |
+ if err != nil {
|
|
| 212 |
+ t.Fatalf("Couldn't get BuildConfig: %v", err)
|
|
| 213 |
+ } |
|
| 214 |
+ // the first tag did not have an image id, so the last trigger field is the pull spec |
|
| 215 |
+ if updatedConfig.Triggers[0].ImageChange.LastTriggeredImageID != "registry:8080/openshift/test-image-trigger:latest" {
|
|
| 216 |
+ t.Errorf("Expected imageID equal to pull spec, got %s", updatedConfig.Triggers[0].ImageChange)
|
|
| 217 |
+ } |
|
| 218 |
+ |
|
| 219 |
+ // trigger a build by posting a new image |
|
| 220 |
+ if err := openshift.Client.ImageRepositoryMappings(testutil.Namespace()).Create(&imageapi.ImageRepositoryMapping{
|
|
| 221 |
+ ObjectMeta: kapi.ObjectMeta{
|
|
| 222 |
+ Namespace: testutil.Namespace(), |
|
| 223 |
+ Name: imageRepo.Name, |
|
| 224 |
+ }, |
|
| 225 |
+ Tag: "latest", |
|
| 226 |
+ Image: imageapi.Image{
|
|
| 227 |
+ ObjectMeta: kapi.ObjectMeta{
|
|
| 228 |
+ Name: "ref-2-random", |
|
| 229 |
+ }, |
|
| 230 |
+ DockerImageReference: "registry:8080/openshift/test-image-trigger:ref-2", |
|
| 231 |
+ }, |
|
| 232 |
+ }); err != nil {
|
|
| 233 |
+ t.Fatalf("unexpected error: %v", err)
|
|
| 234 |
+ } |
|
| 235 |
+ event = <-watch.ResultChan() |
|
| 236 |
+ if e, a := watchapi.Added, event.Type; e != a {
|
|
| 237 |
+ t.Fatalf("expected watch event type %s, got %s", e, a)
|
|
| 238 |
+ } |
|
| 239 |
+ newBuild = event.Object.(*buildapi.Build) |
|
| 240 |
+ if newBuild.Parameters.Strategy.STIStrategy.Image != "registry:8080/openshift/test-image-trigger:ref-2" {
|
|
| 241 |
+ i, _ := openshift.Client.ImageRepositories(testutil.Namespace()).Get(imageRepo.Name) |
|
| 242 |
+ bc, _ := openshift.Client.BuildConfigs(testutil.Namespace()).Get(config.Name) |
|
| 243 |
+ t.Fatalf("Expected build with base image %s, got %s\n, imagerepo is %v\trigger is %s\n", "registry:8080/openshift/test-image-trigger:ref-2", newBuild.Parameters.Strategy.STIStrategy.Image, i, bc.Triggers[0].ImageChange)
|
|
| 244 |
+ } |
|
| 245 |
+ event = <-watch.ResultChan() |
|
| 246 |
+ if e, a := watchapi.Modified, event.Type; e != a {
|
|
| 247 |
+ t.Fatalf("expected watch event type %s, got %s", e, a)
|
|
| 248 |
+ } |
|
| 249 |
+ newBuild = event.Object.(*buildapi.Build) |
|
| 250 |
+ if newBuild.Parameters.Output.DockerImageReference != "registry:8080/openshift/test-image-trigger:outputtag" {
|
|
| 251 |
+ t.Fatalf("Expected build with output image %s, got %s", "registry:8080/openshift/test-image-trigger:outputtag", newBuild.Parameters.Output.DockerImageReference)
|
|
| 252 |
+ } |
|
| 253 |
+ if newBuild.Labels["testlabel"] != "testvalue" {
|
|
| 254 |
+ t.Fatalf("Expected build with label %s=%s from build config got %s=%s", "testlabel", "testvalue", "testlabel", newBuild.Labels["testlabel"])
|
|
| 255 |
+ } |
|
| 256 |
+ |
|
| 257 |
+ <-watch2.ResultChan() |
|
| 139 | 258 |
updatedConfig, err = openshift.Client.BuildConfigs(testutil.Namespace()).Get(config.Name) |
| 140 | 259 |
if err != nil {
|
| 141 | 260 |
t.Fatalf("Couldn't get BuildConfig: %v", err)
|
| ... | ... |
@@ -187,3 +299,48 @@ func imageChangeBuildConfig() *buildapi.BuildConfig {
|
| 187 | 187 |
} |
| 188 | 188 |
return buildcfg |
| 189 | 189 |
} |
| 190 |
+ |
|
| 191 |
+func imageChangeBuildConfigFromRef() *buildapi.BuildConfig {
|
|
| 192 |
+ buildcfg := &buildapi.BuildConfig{
|
|
| 193 |
+ ObjectMeta: kapi.ObjectMeta{
|
|
| 194 |
+ Name: "test-build-cfg", |
|
| 195 |
+ Labels: map[string]string{"testlabel": "testvalue"},
|
|
| 196 |
+ }, |
|
| 197 |
+ Parameters: buildapi.BuildParameters{
|
|
| 198 |
+ Source: buildapi.BuildSource{
|
|
| 199 |
+ Type: "Git", |
|
| 200 |
+ Git: &buildapi.GitBuildSource{
|
|
| 201 |
+ URI: "git://github.com/openshift/ruby-hello-world.git", |
|
| 202 |
+ }, |
|
| 203 |
+ ContextDir: "contextimage", |
|
| 204 |
+ }, |
|
| 205 |
+ Strategy: buildapi.BuildStrategy{
|
|
| 206 |
+ Type: buildapi.STIBuildStrategyType, |
|
| 207 |
+ STIStrategy: &buildapi.STIBuildStrategy{
|
|
| 208 |
+ From: &kapi.ObjectReference{
|
|
| 209 |
+ Name: "test-image-trigger-repo", |
|
| 210 |
+ }, |
|
| 211 |
+ }, |
|
| 212 |
+ }, |
|
| 213 |
+ Output: buildapi.BuildOutput{
|
|
| 214 |
+ To: &kapi.ObjectReference{
|
|
| 215 |
+ Name: "test-image-trigger-repo", |
|
| 216 |
+ }, |
|
| 217 |
+ Tag: "outputtag", |
|
| 218 |
+ }, |
|
| 219 |
+ }, |
|
| 220 |
+ Triggers: []buildapi.BuildTriggerPolicy{
|
|
| 221 |
+ {
|
|
| 222 |
+ Type: buildapi.ImageChangeBuildTriggerType, |
|
| 223 |
+ ImageChange: &buildapi.ImageChangeTrigger{
|
|
| 224 |
+ Image: "registry:8080/openshift/test-image-trigger", |
|
| 225 |
+ From: kapi.ObjectReference{
|
|
| 226 |
+ Name: "test-image-trigger-repo", |
|
| 227 |
+ }, |
|
| 228 |
+ Tag: "latest", |
|
| 229 |
+ }, |
|
| 230 |
+ }, |
|
| 231 |
+ }, |
|
| 232 |
+ } |
|
| 233 |
+ return buildcfg |
|
| 234 |
+} |
| ... | ... |
@@ -92,6 +92,48 @@ func TestWebhookGithubPushWithImageTag(t *testing.T) {
|
| 92 | 92 |
} |
| 93 | 93 |
} |
| 94 | 94 |
|
| 95 |
+func TestWebhookGithubPushWithImageTagRef(t *testing.T) {
|
|
| 96 |
+ testutil.DeleteAllEtcdKeys() |
|
| 97 |
+ openshift := NewTestBuildOpenshift(t) |
|
| 98 |
+ defer openshift.Close() |
|
| 99 |
+ |
|
| 100 |
+ // create imagerepo |
|
| 101 |
+ imageRepo := &imageapi.ImageRepository{
|
|
| 102 |
+ ObjectMeta: kapi.ObjectMeta{Name: "imageRepo"},
|
|
| 103 |
+ Tags: map[string]string{"validTag": "success"},
|
|
| 104 |
+ } |
|
| 105 |
+ if _, err := openshift.Client.ImageRepositories(testutil.Namespace()).Create(imageRepo); err != nil {
|
|
| 106 |
+ t.Fatalf("Unexpected error: %v", err)
|
|
| 107 |
+ } |
|
| 108 |
+ |
|
| 109 |
+ // create buildconfig |
|
| 110 |
+ buildConfig := mockBuildConfigRefParms("originalImage", "imageRepo", "validTag")
|
|
| 111 |
+ |
|
| 112 |
+ if _, err := openshift.Client.BuildConfigs(testutil.Namespace()).Create(buildConfig); err != nil {
|
|
| 113 |
+ t.Fatalf("Unexpected error: %v", err)
|
|
| 114 |
+ } |
|
| 115 |
+ |
|
| 116 |
+ watch, err := openshift.Client.Builds(testutil.Namespace()).Watch(labels.Everything(), fields.Everything(), "0") |
|
| 117 |
+ if err != nil {
|
|
| 118 |
+ t.Fatalf("Couldn't subscribe to builds: %v", err)
|
|
| 119 |
+ } |
|
| 120 |
+ defer watch.Stop() |
|
| 121 |
+ |
|
| 122 |
+ // trigger build event sending push notification |
|
| 123 |
+ postFile("push", "pushevent.json", openshift.server.URL+openshift.whPrefix+"pushbuild/secret101/github?namespace="+testutil.Namespace(), http.StatusOK, t)
|
|
| 124 |
+ |
|
| 125 |
+ event := <-watch.ResultChan() |
|
| 126 |
+ actual := event.Object.(*buildapi.Build) |
|
| 127 |
+ |
|
| 128 |
+ if actual.Status != buildapi.BuildStatusNew {
|
|
| 129 |
+ t.Errorf("Expected %s, got %s", buildapi.BuildStatusNew, actual.Status)
|
|
| 130 |
+ } |
|
| 131 |
+ |
|
| 132 |
+ if actual.Parameters.Strategy.STIStrategy.Image != "registry:3000/integration/imageRepo:success" {
|
|
| 133 |
+ t.Errorf("Expected %s, got %s", "registry:3000/integration-test/imageRepo:success", actual.Parameters.Strategy.STIStrategy.Image)
|
|
| 134 |
+ } |
|
| 135 |
+} |
|
| 136 |
+ |
|
| 95 | 137 |
func TestWebhookGithubPushWithImageTagUnmatched(t *testing.T) {
|
| 96 | 138 |
testutil.DeleteAllEtcdKeys() |
| 97 | 139 |
openshift := NewTestBuildOpenshift(t) |
| ... | ... |
@@ -272,3 +314,50 @@ func mockBuildConfigParms(imageName, imageRepo, imageTag string) *buildapi.Build |
| 272 | 272 |
}, |
| 273 | 273 |
} |
| 274 | 274 |
} |
| 275 |
+ |
|
| 276 |
+func mockBuildConfigRefParms(imageName, imageRepo, imageTag string) *buildapi.BuildConfig {
|
|
| 277 |
+ return &buildapi.BuildConfig{
|
|
| 278 |
+ ObjectMeta: kapi.ObjectMeta{
|
|
| 279 |
+ Name: "pushbuild", |
|
| 280 |
+ }, |
|
| 281 |
+ Triggers: []buildapi.BuildTriggerPolicy{
|
|
| 282 |
+ {
|
|
| 283 |
+ Type: buildapi.GithubWebHookBuildTriggerType, |
|
| 284 |
+ GithubWebHook: &buildapi.WebHookTrigger{
|
|
| 285 |
+ Secret: "secret101", |
|
| 286 |
+ }, |
|
| 287 |
+ }, |
|
| 288 |
+ {
|
|
| 289 |
+ Type: buildapi.ImageChangeBuildTriggerType, |
|
| 290 |
+ ImageChange: &buildapi.ImageChangeTrigger{
|
|
| 291 |
+ Image: imageName, |
|
| 292 |
+ From: kapi.ObjectReference{
|
|
| 293 |
+ Name: imageRepo, |
|
| 294 |
+ }, |
|
| 295 |
+ Tag: imageTag, |
|
| 296 |
+ }, |
|
| 297 |
+ }, |
|
| 298 |
+ }, |
|
| 299 |
+ Parameters: buildapi.BuildParameters{
|
|
| 300 |
+ Source: buildapi.BuildSource{
|
|
| 301 |
+ Type: buildapi.BuildSourceGit, |
|
| 302 |
+ Git: &buildapi.GitBuildSource{
|
|
| 303 |
+ URI: "http://my.docker/build", |
|
| 304 |
+ }, |
|
| 305 |
+ ContextDir: "context", |
|
| 306 |
+ }, |
|
| 307 |
+ Strategy: buildapi.BuildStrategy{
|
|
| 308 |
+ Type: buildapi.STIBuildStrategyType, |
|
| 309 |
+ STIStrategy: &buildapi.STIBuildStrategy{
|
|
| 310 |
+ From: &kapi.ObjectReference{
|
|
| 311 |
+ Name: imageRepo, |
|
| 312 |
+ }, |
|
| 313 |
+ Tag: imageTag, |
|
| 314 |
+ }, |
|
| 315 |
+ }, |
|
| 316 |
+ Output: buildapi.BuildOutput{
|
|
| 317 |
+ DockerImageReference: "namespace/builtimage", |
|
| 318 |
+ }, |
|
| 319 |
+ }, |
|
| 320 |
+ } |
|
| 321 |
+} |