Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

oc: enable following deployment logs in deploy #9482

Merged
merged 2 commits into from
Jul 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contrib/completions/bash/oc
Original file line number Diff line number Diff line change
Expand Up @@ -1137,6 +1137,7 @@ _oc_deploy()

flags+=("--cancel")
flags+=("--enable-triggers")
flags+=("--follow")
flags+=("--latest")
flags+=("--retry")
flags+=("--api-version=")
Expand Down
1 change: 1 addition & 0 deletions contrib/completions/bash/openshift
Original file line number Diff line number Diff line change
Expand Up @@ -5306,6 +5306,7 @@ _openshift_cli_deploy()

flags+=("--cancel")
flags+=("--enable-triggers")
flags+=("--follow")
flags+=("--latest")
flags+=("--retry")
flags+=("--api-version=")
Expand Down
1 change: 1 addition & 0 deletions contrib/completions/zsh/oc
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,7 @@ _oc_deploy()

flags+=("--cancel")
flags+=("--enable-triggers")
flags+=("--follow")
flags+=("--latest")
flags+=("--retry")
flags+=("--api-version=")
Expand Down
1 change: 1 addition & 0 deletions contrib/completions/zsh/openshift
Original file line number Diff line number Diff line change
Expand Up @@ -5467,6 +5467,7 @@ _openshift_cli_deploy()

flags+=("--cancel")
flags+=("--enable-triggers")
flags+=("--follow")
flags+=("--latest")
flags+=("--retry")
flags+=("--api-version=")
Expand Down
3 changes: 3 additions & 0 deletions docs/generated/oc_by_example_content.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1250,6 +1250,9 @@ View, start, cancel, or retry a deployment
# Start a new deployment based on the 'database'
oc deploy database --latest

# Start a new deployment and follow its log
oc deploy database --latest --follow

# Retry the latest failed deployment based on 'frontend'
# The deployer pod and any hook pods are deleted for the latest failed deployment
oc deploy frontend --retry
Expand Down
7 changes: 7 additions & 0 deletions docs/man/man1/oc-deploy.1
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ If no options are given, shows information about the latest deployment.
\fB\-\-enable\-triggers\fP=false
Enables all image triggers for the deployment config.

.PP
\fB\-\-follow\fP=false
Follow the logs of a deployment

.PP
\fB\-\-latest\fP=false
Start a new deployment now.
Expand Down Expand Up @@ -146,6 +150,9 @@ If no options are given, shows information about the latest deployment.
# Start a new deployment based on the 'database'
oc deploy database \-\-latest

# Start a new deployment and follow its log
oc deploy database \-\-latest \-\-follow

# Retry the latest failed deployment based on 'frontend'
# The deployer pod and any hook pods are deleted for the latest failed deployment
oc deploy frontend \-\-retry
Expand Down
7 changes: 7 additions & 0 deletions docs/man/man1/openshift-cli-deploy.1
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ If no options are given, shows information about the latest deployment.
\fB\-\-enable\-triggers\fP=false
Enables all image triggers for the deployment config.

.PP
\fB\-\-follow\fP=false
Follow the logs of a deployment

.PP
\fB\-\-latest\fP=false
Start a new deployment now.
Expand Down Expand Up @@ -146,6 +150,9 @@ If no options are given, shows information about the latest deployment.
# Start a new deployment based on the 'database'
openshift cli deploy database \-\-latest

# Start a new deployment and follow its log
openshift cli deploy database \-\-latest \-\-follow

# Retry the latest failed deployment based on 'frontend'
# The deployer pod and any hook pods are deleted for the latest failed deployment
openshift cli deploy frontend \-\-retry
Expand Down
73 changes: 54 additions & 19 deletions pkg/cmd/cli/cmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type DeployOptions struct {
retryDeploy bool
cancelDeploy bool
enableTriggers bool
follow bool
}

