From 880750ebd861dbe410346edbdd701c201557aafa Mon Sep 17 00:00:00 2001 From: Clayton Coleman Date: Wed, 3 Feb 2016 12:55:22 -0500 Subject: [PATCH] Allow new-app to create test deployments Improve deployment config get and describe, add test cases around the flows. --- contrib/completions/bash/oc | 1 + contrib/completions/bash/openshift | 1 + pkg/cmd/cli/cmd/newapp.go | 1 + pkg/cmd/cli/describe/printer.go | 44 +++++++++++++++++-- pkg/cmd/cli/describe/projectstatus_test.go | 9 ++-- pkg/generate/app/app.go | 2 + pkg/generate/app/cmd/describe.go | 14 ++++-- pkg/generate/app/cmd/newapp.go | 6 ++- pkg/generate/app/pipeline.go | 3 +- test/cmd/newapp.sh | 3 ++ .../new-project-deployed-app.yaml | 1 + 11 files changed, 72 insertions(+), 13 deletions(-) diff --git a/contrib/completions/bash/oc b/contrib/completions/bash/oc index d9254edc0612..b11b4ec99824 100644 --- a/contrib/completions/bash/oc +++ b/contrib/completions/bash/oc @@ -512,6 +512,7 @@ _oc_new-app() flags_completion=() flags+=("--allow-missing-images") + flags+=("--as-test") flags+=("--code=") flags+=("--context-dir=") flags+=("--docker-image=") diff --git a/contrib/completions/bash/openshift b/contrib/completions/bash/openshift index 36e5d8c130aa..5aeaa67ba08e 100644 --- a/contrib/completions/bash/openshift +++ b/contrib/completions/bash/openshift @@ -5646,6 +5646,7 @@ _openshift_cli_new-app() flags_completion=() flags+=("--allow-missing-images") + flags+=("--as-test") flags+=("--code=") flags+=("--context-dir=") flags+=("--docker-image=") diff --git a/pkg/cmd/cli/cmd/newapp.go b/pkg/cmd/cli/cmd/newapp.go index 5485f099bf10..24c7c15bb0e8 100644 --- a/pkg/cmd/cli/cmd/newapp.go +++ b/pkg/cmd/cli/cmd/newapp.go @@ -142,6 +142,7 @@ func NewCmdNewApplication(fullName string, f *clientcmd.Factory, out io.Writer) }, } + cmd.Flags().BoolVar(&config.AsTestDeployment, "as-test", config.AsTestDeployment, "If true create this application as a test deployment, which validates that the deployment succeeds and then scales down.") cmd.Flags().StringSliceVar(&config.SourceRepositories, "code", config.SourceRepositories, "Source code to use to build this application.") cmd.Flags().StringVar(&config.ContextDir, "context-dir", "", "Context directory to be used for the build.") cmd.Flags().StringSliceVarP(&config.ImageStreams, "image", "", config.ImageStreams, "Name of an image stream to use in the app. (deprecated)") diff --git a/pkg/cmd/cli/describe/printer.go b/pkg/cmd/cli/describe/printer.go index 2aeb7b432d14..e9a78184c075 100644 --- a/pkg/cmd/cli/describe/printer.go +++ b/pkg/cmd/cli/describe/printer.go @@ -36,7 +36,7 @@ var ( projectColumns = []string{"NAME", "DISPLAY NAME", "STATUS"} routeColumns = []string{"NAME", "HOST/PORT", "PATH", "SERVICE", "LABELS", "INSECURE POLICY", "TLS TERMINATION"} deploymentColumns = []string{"NAME", "STATUS", "CAUSE"} - deploymentConfigColumns = []string{"NAME", "TRIGGERS", "LATEST"} + deploymentConfigColumns = []string{"NAME", "REVISION", "REPLICAS", "TRIGGERED BY"} templateColumns = []string{"NAME", "DESCRIPTION", "PARAMETERS", "OBJECTS"} policyColumns = []string{"NAME", "ROLES", "LAST MODIFIED"} policyBindingColumns = []string{"NAME", "ROLE BINDINGS", "LAST MODIFIED"} @@ -452,18 +452,54 @@ func printRouteList(routeList *routeapi.RouteList, w io.Writer, opts kctl.PrintO } func printDeploymentConfig(dc *deployapi.DeploymentConfig, w io.Writer, opts kctl.PrintOptions) error { + var scale string + if dc.Spec.Test { + scale = fmt.Sprintf("%d (during test)", dc.Spec.Replicas) + } else { + scale = fmt.Sprintf("%d", dc.Spec.Replicas) + } + + containers := sets.NewString() + if dc.Spec.Template != nil { + for _, c := range dc.Spec.Template.Spec.Containers { + containers.Insert(c.Name) + } + } + //names := containers.List() + referencedContainers := sets.NewString() + triggers := sets.String{} for _, trigger := range dc.Spec.Triggers { - triggers.Insert(string(trigger.Type)) + switch t := trigger.Type; t { + case deployapi.DeploymentTriggerOnConfigChange: + triggers.Insert("config") + case deployapi.DeploymentTriggerOnImageChange: + if p := trigger.ImageChangeParams; p != nil && p.Automatic { + var prefix string + if len(containers) != 1 && !containers.HasAll(p.ContainerNames...) { + sort.Sort(sort.StringSlice(p.ContainerNames)) + prefix = strings.Join(p.ContainerNames, ",") + ":" + } + referencedContainers.Insert(p.ContainerNames...) + switch p.From.Kind { + case "ImageStreamTag": + triggers.Insert(fmt.Sprintf("image(%s%s)", prefix, p.From.Name)) + default: + triggers.Insert(fmt.Sprintf("%s(%s%s)", p.From.Kind, prefix, p.From.Name)) + } + } + default: + triggers.Insert(string(t)) + } } - tStr := strings.Join(triggers.List(), ", ") + trigger := strings.Join(triggers.List(), ",") if opts.WithNamespace { if _, err := fmt.Fprintf(w, "%s\t", dc.Namespace); err != nil { return err } } - _, err := fmt.Fprintf(w, "%s\t%s\t%v\n", dc.Name, tStr, dc.Status.LatestVersion) + _, err := fmt.Fprintf(w, "%s\t%v\t%s\t%s\n", dc.Name, dc.Status.LatestVersion, scale, trigger) return err } diff --git a/pkg/cmd/cli/describe/projectstatus_test.go b/pkg/cmd/cli/describe/projectstatus_test.go index 46eae461c038..1430c32eca1c 100644 --- a/pkg/cmd/cli/describe/projectstatus_test.go +++ b/pkg/cmd/cli/describe/projectstatus_test.go @@ -247,13 +247,16 @@ func TestProjectStatus(t *testing.T) { "svc/database - 172.30.17.240:5434 -> 3306", "exposed by route/frontend on pod port 8080", "svc/frontend - 172.30.17.154:5432 -> 8080", - "database deploys", + "database test deploys", "frontend deploys", "with docker.io/centos/ruby-22-centos7:latest", + "#3 deployment pending on image", "#2 deployment failed less than a second ago: unable to contact server - 0/1 pods", - "#2 deployment running for 7 seconds - 2/1 pods", - "#1 deployed 8 seconds ago", "#1 deployed less than a second ago", + "#2 test deployment running for 7 seconds - 2/1 pods", + "#1 test deployed 8 seconds ago", + "* bc/ruby-sample-build is pushing to istag/origin-ruby-sample:latest that is using is/origin-ruby-sample, but that image stream does not exist.", + "* The image trigger for dc/frontend will have no effect because is/origin-ruby-sample does not exist", "View details with 'oc describe /' or list everything with 'oc get all'.", }, Time: mustParseTime("2015-04-07T04:12:25Z"), diff --git a/pkg/generate/app/app.go b/pkg/generate/app/app.go index bd6313c1b815..4dc9b45ca2a1 100644 --- a/pkg/generate/app/app.go +++ b/pkg/generate/app/app.go @@ -271,6 +271,7 @@ type DeploymentConfigRef struct { Images []*ImageRef Env Environment Labels map[string]string + AsTest bool } // DeploymentConfig creates a deploymentConfig resource from the deployment configuration reference @@ -337,6 +338,7 @@ func (r *DeploymentConfigRef) DeploymentConfig() (*deployapi.DeploymentConfig, e }, Spec: deployapi.DeploymentConfigSpec{ Replicas: 1, + Test: r.AsTest, Selector: selector, Template: &kapi.PodTemplateSpec{ ObjectMeta: kapi.ObjectMeta{ diff --git a/pkg/generate/app/cmd/describe.go b/pkg/generate/app/cmd/describe.go index 2d40e0e6d2ed..ba12be1c2391 100644 --- a/pkg/generate/app/cmd/describe.go +++ b/pkg/generate/app/cmd/describe.go @@ -172,10 +172,18 @@ func describeBuildPipelineWithImage(out io.Writer, ref app.ComponentReference, p } } if pipeline.Deployment != nil { - if len(pipeline.Deployment.Images) > 1 { - fmt.Fprintf(out, " * This image will be deployed as part of deployment config %q\n", pipeline.Deployment.Name) + if pipeline.Deployment.AsTest { + if len(pipeline.Deployment.Images) > 1 { + fmt.Fprintf(out, " * This image will be test deployed as part of deployment config %q\n", pipeline.Deployment.Name) + } else { + fmt.Fprintf(out, " * This image will be test deployed in deployment config %q\n", pipeline.Deployment.Name) + } } else { - fmt.Fprintf(out, " * This image will be deployed in deployment config %q\n", pipeline.Deployment.Name) + if len(pipeline.Deployment.Images) > 1 { + fmt.Fprintf(out, " * This image will be deployed as part of deployment config %q\n", pipeline.Deployment.Name) + } else { + fmt.Fprintf(out, " * This image will be deployed in deployment config %q\n", pipeline.Deployment.Name) + } } } if match != nil && match.Image != nil { diff --git a/pkg/generate/app/cmd/newapp.go b/pkg/generate/app/cmd/newapp.go index 1b61bf0d2744..56705cd157a6 100644 --- a/pkg/generate/app/cmd/newapp.go +++ b/pkg/generate/app/cmd/newapp.go @@ -73,7 +73,9 @@ type AppConfig struct { ExpectToBuild bool BinaryBuild bool AllowMissingImages bool - Deploy bool + + Deploy bool + AsTestDeployment bool SourceImage string SourceImagePath string @@ -681,7 +683,7 @@ func (c *AppConfig) buildPipelines(components app.ComponentReferences, environme } } if c.Deploy { - if err := pipeline.NeedsDeployment(environment, c.Labels); err != nil { + if err := pipeline.NeedsDeployment(environment, c.Labels, c.AsTestDeployment); err != nil { return nil, fmt.Errorf("can't set up a deployment for %q: %v", refInput, err) } } diff --git a/pkg/generate/app/pipeline.go b/pkg/generate/app/pipeline.go index 32dd28caae58..71f1b04359c1 100644 --- a/pkg/generate/app/pipeline.go +++ b/pkg/generate/app/pipeline.go @@ -180,7 +180,7 @@ type Pipeline struct { } // NeedsDeployment sets the pipeline for deployment. -func (p *Pipeline) NeedsDeployment(env Environment, labels map[string]string) error { +func (p *Pipeline) NeedsDeployment(env Environment, labels map[string]string, asTest bool) error { if p.Deployment != nil { return nil } @@ -191,6 +191,7 @@ func (p *Pipeline) NeedsDeployment(env Environment, labels map[string]string) er }, Env: env, Labels: labels, + AsTest: asTest, } return nil } diff --git a/test/cmd/newapp.sh b/test/cmd/newapp.sh index b3918aa8764c..4f83bb57da78 100755 --- a/test/cmd/newapp.sh +++ b/test/cmd/newapp.sh @@ -34,6 +34,9 @@ os::cmd::expect_success_and_not_text 'oc new-app mysql --dry-run' "runs as the ' # trigger and output should say 5.6 os::cmd::expect_success_and_text 'oc new-app mysql -o yaml' 'mysql:5.6' os::cmd::expect_success_and_text 'oc new-app mysql --dry-run' 'tag "5.6" for "mysql"' +# test deployments are created with the boolean flag and printed in the UI +os::cmd::expect_success_and_text 'oc new-app mysql --dry-run --as-test' 'This image will be test deployed' +os::cmd::expect_success_and_text 'oc new-app mysql -o yaml --as-test' 'test: true' # docker strategy with repo that has no dockerfile os::cmd::expect_failure_and_text 'oc new-app https://github.com/openshift/nodejs-ex --strategy=docker' 'No Dockerfile was found' diff --git a/test/fixtures/app-scenarios/new-project-deployed-app.yaml b/test/fixtures/app-scenarios/new-project-deployed-app.yaml index 293980f63ce0..4a303384bece 100644 --- a/test/fixtures/app-scenarios/new-project-deployed-app.yaml +++ b/test/fixtures/app-scenarios/new-project-deployed-app.yaml @@ -226,6 +226,7 @@ items: terminationMessagePath: /dev/termination-log dnsPolicy: ClusterFirst restartPolicy: Always + test: true triggers: - type: ConfigChange status: