Skip to content

Commit

Permalink
pkg/cli/admin/upgrade/channel: Add 'oc adm upgrade channel ...'
Browse files Browse the repository at this point in the history
A new subcommand for conveniently managing channels.  Example
workflow, starting in a channel:

  $ oc adm upgrade
  Cluster version is 4.6.0-fc.3

  Upstream: https://api.openshift.com/api/upgrades_info/v1/graph
  Channel: candidate-4.6 (choices: candidate-4.6)
  Updates:

  VERSION    IMAGE
  4.6.0-fc.4 quay.io/openshift-release-dev/ocp-release@sha256:960ec73733150827076cbb5fa2c1f5aaa9a94bfbce1b4897e46432a56ac976c1
  4.6.0-fc.5 quay.io/openshift-release-dev/ocp-release@sha256:5883d0db15939484bd477147e6949c53fbc6f551ec20a0f1106b8a3acfb86ef8

Trying to change to the same channel is a no-op:

  $ oc adm upgrade channel candidate-4.6
  info: Cluster is already in candidate-4.6

Trying to change to an unrecognized channel gets a warning:

  $ oc adm upgrade channel does-not-exist
  error: the requested channel "does-not-exist" is not one of the available channels (candidate-4.6), you must pass --allow-explicit-channel to continue
  $ oc adm upgrade channel --allow-explicit-channel does-not-exist
  warning: The requested channel "does-not-exist" is not one of the available channels (candidate-4.6).  You have used --allow-explicit-channel to proceed anyway.
  $ oc adm upgrade
  Cluster version is 4.6.0-fc.3

  Channel: does-not-exist
  warning: Cannot display available updates:
    Reason: VersionNotFound
    Message: Unable to retrieve available updates: currently reconciling cluster version 4.6.0-fc.3 not found in the "does-not-exist" channel

When we have no known channels, changing requires no override:

  $ oc adm upgrade channel does-not-exist-either
  warning: No channels known to be compatible with the current version "4.6.0-fc.3"; unable to validate "does-not-exist-either".
  $ oc adm upgrade channel candidate-4.6
  warning: No channels known to be compatible with the current version "4.6.0-fc.3"; unable to validate "candidate-4.6".

Clearing a known channel needs an explicit override:

  $ oc adm upgrade channel
  error: the requested channel "" is not one of the available channels (candidate-4.6), you must pass --allow-explicit-channel to continue
  $ oc adm upgrade channel --allow-explicit-channel
  warning: Clearing channel "candidate-4.6"; cluster will no longer request available update recommendations.
  $ oc adm upgrade
  Cluster version is 4.6.0-fc.3

  warning: Cannot display available updates:
    Reason: NoChannel
    Message: The update channel has not been configured.

Trying to re-clear the channel is a no-op:

  $ oc adm upgrade channel
  info: Cluster channel is already clear

And you can set any channel from a cleared channel without an
override, because this is another case where we have no idea what the
valid choices are:

  $ oc adm upgrade channel candidate-4.6
  warning: No channels known to be compatible with the current version "4.6.0-fc.3"; unable to validate "candidate-4.6".
  $ oc adm upgrade
  Cluster version is 4.6.0-fc.3

  Upstream: https://api.openshift.com/api/upgrades_info/v1/graph
  Channel: candidate-4.6 (choices: candidate-4.6)
  Updates:

  VERSION    IMAGE
  4.6.0-fc.4 quay.io/openshift-release-dev/ocp-release@sha256:960ec73733150827076cbb5fa2c1f5aaa9a94bfbce1b4897e46432a56ac976c1
  4.6.0-fc.5 quay.io/openshift-release-dev/ocp-release@sha256:5883d0db15939484bd477147e6949c53fbc6f551ec20a0f1106b8a3acfb86ef8

Clearing from an unknown channel does not require an override either:

  $ oc adm upgrade channel --allow-explicit-channel does-not-exist
  warning: The requested channel "does-not-exist" is not one of the available channels (candidate-4.6).  You have used --allow-explicit-channel to proceed anyway.
  $ oc adm upgrade channel
  warning: Clearing channel "does-not-exist"; cluster will no longer request available update recommendations.

Completions updated with:

  $ hack/update-generated-completions.sh
  • Loading branch information
wking committed Feb 8, 2021
1 parent 0be070f commit 7d8908b
Show file tree
Hide file tree
Showing 4 changed files with 254 additions and 0 deletions.
61 changes: 61 additions & 0 deletions contrib/completions/bash/oc
Expand Up @@ -6873,13 +6873,74 @@ _oc_adm_uncordon()
noun_aliases=()
}

