Skip to content

Commit

Permalink
Pass kube client on command context in CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
RonFed committed Nov 16, 2024
1 parent 0cb3f5b commit ca41879
Show file tree
Hide file tree
Showing 15 changed files with 73 additions and 66 deletions.
2 changes: 1 addition & 1 deletion cli/cmd/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ var cloudCmd = &cobra.Command{
Short: "Manage odigos cloud",
Long: `Used to interact with odigos managed service.`,
Run: func(cmd *cobra.Command, args []string) {
client := kube.GetCLIClient()
ctx := cmd.Context()
client := kube.KubeClientFromContextOrExit(ctx)

ns, err := resources.GetOdigosNamespace(client, ctx)
if resources.IsErrNoOdigosNamespaceFound(err) {
Expand Down
14 changes: 7 additions & 7 deletions cli/cmd/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ var describeCmd = &cobra.Command{
Short: "Show details on odigos deployment",
Long: `Print detailed description odigos deployment, which can be used to troubleshoot issues`,
Run: func(cmd *cobra.Command, args []string) {

client := kube.GetCLIClient()
ctx := cmd.Context()
client := kube.KubeClientFromContextOrExit(ctx)

odigosNs, err := resources.GetOdigosNamespace(client, ctx)
if err != nil {
Expand Down Expand Up @@ -63,8 +62,9 @@ var describeSourceDeploymentCmd = &cobra.Command{
Aliases: []string{"deploy", "deployments", "deploy.apps", "deployment.apps", "deployments.apps"},
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
client := kube.GetCLIClient()
ctx := cmd.Context()
client := kube.KubeClientFromContextOrExit(ctx)

name := args[0]
ns := cmd.Flag("namespace").Value.String()

Expand All @@ -90,9 +90,9 @@ var describeSourceDaemonSetCmd = &cobra.Command{
Aliases: []string{"ds", "daemonsets", "ds.apps", "daemonset.apps", "daemonsets.apps"},
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
client := kube.GetCLIClient()

ctx := cmd.Context()
client := kube.KubeClientFromContextOrExit(ctx)

name := args[0]
ns := cmd.Flag("namespace").Value.String()

Expand All @@ -118,9 +118,9 @@ var describeSourceStatefulSetCmd = &cobra.Command{
Aliases: []string{"sts", "statefulsets", "sts.apps", "statefulset.apps", "statefulsets.apps"},
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
client := kube.GetCLIClient()

ctx := cmd.Context()
client := kube.KubeClientFromContextOrExit(ctx)

name := args[0]
ns := cmd.Flag("namespace").Value.String()

Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/diagnose.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ var diagnoseCmd = &cobra.Command{
Long: `Diagnose Client Cluster to identify issues and resolve them. This command is useful for troubleshooting and debugging.`,
Run: func(cmd *cobra.Command, args []string) {
ctx := cmd.Context()
client := kube.GetCLIClient()
client := kube.KubeClientFromContextOrExit(ctx)

err := startDiagnose(ctx, client)
if err != nil {
Expand Down
35 changes: 3 additions & 32 deletions cli/cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/version"
"k8s.io/apimachinery/pkg/util/wait"
)

Expand All @@ -46,12 +45,6 @@ var (
imagePrefix string
)

var (
// minK8SVersionForInstallation is the minimum Kubernetes version required for Odigos installation
// this value must be in sync with the one defined in the kubeVersion field in Chart.yaml
minK8SVersionForInstallation = version.MustParse("v1.20.15")
)

type ResourceCreationFunc func(ctx context.Context, cmd *cobra.Command, client *kube.Client, ns string) error

// installCmd represents the install command
Expand All @@ -61,9 +54,8 @@ var installCmd = &cobra.Command{
Long: `Install Odigos in your kubernetes cluster.
This command will install k8s components that will auto-instrument your applications with OpenTelemetry and send traces, metrics and logs to any telemetry backend`,
Run: func(cmd *cobra.Command, args []string) {

client := kube.GetCLIClient()
ctx := cmd.Context()
client := kube.KubeClientFromContextOrExit(ctx)
ns := cmd.Flag("namespace").Value.String()

// Check if Odigos already installed
Expand All @@ -83,36 +75,15 @@ This command will install k8s components that will auto-instrument your applicat

k8sVersion := autodetect.GetK8SVersion()
if k8sVersion != nil {
if k8sVersion.LessThan(minK8SVersionForInstallation) {
fmt.Printf("\033[31mERROR\033[0m Odigos requires Kubernetes version %s or higher but found %s, aborting\n", minK8SVersionForInstallation.String(), k8sVersion.String())
if k8sVersion.LessThan(k8sconsts.MinK8SVersionForInstallation) {
fmt.Printf("\033[31mERROR\033[0m Odigos requires Kubernetes version %s or higher but found %s, aborting\n", k8sconsts.MinK8SVersionForInstallation.String(), k8sVersion.String())
os.Exit(1)
}
fmt.Printf("Detected cluster: Kubernetes version: %s\n", k8sVersion.String())
} else {
fmt.Println("Unknown Kubernetes version detected, proceeding with installation")
}


// kc := cmd.Flag("kubeconfig").Value.String()
// details, err := autodetect.SetK8SClusterDetails(ctx, kc, client)
// if !errors.Is(err, autodetect.ErrCannotDetectClusterKind) {
// autodetect.CurrentClusterDetails.Kind = details.Kind
// fmt.Printf("Detected cluster: Kubernetes kind: %s\n", details.Kind)
// } else {
// fmt.Println("Unknown Kubernetes cluster detected, proceeding with installation")
// }

// if !errors.Is(err, autodetect.ErrCannotDetectK8sVersion) {
// autodetect.CurrentClusterDetails.K8SVersion = details.K8SVersion
// if details.K8SVersion.LessThan(minK8SVersionForInstallation) {
// fmt.Printf("\033[31mERROR\033[0m Odigos requires Kubernetes version %s or higher but found %s, aborting\n", minK8SVersionForInstallation.String(), details.K8SVersion.String())
// os.Exit(1)
// }
// fmt.Printf("Detected cluster: Kubernetes version: %s\n", details.K8SVersion.String())
// } else {
// fmt.Println("Unknown Kubernetes version detected, proceeding with installation")
// }

var odigosProToken string
odigosTier := common.CommunityOdigosTier
if odigosCloudApiKeyFlag != "" {
Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ func restartPodsAfterCloudLogin(ctx context.Context, client *kube.Client, ns str

// both login and update trigger this function.
func updateApiKey(cmd *cobra.Command, args []string) {
client := kube.GetCLIClient()
ctx := cmd.Context()
client := kube.KubeClientFromContextOrExit(ctx)

ns, err := resources.GetOdigosNamespace(client, ctx)
if resources.IsErrNoOdigosNamespaceFound(err) {
Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/logout.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ var logoutCmd = &cobra.Command{
You can run 'odigos ui' to manage your Odigos installation locally.
`,
Run: func(cmd *cobra.Command, args []string) {
client := kube.GetCLIClient()
ctx := cmd.Context()
client := kube.KubeClientFromContextOrExit(ctx)

ns, err := resources.GetOdigosNamespace(client, ctx)
if resources.IsErrNoOdigosNamespaceFound(err) {
Expand Down
6 changes: 3 additions & 3 deletions cli/cmd/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ var profileCmd = &cobra.Command{
Short: "Manage odigos profiles",
Long: `Odigos profiles are used to apply some specific preset configuration to the odigos installation`,
Run: func(cmd *cobra.Command, args []string) {
client := kube.GetCLIClient()
ctx := cmd.Context()
client := kube.KubeClientFromContextOrExit(ctx)

ns, err := resources.GetOdigosNamespace(client, ctx)
if resources.IsErrNoOdigosNamespaceFound(err) {
Expand Down Expand Up @@ -75,8 +75,8 @@ var addProfileCmd = &cobra.Command{
Long: `Add a profile by its name to the current Odigos installation.`,
Args: cobra.ExactArgs(1), // Ensure exactly one argument is passed (the profile name)
Run: func(cmd *cobra.Command, args []string) {
client := kube.GetCLIClient()
ctx := cmd.Context()
client := kube.KubeClientFromContextOrExit(ctx)

ns, err := resources.GetOdigosNamespace(client, ctx)
if resources.IsErrNoOdigosNamespaceFound(err) {
Expand Down Expand Up @@ -158,8 +158,8 @@ var removeProfileCmd = &cobra.Command{
Long: `Remove a profile by its name from the current Odigos installation.`,
Args: cobra.ExactArgs(1), // Ensure exactly one argument is passed (the profile name)
Run: func(cmd *cobra.Command, args []string) {
client := kube.GetCLIClient()
ctx := cmd.Context()
client := kube.KubeClientFromContextOrExit(ctx)

ns, err := resources.GetOdigosNamespace(client, ctx)
if resources.IsErrNoOdigosNamespaceFound(err) {
Expand Down
7 changes: 6 additions & 1 deletion cli/cmd/resources/applyresources.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/odigos-io/odigos/cli/pkg/log"
"github.com/odigos-io/odigos/common"
"github.com/odigos-io/odigos/common/consts"
k8sconsts "github.com/odigos-io/odigos/k8sutils/pkg/consts"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"
)
Expand All @@ -31,9 +32,13 @@ func ApplyResourceManagers(ctx context.Context, client *kube.Client, resourceMan

func DeleteOldOdigosSystemObjects(ctx context.Context, client *kube.Client, ns string, config *common.OdigosConfiguration) error {
resources := kube.GetManagedResources(ns)
k8sVersion := autodetect.GetK8SVersion()
if k8sVersion == nil {
fmt.Printf("Unknown k8s version, assuming oldest supported version: %s\n", k8sconsts.MinK8SVersionForInstallation)
}
for _, resource := range resources {
l := log.Print(fmt.Sprintf("Syncing %s", resource.Resource.Resource))
err := client.DeleteOldOdigosSystemObjects(ctx, resource, config.ConfigVersion, autodetect.GetK8SVersion())
err := client.DeleteOldOdigosSystemObjects(ctx, resource, config.ConfigVersion, k8sVersion)
if err != nil {
l.Error(err)
os.Exit(1)
Expand Down
7 changes: 5 additions & 2 deletions cli/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ Key Features of Odigos:
Get started with Odigos today to effortlessly improve the observability of your Kubernetes services!`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
client := kube.SetCLIClientOrExit(cmd)
autodetect.SetK8SClusterDetails(cmd.Context(), kubeConfig, client)
client := kube.GetCLIClientOrExit(cmd)
ctx := cmd.Context()
autodetect.SetK8SClusterDetails(ctx, kubeConfig, client)
ctx = kube.ContextWithKubeClient(ctx, client)
cmd.SetContext(ctx)
},
}

Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ var uiCmd = &cobra.Command{
Long: `Start the Odigos UI. This command will port-forward the odigos-ui pod to your local machine.`,
Run: func(cmd *cobra.Command, args []string) {
ctx := cmd.Context()
client := kube.GetCLIClient()
client := kube.KubeClientFromContextOrExit(ctx)

ns, err := resources.GetOdigosNamespace(client, ctx)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/uninstall.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ var uninstallCmd = &cobra.Command{
Use: "uninstall",
Short: "Unistall Odigos from your cluster",
Run: func(cmd *cobra.Command, args []string) {
client := kube.GetCLIClient()
ctx := cmd.Context()
client := kube.KubeClientFromContextOrExit(ctx)

ns, err := resources.GetOdigosNamespace(client, ctx)
if err != nil && !resources.IsErrNoOdigosNamespaceFound(err) {
Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ var upgradeCmd = &cobra.Command{
This command will upgrade the Odigos version in the cluster to the version of Odigos CLI
and apply any required migrations and adaptations.`,
Run: func(cmd *cobra.Command, args []string) {
client := kube.GetCLIClient()
ctx := cmd.Context()
client := kube.KubeClientFromContextOrExit(ctx)

ns, err := resources.GetOdigosNamespace(client, ctx)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ func getOdigosVersionInCluster(cmd *cobra.Command) (string, error) {
}

func getOdigosKubeClientAndNamespace(cmd *cobra.Command) (*kube.Client, string, error) {
client := kube.GetCLIClient()
ctx := cmd.Context()
client := kube.KubeClientFromContextOrExit(ctx)

ns, err := resources.GetOdigosNamespace(client, ctx)
if err != nil {
Expand Down
46 changes: 33 additions & 13 deletions cli/pkg/kube/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package kube

import (
"context"
"errors"
"fmt"
"os"
"strconv"
Expand Down Expand Up @@ -44,22 +45,44 @@ type Object interface {
runtime.Object
}

var cliClient *Client
type kubeClientContextKeyType int

func SetCLIClientOrExit(cmd *cobra.Command) *Client {
if cliClient != nil {
return cliClient
const currentClientKey kubeClientContextKeyType = iota

// ContextWithKubeClient returns a copy of parent with kubeClient set as the current client.
func ContextWithKubeClient(parent context.Context, kubeClient *Client) context.Context {
return context.WithValue(parent, currentClientKey, kubeClient)
}

// KubeClientFromContextOrExit returns the current kube client from ctx.
//
// If no client is currently set in ctx the program will exit with an error message.
func KubeClientFromContextOrExit(ctx context.Context) *Client {
if ctx == nil {
PrintClientErrorAndExit(errors.New("context is nil when trying to get kube client"))
return nil
}
if client, ok := ctx.Value(currentClientKey).(*Client); ok {
return client
}
PrintClientErrorAndExit(errors.New("context does not contain kube client"))
return nil
}

// GetCLIClientOrExit returns the current kube client from cmd.Context() if one exists.
// otherwise it creates a new client and returns it.
func GetCLIClientOrExit(cmd *cobra.Command) *Client {
cmdCtx := cmd.Context()
if cmdCtx != nil {
if client, ok := cmdCtx.Value(currentClientKey).(*Client); ok {
return client
}
}
client, err := createClient(cmd)
if err != nil {
PrintClientErrorAndExit(err)
}
cliClient = client
return cliClient
}

func GetCLIClient() *Client {
return cliClient
return client
}

func createClient(cmd *cobra.Command) (*Client, error) {
Expand Down Expand Up @@ -216,9 +239,6 @@ func (c *Client) DeleteOldOdigosSystemObjects(ctx context.Context, resourceAndNa
labelSelector := k8slabels.NewSelector().Add(*systemObject).Add(*notLatestVersion).String()
resource := resourceAndNamespace.Resource
ns := resourceAndNamespace.Namespace
if k8sVersion == nil {
fmt.Printf("DeleteOldOdigosSystemObjects failed to get k8s version, proceeding.. ")
}
// DeleteCollection is only available in k8s 1.23 and above, for older versions we need to list and delete each resource
if k8sVersion != nil && k8sVersion.GreaterThan(version.MustParse("1.23")) {
return c.Dynamic.Resource(resource).Namespace(ns).DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{
Expand Down
8 changes: 8 additions & 0 deletions k8sutils/pkg/consts/consts.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package consts

import "k8s.io/apimachinery/pkg/util/version"

type CollectorRole string

const (
Expand Down Expand Up @@ -49,3 +51,9 @@ func OdigosInjectedEnvVars() []string {
OdigosEnvVarPodName,
}
}

var (
// MinK8SVersionForInstallation is the minimum Kubernetes version required for Odigos installation
// this value must be in sync with the one defined in the kubeVersion field in Chart.yaml
MinK8SVersionForInstallation = version.MustParse("v1.20.15-0")
)

0 comments on commit ca41879

Please sign in to comment.