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

fix(cli): Improve CLI / operator versions compatibility check #1944

Merged
merged 3 commits into from
Jan 25, 2021
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
4 changes: 3 additions & 1 deletion pkg/cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,14 @@ import (
"github.com/apache/camel-k/pkg/util/watch"
)

const installCommand = "install"

func newCmdInstall(rootCmdOptions *RootCmdOptions) (*cobra.Command, *installCmdOptions) {
options := installCmdOptions{
RootCmdOptions: rootCmdOptions,
}
cmd := cobra.Command{
Use: "install",
Use: installCommand,
Short: "Install Camel K on a Kubernetes cluster",
Long: `Install Camel K on a Kubernetes or OpenShift cluster.`,
PreRunE: options.decode,
Expand Down
31 changes: 22 additions & 9 deletions pkg/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"

k8serrors "k8s.io/apimachinery/pkg/api/errors"

"github.com/apache/camel-k/pkg/client"
camelv1 "github.com/apache/camel-k/pkg/client/camel/clientset/versioned/typed/camel/v1"
"github.com/apache/camel-k/pkg/util/defaults"
Expand Down Expand Up @@ -73,7 +75,6 @@ func NewKamelCommand(ctx context.Context) (*cobra.Command, error) {
}

func kamelPreAddCommandInit(options *RootCmdOptions) *cobra.Command {

var cmd = cobra.Command{
BashCompletionFunction: bashCompletionFunction,
PersistentPreRunE: options.preRun,
Expand Down Expand Up @@ -171,12 +172,12 @@ func addHelpSubCommands(cmd *cobra.Command, options *RootCmdOptions) error {

func (command *RootCmdOptions) preRun(cmd *cobra.Command, _ []string) error {
if !isOfflineCommand(cmd) {
client, err := command.GetCmdClient()
c, err := command.GetCmdClient()
if err != nil {
return errors.Wrap(err, "cannot get command client")
}
if command.Namespace == "" {
current, err := client.GetCurrentNamespace(command.KubeConfig)
current, err := c.GetCurrentNamespace(command.KubeConfig)
if err != nil {
return errors.Wrap(err, "cannot get current namespace")
}
Expand All @@ -185,19 +186,31 @@ func (command *RootCmdOptions) preRun(cmd *cobra.Command, _ []string) error {
return err
}
}
checkAndShowCompatibilityWarning(command.Context, client, command.Namespace)
// Check that the Kamel CLI matches that of the operator.
// The check relies on the version reported in the IntegrationPlatform status,
// which requires the operator is running and the IntegrationPlatform resource
// reconciled. Hence the compatibility check is skipped for the install command.
// Furthermore, there can be any incompatibilities, as the install command deploys
// the operator version it's compatible with.
if cmd.Use != installCommand {
checkAndShowCompatibilityWarning(command.Context, c, command.Namespace)
}
}

return nil
}

func checkAndShowCompatibilityWarning(ctx context.Context, cli client.Client, namespace string) {
operatorVersion, err := operatorVersion(ctx, cli, namespace)
func checkAndShowCompatibilityWarning(ctx context.Context, c client.Client, namespace string) {
operatorVersion, err := operatorVersion(ctx, c, namespace)
if err != nil {
fmt.Printf("No Integration Platform available in %s namespace\n", namespace)
if k8serrors.IsNotFound(err) {
fmt.Printf("No IntegrationPlatform resource in %s namespace\n", namespace)
} else {
fmt.Printf("Unable to retrieve the operator version: %s", err.Error())
}
} else {
if !compatibleVersions(operatorVersion, defaults.Version) {
fmt.Printf("Warning: you're using Camel K %s client against a %s cluster operator\n\n", defaults.Version, operatorVersion)
if operatorVersion != "" && !compatibleVersions(operatorVersion, defaults.Version) {
fmt.Printf("You're using Camel K %s client with a %s cluster operator, it's recommended to use the same version to improve compatibility.\n\n", defaults.Version, operatorVersion)
}
}
}
Expand Down
32 changes: 19 additions & 13 deletions pkg/cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ import (
"fmt"

"github.com/Masterminds/semver"
"github.com/spf13/cobra"

k8sclient "sigs.k8s.io/controller-runtime/pkg/client"

v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
"github.com/apache/camel-k/pkg/client"
"github.com/apache/camel-k/pkg/util/defaults"
"github.com/spf13/cobra"
k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
)

// VersionVariant may be overridden at build time
Expand Down Expand Up @@ -65,13 +67,13 @@ func (o *versionCmdOptions) preRunE(cmd *cobra.Command, args []string) error {
return o.RootCmdOptions.preRun(cmd, args)
}

func (o *versionCmdOptions) run(cmd *cobra.Command, _ []string) error {
func (o *versionCmdOptions) run(_ *cobra.Command, _ []string) error {
if o.Operator {
client, err := o.GetCmdClient()
c, err := o.GetCmdClient()
if err != nil {
return err
}
displayOperatorVersion(o.Context, client, o.Namespace)
displayOperatorVersion(o.Context, c, o.Namespace)
} else {
displayClientVersion()
}
Expand All @@ -88,10 +90,14 @@ func displayClientVersion() {

func displayOperatorVersion(ctx context.Context, c client.Client, namespace string) {
operatorVersion, err := operatorVersion(ctx, c, namespace)
if err == nil {
fmt.Printf("Camel K Operator %s\n", operatorVersion)
if err != nil {
fmt.Printf("Unable to retrieve operator version: %s\n", err)
} else {
fmt.Printf("Error while looking for camel-k operator in namespace %s (%s)\n", namespace, err)
if operatorVersion == "" {
fmt.Printf("Unable to retrieve operator version: The IntegrationPlatform resource hasn't been reconciled yet!")
} else {
fmt.Printf("Camel K Operator %s\n", operatorVersion)
}
}
}

Expand All @@ -110,16 +116,16 @@ func operatorVersion(ctx context.Context, c client.Client, namespace string) (st
}

func compatibleVersions(aVersion, bVersion string) bool {
v1, err := semver.NewVersion(aVersion)
a, err := semver.NewVersion(aVersion)
if err != nil {
fmt.Printf("Could not parse %s (error: %s)\n", v1, err)
fmt.Printf("Could not parse %s (error: %s)\n", a, err)
return false
}
v2, err := semver.NewVersion(bVersion)
b, err := semver.NewVersion(bVersion)
if err != nil {
fmt.Printf("Could not parse %s (error: %s)\n", v2, err)
fmt.Printf("Could not parse %s (error: %s)\n", b, err)
return false
}
// We consider compatible when major and minor are equals
return v1.Major() == v2.Major() && v1.Minor() == v2.Minor()
return a.Major() == b.Major() && a.Minor() == b.Minor()
}