_oc_adm_upgrade_channel()
{
last_command="oc_adm_upgrade_channel"

command_aliases=()

commands=()

flags=()
two_word_flags=()
local_nonpersistent_flags=()
flags_with_completion=()
flags_completion=()

flags+=("--allow-explicit-channel")
local_nonpersistent_flags+=("--allow-explicit-channel")
flags+=("--as=")
two_word_flags+=("--as")
flags+=("--as-group=")
two_word_flags+=("--as-group")
flags+=("--cache-dir=")
two_word_flags+=("--cache-dir")
flags+=("--certificate-authority=")
two_word_flags+=("--certificate-authority")
flags+=("--client-certificate=")
two_word_flags+=("--client-certificate")
flags+=("--client-key=")
two_word_flags+=("--client-key")
flags+=("--cluster=")
two_word_flags+=("--cluster")
flags+=("--context=")
two_word_flags+=("--context")
flags+=("--insecure-skip-tls-verify")
flags+=("--kubeconfig=")
two_word_flags+=("--kubeconfig")
flags+=("--match-server-version")
flags+=("--namespace=")
two_word_flags+=("--namespace")
flags_with_completion+=("--namespace")
flags_completion+=("__oc_get_namespaces")
two_word_flags+=("-n")
flags_with_completion+=("-n")
flags_completion+=("__oc_get_namespaces")
flags+=("--request-timeout=")
two_word_flags+=("--request-timeout")
flags+=("--server=")
two_word_flags+=("--server")
two_word_flags+=("-s")
flags+=("--tls-server-name=")
two_word_flags+=("--tls-server-name")
flags+=("--token=")
two_word_flags+=("--token")
flags+=("--user=")
two_word_flags+=("--user")

must_have_one_flag=()
must_have_one_noun=()
noun_aliases=()
}

_oc_adm_upgrade()
{
last_command="oc_adm_upgrade"

command_aliases=()

commands=()
commands+=("channel")

flags=()
two_word_flags=()
Expand Down
61 changes: 61 additions & 0 deletions contrib/completions/zsh/oc
Expand Up @@ -6973,13 +6973,74 @@ _oc_adm_uncordon()
noun_aliases=()
}

_oc_adm_upgrade_channel()
{
last_command="oc_adm_upgrade_channel"

command_aliases=()

commands=()

flags=()
two_word_flags=()
local_nonpersistent_flags=()
flags_with_completion=()
flags_completion=()

flags+=("--allow-explicit-channel")
local_nonpersistent_flags+=("--allow-explicit-channel")
flags+=("--as=")
two_word_flags+=("--as")
flags+=("--as-group=")
two_word_flags+=("--as-group")
flags+=("--cache-dir=")
two_word_flags+=("--cache-dir")
flags+=("--certificate-authority=")
two_word_flags+=("--certificate-authority")
flags+=("--client-certificate=")
two_word_flags+=("--client-certificate")
flags+=("--client-key=")
two_word_flags+=("--client-key")
flags+=("--cluster=")
two_word_flags+=("--cluster")
flags+=("--context=")
two_word_flags+=("--context")
flags+=("--insecure-skip-tls-verify")
flags+=("--kubeconfig=")
two_word_flags+=("--kubeconfig")
flags+=("--match-server-version")
flags+=("--namespace=")
two_word_flags+=("--namespace")
flags_with_completion+=("--namespace")
flags_completion+=("__oc_get_namespaces")
two_word_flags+=("-n")
flags_with_completion+=("-n")
flags_completion+=("__oc_get_namespaces")
flags+=("--request-timeout=")
two_word_flags+=("--request-timeout")
flags+=("--server=")
two_word_flags+=("--server")
two_word_flags+=("-s")
flags+=("--tls-server-name=")
two_word_flags+=("--tls-server-name")
flags+=("--token=")
two_word_flags+=("--token")
flags+=("--user=")
two_word_flags+=("--user")

must_have_one_flag=()
must_have_one_noun=()
noun_aliases=()
}

