Skip to content

Commit

Permalink
Merge pull request openshift#786 from ironcladlou/rollback-cli
Browse files Browse the repository at this point in the history
Merged by openshift-bot
  • Loading branch information
OpenShift Bot committed Jan 30, 2015
2 parents 2f83137 + 7df83d2 commit c396c22
Show file tree
Hide file tree
Showing 10 changed files with 345 additions and 61 deletions.
12 changes: 12 additions & 0 deletions pkg/client/deploymentconfigs.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type DeploymentConfigInterface interface {
Delete(name string) error
Watch(label, field labels.Selector, resourceVersion string) (watch.Interface, error)
Generate(name string) (*deployapi.DeploymentConfig, error)
Rollback(config *deployapi.DeploymentConfigRollback) (*deployapi.DeploymentConfig, error)
}

// deploymentConfigs implements DeploymentConfigsNamespacer interface
Expand Down Expand Up @@ -94,3 +95,14 @@ func (c *deploymentConfigs) Generate(name string) (result *deployapi.DeploymentC
err = c.r.Get().Namespace(c.ns).Resource("generateDeploymentConfigs").Name(name).Do().Into(result)
return
}

func (c *deploymentConfigs) Rollback(config *deployapi.DeploymentConfigRollback) (result *deployapi.DeploymentConfig, err error) {
result = &deployapi.DeploymentConfig{}
err = c.r.Post().
Namespace(c.ns).
Resource("deploymentConfigRollbacks").
Body(config).
Do().
Into(result)
return
}
5 changes: 5 additions & 0 deletions pkg/client/fake_deploymentconfigs.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,8 @@ func (c *FakeDeploymentConfigs) Generate(name string) (*deployapi.DeploymentConf
c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "generate-deploymentconfig"})
return nil, nil
}

func (c *FakeDeploymentConfigs) Rollback(config *deployapi.DeploymentConfigRollback) (result *deployapi.DeploymentConfig, err error) {
c.Fake.Actions = append(c.Fake.Actions, FakeAction{Action: "rollback"})
return nil, nil
}
2 changes: 2 additions & 0 deletions pkg/cmd/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ func NewCommandCLI(name string) *cobra.Command {
cmds.AddCommand(cmd.NewCmdStartBuild(f, out))
cmds.AddCommand(cmd.NewCmdCancelBuild(f, out))

cmds.AddCommand(cmd.NewCmdRollback(name, "rollback", f, out))

return cmds
}

Expand Down
108 changes: 108 additions & 0 deletions pkg/cmd/cli/cmd/rollback.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package cmd

import (
"fmt"
"io"

"github.com/spf13/cobra"

kubectl "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
kcmd "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd"

describe "github.com/openshift/origin/pkg/cmd/cli/describe"
deployapi "github.com/openshift/origin/pkg/deploy/api"
)

const rollbackLongDesc = `
Revert part of an application back to a previous deployment.
When you run this command your deployment configuration will be updated to match
the provided deployment. By default only the pod and container configuration
will be changed and scaling or trigger settings will be left as-is. Note that
environment variables and volumes are included in rollbacks, so if you've
recently updated security credentials in your environment your previous
deployment may not have the correct values.
If you would like to review the outcome of the rollback, pass '--dry-run' to print
a human-readable representation of the updated deployment configuration instead of
executing the rollback. This is useful if you're not quite sure what the outcome
will be.
Examples:
Perform a rollback:
$ %[1]s %[2]s deployment-1
See what the rollback will look like, but don't perform the rollback:
$ %[1]s %[2]s deployment-1 --dry-run
Perform the rollback manually by piping the JSON of the new config back to %[1]s:
$ %[1]s %[2]s deployment-1 --output=json | %[1]s update deploymentConfigs deployment -f -
`

func NewCmdRollback(parentName string, name string, f *Factory, out io.Writer) *cobra.Command {
rollback := &deployapi.DeploymentConfigRollback{
Spec: deployapi.DeploymentConfigRollbackSpec{
IncludeTemplate: true,
},
}

cmd := &cobra.Command{
Use: fmt.Sprintf("%s <from-deployment>", name),
Short: "Revert part of an application back to a previous deployment.",
Long: fmt.Sprintf(rollbackLongDesc, parentName, name),
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 || len(args[0]) == 0 {
usageError(cmd, "A deployment name is required.")
}

rollback.Spec.From.Name = args[0]

outputFormat := kcmd.GetFlagString(cmd, "output")
outputTemplate := kcmd.GetFlagString(cmd, "template")
dryRun := kcmd.GetFlagBool(cmd, "dry-run")

osClient, _, err := f.Clients(cmd)
checkErr(err)

namespace := getOriginNamespace(cmd)

// Generate the rollback config
newConfig, err := osClient.DeploymentConfigs(namespace).Rollback(rollback)
checkErr(err)

// If dry-run is specified, describe the rollback and exit
if dryRun {
describer := describe.NewDeploymentConfigDescriberForConfig(newConfig)
description, descErr := describer.Describe(newConfig.Namespace, newConfig.Name)
checkErr(descErr)
out.Write([]byte(description))
return
}

// If an output format is specified, display the rollback config JSON and exit
// WITHOUT performing a rollback.
if len(outputFormat) > 0 {
printer, _, perr := kubectl.GetPrinter(outputFormat, outputTemplate)
checkErr(perr)
printer.PrintObj(newConfig, out)
return
}

// Apply the rollback config
_, updateErr := osClient.DeploymentConfigs(namespace).Update(newConfig)
checkErr(updateErr)
},
}