const (
Expand Down Expand Up @@ -79,6 +80,9 @@ If no options are given, shows information about the latest deployment.`
# Start a new deployment based on the 'database'
%[1]s deploy database --latest

# Start a new deployment and follow its log
%[1]s deploy database --latest --follow

# Retry the latest failed deployment based on 'frontend'
# The deployer pod and any hook pods are deleted for the latest failed deployment
%[1]s deploy frontend --retry
Expand Down Expand Up @@ -118,6 +122,7 @@ func NewCmdDeploy(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.C
cmd.Flags().BoolVar(&options.retryDeploy, "retry", false, "Retry the latest failed deployment.")
cmd.Flags().BoolVar(&options.cancelDeploy, "cancel", false, "Cancel the in-progress deployment.")
cmd.Flags().BoolVar(&options.enableTriggers, "enable-triggers", false, "Enables all image triggers for the deployment config.")
cmd.Flags().BoolVar(&options.follow, "follow", false, "Follow the logs of a deployment")

return cmd
}
Expand Down Expand Up @@ -161,9 +166,15 @@ func (o DeployOptions) Validate() error {
numOptions++
}
if o.cancelDeploy {
if o.follow {
return errors.New("cannot follow the logs while canceling a deployment")
}
numOptions++
}
if o.enableTriggers {
if o.follow {
return errors.New("cannot follow the logs while enabling triggers for a deployment")
}
numOptions++
}
if numOptions > 1 {
Expand All @@ -189,14 +200,17 @@ func (o DeployOptions) RunDeploy() error {

switch {
case o.deployLatest:
err = o.deploy(config, o.out)
err = o.deploy(config)
case o.retryDeploy:
err = o.retry(config, o.out)
err = o.retry(config)
case o.cancelDeploy:
err = o.cancel(config, o.out)
err = o.cancel(config)
case o.enableTriggers:
err = o.reenableTriggers(config, o.out)
err = o.reenableTriggers(config)
default:
if o.follow {
return o.getLogs(config)
}
describer := describe.NewLatestDeploymentsDescriber(o.osClient, o.kubeClient, -1)
desc, err := describer.Describe(config.Namespace, config.Name)
if err != nil {
Expand All @@ -210,7 +224,7 @@ func (o DeployOptions) RunDeploy() error {

// deploy launches a new deployment unless there's already a deployment
// process in progress for config.
func (o DeployOptions) deploy(config *deployapi.DeploymentConfig, out io.Writer) error {
func (o DeployOptions) deploy(config *deployapi.DeploymentConfig) error {
if config.Spec.Paused {
return fmt.Errorf("cannot deploy a paused deployment config")
}
Expand Down Expand Up @@ -238,15 +252,18 @@ func (o DeployOptions) deploy(config *deployapi.DeploymentConfig, out io.Writer)
if err != nil {
return err
}
fmt.Fprintf(out, "Started deployment #%d\n", dc.Status.LatestVersion)
fmt.Fprintf(out, "Use '%s logs -f dc/%s' to track its progress.\n", o.baseCommandName, dc.Name)
fmt.Fprintf(o.out, "Started deployment #%d\n", dc.Status.LatestVersion)
if o.follow {
return o.getLogs(dc)
}
fmt.Fprintf(o.out, "Use '%s logs -f dc/%s' to track its progress.\n", o.baseCommandName, dc.Name)
return nil
}

// retry resets the status of the latest deployment to New, which will cause
// the deployment to be retried. An error is returned if the deployment is not
// currently in a failed state.
func (o DeployOptions) retry(config *deployapi.DeploymentConfig, out io.Writer) error {
func (o DeployOptions) retry(config *deployapi.DeploymentConfig) error {
if config.Spec.Paused {
return fmt.Errorf("cannot retry a paused deployment config")
}
Expand Down Expand Up @@ -295,14 +312,19 @@ func (o DeployOptions) retry(config *deployapi.DeploymentConfig, out io.Writer)
delete(deployment.Annotations, deployapi.DeploymentStatusReasonAnnotation)
delete(deployment.Annotations, deployapi.DeploymentCancelledAnnotation)
_, err = o.kubeClient.ReplicationControllers(deployment.Namespace).Update(deployment)
if err == nil {
fmt.Fprintf(out, "Retried #%d\n", config.Status.LatestVersion)
if err != nil {
return err
}
return err
fmt.Fprintf(o.out, "Retried #%d\n", config.Status.LatestVersion)
if o.follow {
return o.getLogs(config)
}
fmt.Fprintf(o.out, "Use '%s logs -f dc/%s' to track its progress.\n", o.baseCommandName, config.Name)
return nil
}

// cancel cancels any deployment process in progress for config.
func (o DeployOptions) cancel(config *deployapi.DeploymentConfig, out io.Writer) error {
func (o DeployOptions) cancel(config *deployapi.DeploymentConfig) error {
if config.Spec.Paused {
return fmt.Errorf("cannot cancel a paused deployment config")
}
Expand All @@ -311,7 +333,7 @@ func (o DeployOptions) cancel(config *deployapi.DeploymentConfig, out io.Writer)
return err
}
if len(deployments.Items) == 0 {
fmt.Fprintf(out, "There have been no deployments for %s/%s\n", config.Namespace, config.Name)
fmt.Fprintf(o.out, "There have been no deployments for %s/%s\n", config.Namespace, config.Name)
return nil
}
sort.Sort(deployutil.ByLatestVersionDesc(deployments.Items))
Expand All @@ -332,10 +354,10 @@ func (o DeployOptions) cancel(config *deployapi.DeploymentConfig, out io.Writer)
deployment.Annotations[deployapi.DeploymentStatusReasonAnnotation] = deployapi.DeploymentCancelledByUser
_, err := o.kubeClient.ReplicationControllers(deployment.Namespace).Update(&deployment)
if err == nil {
fmt.Fprintf(out, "Cancelled deployment #%d\n", config.Status.LatestVersion)
fmt.Fprintf(o.out, "Cancelled deployment #%d\n", config.Status.LatestVersion)
anyCancelled = true
} else {
fmt.Fprintf(out, "Couldn't cancel deployment #%d (status: %s): %v\n", deployutil.DeploymentVersionFor(&deployment), status, err)
fmt.Fprintf(o.out, "Couldn't cancel deployment #%d (status: %s): %v\n", deployutil.DeploymentVersionFor(&deployment), status, err)
failedCancellations = append(failedCancellations, strconv.FormatInt(deployutil.DeploymentVersionFor(&deployment), 10))
}
}
Expand All @@ -350,7 +372,7 @@ func (o DeployOptions) cancel(config *deployapi.DeploymentConfig, out io.Writer)
maybeCancelling = " (cancelling)"
}
timeAt := strings.ToLower(units.HumanDuration(time.Now().Sub(latest.CreationTimestamp.Time)))
fmt.Fprintf(out, "No deployments are in progress (latest deployment #%d %s%s %s ago)\n",
fmt.Fprintf(o.out, "No deployments are in progress (latest deployment #%d %s%s %s ago)\n",
deployutil.DeploymentVersionFor(latest),
strings.ToLower(string(deployutil.DeploymentStatusFor(latest))),
maybeCancelling,
Expand All @@ -360,7 +382,7 @@ func (o DeployOptions) cancel(config *deployapi.DeploymentConfig, out io.Writer)
}

// reenableTriggers enables all image triggers and then persists config.
func (o DeployOptions) reenableTriggers(config *deployapi.DeploymentConfig, out io.Writer) error {
func (o DeployOptions) reenableTriggers(config *deployapi.DeploymentConfig) error {
enabled := []string{}
for _, trigger := range config.Spec.Triggers {
if trigger.Type == deployapi.DeploymentTriggerOnImageChange {
Expand All @@ -369,13 +391,26 @@ func (o DeployOptions) reenableTriggers(config *deployapi.DeploymentConfig, out
}
}
if len(enabled) == 0 {
fmt.Fprintln(out, "No image triggers found to enable")
fmt.Fprintln(o.out, "No image triggers found to enable")
return nil
}
_, err := o.osClient.DeploymentConfigs(config.Namespace).Update(config)
if err != nil {
return err
}
fmt.Fprintf(out, "Enabled image triggers: %s\n", strings.Join(enabled, ","))
fmt.Fprintf(o.out, "Enabled image triggers: %s\n", strings.Join(enabled, ","))
return nil
}

func (o DeployOptions) getLogs(config *deployapi.DeploymentConfig) error {
opts := deployapi.DeploymentLogOptions{
Follow: true,
}
readCloser, err := o.osClient.DeploymentLogs(config.Namespace).Get(config.Name, opts).Stream()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this will wait till the logs are available (iow. the deployer pod is started).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently it just wait until the replication controller is created. I will open a separate issue to make it wait for the deployer pod to come up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if err != nil {
return err
}
defer readCloser.Close()
_, err = io.Copy(o.out, readCloser)
return err
}
28 changes: 14 additions & 14 deletions pkg/cmd/cli/cmd/deploy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ func TestCmdDeploy_latestOk(t *testing.T) {
return true, deploymentFor(config, status), nil
})

o := &DeployOptions{osClient: osClient, kubeClient: kubeClient}
err := o.deploy(config, ioutil.Discard)
o := &DeployOptions{osClient: osClient, kubeClient: kubeClient, out: ioutil.Discard}
err := o.deploy(config)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
Expand All @@ -84,9 +84,9 @@ func TestCmdDeploy_latestConcurrentRejection(t *testing.T) {
config := deploytest.OkDeploymentConfig(1)
existingDeployment := deploymentFor(config, status)
kubeClient := ktc.NewSimpleFake(existingDeployment)
o := &DeployOptions{kubeClient: kubeClient}
o := &DeployOptions{kubeClient: kubeClient, out: ioutil.Discard}

err := o.deploy(config, ioutil.Discard)
err := o.deploy(config)
if err == nil {
t.Errorf("expected an error starting deployment with existing status %s", status)
}
Expand All @@ -102,8 +102,8 @@ func TestCmdDeploy_latestLookupError(t *testing.T) {
})

config := deploytest.OkDeploymentConfig(1)
o := &DeployOptions{kubeClient: kubeClient}
err := o.deploy(config, ioutil.Discard)
o := &DeployOptions{kubeClient: kubeClient, out: ioutil.Discard}
err := o.deploy(config)

if err == nil {
t.Fatal("expected an error")
Expand Down Expand Up @@ -150,8 +150,8 @@ func TestCmdDeploy_retryOk(t *testing.T) {
return true, nil, nil
})

o := &DeployOptions{kubeClient: kubeClient}
err := o.retry(config, ioutil.Discard)
o := &DeployOptions{kubeClient: kubeClient, out: ioutil.Discard}
err := o.retry(config)

if err != nil {
t.Fatalf("unexpected error: %v", err)
Expand Down Expand Up @@ -194,8 +194,8 @@ func TestCmdDeploy_retryRejectNonFailed(t *testing.T) {
config := deploytest.OkDeploymentConfig(1)
existingDeployment := deploymentFor(config, status)
kubeClient := ktc.NewSimpleFake(existingDeployment)
o := &DeployOptions{kubeClient: kubeClient}
err := o.retry(config, ioutil.Discard)
o := &DeployOptions{kubeClient: kubeClient, out: ioutil.Discard}
err := o.retry(config)
if err == nil {
t.Errorf("expected an error retrying deployment with status %s", status)
}
Expand Down Expand Up @@ -255,9 +255,9 @@ func TestCmdDeploy_cancelOk(t *testing.T) {
return true, existingDeployments, nil
})

o := &DeployOptions{kubeClient: kubeClient}
o := &DeployOptions{kubeClient: kubeClient, out: ioutil.Discard}

err := o.cancel(config, ioutil.Discard)
err := o.cancel(config)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
Expand Down Expand Up @@ -309,8 +309,8 @@ func TestDeploy_reenableTriggers(t *testing.T) {
config.Spec.Triggers = append(config.Spec.Triggers, mktrigger())
}

o := &DeployOptions{osClient: osClient}
err := o.reenableTriggers(config, ioutil.Discard)
o := &DeployOptions{osClient: osClient, out: ioutil.Discard}
err := o.reenableTriggers(config)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
Expand Down
Loading