_oc_adm_upgrade()
{
last_command="oc_adm_upgrade"

command_aliases=()

commands=()
commands+=("channel")

flags=()
two_word_flags=()
Expand Down
127 changes: 127 additions & 0 deletions pkg/cli/admin/upgrade/channel/channel.go
@@ -0,0 +1,127 @@
// Package channel contains a command for setting a cluster's update channel.
package channel

import (
"context"
"fmt"
"strings"

configv1client "github.com/openshift/client-go/config/clientset/versioned"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/cli-runtime/pkg/genericclioptions"
kcmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/util/templates"
)

func NewOptions(streams genericclioptions.IOStreams) *Options {
return &Options{
IOStreams: streams,
}
}

func New(f kcmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
o := NewOptions(streams)
cmd := &cobra.Command{
Use: "channel CHANNEL",
Short: "Set or clear the update channel",
Long: templates.LongDesc(`
Set or clear the update channel.
This command will set or clear the update channel, which impacts the list of updates
recommended for the cluster.
If there is a list of acceptable channels and the desired channel is not in that list,
you must pass --allow-explicit-channel to allow channel change to proceed.
`),
Run: func(cmd *cobra.Command, args []string) {
kcmdutil.CheckErr(o.Complete(f, cmd, args))
kcmdutil.CheckErr(o.Run())
},
}
flags := cmd.Flags()
flags.BoolVar(&o.AllowExplicitChannel, "allow-explicit-channel", o.AllowExplicitChannel, "Change the channel, even if there is a list of acceptable channels and the desired channel is not in that list.")
return cmd
}

type Options struct {
genericclioptions.IOStreams

Channel string

AllowExplicitChannel bool

Client configv1client.Interface
}

func (o *Options) Complete(f kcmdutil.Factory, cmd *cobra.Command, args []string) error {
if len(args) > 1 {
return kcmdutil.UsageErrorf(cmd, "multiple positional arguments given")
} else if len(args) == 1 {
o.Channel = args[0]
}

cfg, err := f.ToRESTConfig()
if err != nil {
return err
}
client, err := configv1client.NewForConfig(cfg)
if err != nil {
return err
}
o.Client = client
return nil
}

func (o *Options) Run() error {
ctx := context.TODO()
cv, err := o.Client.ConfigV1().ClusterVersions().Get(ctx, "version", metav1.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
return fmt.Errorf("no cluster version information available - you must be connected to an OpenShift version 4 server to fetch the current version")
}
return err
}

if o.Channel == cv.Spec.Channel {
if cv.Spec.Channel == "" {
fmt.Fprint(o.Out, "info: Cluster channel is already clear\n")
} else {
fmt.Fprintf(o.Out, "info: Cluster is already in %s\n", cv.Spec.Channel)
}
return nil
}

if len(cv.Status.Desired.Channels) > 0 {
found := false
for _, channel := range cv.Status.Desired.Channels {
if channel == o.Channel {
found = true
break
}
}
if !found {
if !o.AllowExplicitChannel {
return fmt.Errorf("the requested channel %q is not one of the available channels (%s), you must pass --allow-explicit-channel to continue\n", o.Channel, strings.Join(cv.Status.Desired.Channels, ", "))
}
if o.Channel != "" {
fmt.Fprintf(o.ErrOut, "warning: The requested channel %q is not one of the available channels (%s). You have used --allow-explicit-channel to proceed anyway.\n", o.Channel, strings.Join(cv.Status.Desired.Channels, ", "))
}
}
} else if o.Channel != "" {
fmt.Fprintf(o.ErrOut, "warning: No channels known to be compatible with the current version %q; unable to validate %q.\n", cv.Status.Desired.Version, o.Channel)
}

if o.Channel == "" {
fmt.Fprintf(o.ErrOut, "warning: Clearing channel %q; cluster will no longer request available update recommendations.\n", cv.Spec.Channel)
}

cv.Spec.Channel = o.Channel

if _, err = o.Client.ConfigV1().ClusterVersions().Update(ctx, cv, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("unable to set channel: %w", err)
}

return nil
}
5 changes: 5 additions & 0 deletions pkg/cli/admin/upgrade/upgrade.go
Expand Up @@ -22,6 +22,8 @@ import (
configv1 "github.com/openshift/api/config/v1"
configv1client "github.com/openshift/client-go/config/clientset/versioned"
imagereference "github.com/openshift/library-go/pkg/image/reference"

"github.com/openshift/oc/pkg/cli/admin/upgrade/channel"
)

func NewOptions(streams genericclioptions.IOStreams) *Options {
Expand Down Expand Up @@ -83,6 +85,9 @@ func New(f kcmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command
flags.BoolVar(&o.Force, "force", o.Force, "Forcefully upgrade the cluster even when upgrade release image validation fails and the cluster is reporting errors.")
flags.BoolVar(&o.AllowExplicitUpgrade, "allow-explicit-upgrade", o.AllowExplicitUpgrade, "Upgrade even if the upgrade target is not listed in the available versions list.")
flags.BoolVar(&o.AllowUpgradeWithWarnings, "allow-upgrade-with-warnings", o.AllowUpgradeWithWarnings, "Upgrade even if an upgrade is in process or a cluster error is blocking the update.")

cmd.AddCommand(channel.New(f, streams))

return cmd
}

Expand Down

0 comments on commit 7d8908b

Please sign in to comment.