cmd.Flags().BoolVar(&rollback.Spec.IncludeTriggers, "change-triggers", false, "Include the previous deployment's triggers in the rollback")
cmd.Flags().BoolVar(&rollback.Spec.IncludeStrategy, "change-strategy", false, "Include the previous deployment's strategy in the rollback")
cmd.Flags().BoolVar(&rollback.Spec.IncludeReplicationMeta, "change-scaling-settings", false, "Include the previous deployment's replicationController replica count and selector in the rollback")
cmd.Flags().BoolP("dry-run", "d", false, "Instead of performing the rollback, describe what the rollback will look like in human-readable form")
cmd.Flags().StringP("output", "o", "", "Instead of performing the rollback, print the updated deployment configuration in the specified format (json|yaml|template|templatefile)")
cmd.Flags().StringP("template", "t", "", "Template string or path to template file to use when -o=template or -o=templatefile.")

return cmd
}
160 changes: 160 additions & 0 deletions pkg/cmd/cli/describe/deployments.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package describe

import (
"fmt"
"io"
"strconv"
"strings"
"text/tabwriter"

kapi "github.com/GoogleCloudPlatform/kubernetes/pkg/api"

"github.com/openshift/origin/pkg/client"
deployapi "github.com/openshift/origin/pkg/deploy/api"
)

// DeploymentConfigDescriber generates information about a DeploymentConfig
type DeploymentConfigDescriber struct {
client deploymentDescriberClient
}

type deploymentDescriberClient interface {
GetDeploymentConfig(namespace, name string) (*deployapi.DeploymentConfig, error)
}

type genericDeploymentDescriberClient struct {
getDeploymentConfig func(namespace, name string) (*deployapi.DeploymentConfig, error)
}

func (c *genericDeploymentDescriberClient) GetDeploymentConfig(namespace, name string) (*deployapi.DeploymentConfig, error) {
return c.getDeploymentConfig(namespace, name)
}

func NewDeploymentConfigDescriberForConfig(config *deployapi.DeploymentConfig) *DeploymentConfigDescriber {
return &DeploymentConfigDescriber{
client: &genericDeploymentDescriberClient{
getDeploymentConfig: func(namespace, name string) (*deployapi.DeploymentConfig, error) {
return config, nil
},
},
}
}

func NewDeploymentConfigDescriber(client client.Interface) *DeploymentConfigDescriber {
return &DeploymentConfigDescriber{
client: &genericDeploymentDescriberClient{
getDeploymentConfig: func(namespace, name string) (*deployapi.DeploymentConfig, error) {
return client.DeploymentConfigs(namespace).Get(name)
},
},
}
}

func (d *DeploymentConfigDescriber) Describe(namespace, name string) (string, error) {
deploymentConfig, err := d.client.GetDeploymentConfig(namespace, name)
if err != nil {
return "", err
}

return tabbedString(func(out *tabwriter.Writer) error {
formatMeta(out, deploymentConfig.ObjectMeta)

if deploymentConfig.LatestVersion == 0 {
formatString(out, "Latest Version", "Not deployed")
} else {
formatString(out, "Latest Version", strconv.Itoa(deploymentConfig.LatestVersion))
}

printStrategy(deploymentConfig.Template.Strategy, out)
printTriggers(deploymentConfig.Triggers, out)
printReplicationController(deploymentConfig.Template.ControllerTemplate, out)

return nil
})
}

func printStrategy(strategy deployapi.DeploymentStrategy, w io.Writer) {
fmt.Fprintf(w, "Strategy:\t%s\n", strategy.Type)
switch strategy.Type {
case deployapi.DeploymentStrategyTypeRecreate:
case deployapi.DeploymentStrategyTypeCustom:
fmt.Fprintf(w, "\t- Image:\t%s\n", strategy.CustomParams.Image)

if len(strategy.CustomParams.Environment) > 0 {
fmt.Fprintf(w, "\t- Environment:\t%s\n", formatLabels(convertEnv(strategy.CustomParams.Environment)))
}

if len(strategy.CustomParams.Command) > 0 {
fmt.Fprintf(w, "\t- Command:\t%v\n", strings.Join(strategy.CustomParams.Command, " "))
}
}
}

func printTriggers(triggers []deployapi.DeploymentTriggerPolicy, w io.Writer) {
if len(triggers) == 0 {
fmt.Fprint(w, "No triggers.")
return
}

fmt.Fprint(w, "Triggers:\n")
for _, t := range triggers {
fmt.Fprintf(w, "\t- %s\n", t.Type)
switch t.Type {
case deployapi.DeploymentTriggerOnConfigChange:
fmt.Fprintf(w, "\t\t<no options>\n")
case deployapi.DeploymentTriggerOnImageChange:
fmt.Fprintf(w, "\t\tAutomatic:\t%v\n\t\tRepository:\t%s\n\t\tTag:\t%s\n",
t.ImageChangeParams.Automatic,
t.ImageChangeParams.RepositoryName,
t.ImageChangeParams.Tag,
)
default:
fmt.Fprint(w, "unknown\n")
}
}
}

func printReplicationController(spec kapi.ReplicationControllerSpec, w io.Writer) error {
fmt.Fprint(w, "Template:\n")

fmt.Fprintf(w, "\tSelector:\t%s\n\tReplicas:\t%d\n",
formatLabels(spec.Selector),
spec.Replicas)

fmt.Fprintf(w, "\tContainers:\n\t\tNAME\tIMAGE\tENV\n")
for _, container := range spec.Template.Spec.Containers {
fmt.Fprintf(w, "\t\t%s\t%s\t%s\n",
container.Name,
container.Image,
formatLabels(convertEnv(container.Env)))
}
return nil
}

// DeploymentDescriber generates information about a deployment
// DEPRECATED.
type DeploymentDescriber struct {
client.Interface
}

func (d *DeploymentDescriber) Describe(namespace, name string) (string, error) {
c := d.Deployments(namespace)
deployment, err := c.Get(name)
if err != nil {
return "", err
}

return tabbedString(func(out *tabwriter.Writer) error {
formatMeta(out, deployment.ObjectMeta)
formatString(out, "Status", bold(deployment.Status))
formatString(out, "Strategy", deployment.Strategy.Type)
causes := []string{}
if deployment.Details != nil {
for _, c := range deployment.Details.Causes {
causes = append(causes, string(c.Type))
}
}
formatString(out, "Causes", strings.Join(causes, ","))
return nil
})
}
53 changes: 1 addition & 52 deletions pkg/cmd/cli/describe/describer.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func DescriberFor(kind string, c *client.Client, host string) (kctl.Describer, b
case "Deployment":
return &DeploymentDescriber{c}, true
case "DeploymentConfig":
return &DeploymentConfigDescriber{c}, true
return NewDeploymentConfigDescriber(c), true
case "Image":
return &ImageDescriber{c}, true
case "ImageRepository":
Expand Down Expand Up @@ -157,57 +157,6 @@ func (d *BuildConfigDescriber) Describe(namespace, name string) (string, error)
})
}

// DeploymentDescriber generates information about a deployment
type DeploymentDescriber struct {
client.Interface
}

func (d *DeploymentDescriber) Describe(namespace, name string) (string, error) {
c := d.Deployments(namespace)
deployment, err := c.Get(name)
if err != nil {
return "", err
}

return tabbedString(func(out *tabwriter.Writer) error {
formatMeta(out, deployment.ObjectMeta)
formatString(out, "Status", bold(deployment.Status))
formatString(out, "Strategy", deployment.Strategy.Type)
causes := []string{}
if deployment.Details != nil {
for _, c := range deployment.Details.Causes {
causes = append(causes, string(c.Type))
}
}
formatString(out, "Causes", strings.Join(causes, ","))
return nil
})
}

// DeploymentConfigDescriber generates information about a DeploymentConfig
type DeploymentConfigDescriber struct {
client.Interface
}

func (d *DeploymentConfigDescriber) Describe(namespace, name string) (string, error) {
c := d.DeploymentConfigs(namespace)
deploymentConfig, err := c.Get(name)
if err != nil {
return "", err
}

return tabbedString(func(out *tabwriter.Writer) error {
formatMeta(out, deploymentConfig.ObjectMeta)
formatString(out, "Latest Version", deploymentConfig.LatestVersion)
triggers := []string{}
for _, t := range deploymentConfig.Triggers {
triggers = append(triggers, string(t.Type))
}
formatString(out, "Triggers", strings.Join(triggers, ","))
return nil
})
}

// ImageDescriber generates information about a Image
type ImageDescriber struct {
client.Interface
Expand Down
Loading

0 comments on commit c396c22

Please sign in to comment.