Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into ic-distros
Browse files Browse the repository at this point in the history
  • Loading branch information
blumamir committed Feb 4, 2025
2 parents 32d30f5 + 6544c9d commit 2b4759b
Show file tree
Hide file tree
Showing 10 changed files with 436 additions and 2 deletions.
2 changes: 2 additions & 0 deletions api/k8sconsts/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ const (
WorkloadNameLabel = "odigos.io/workload-name"
WorkloadNamespaceLabel = "odigos.io/workload-namespace"
WorkloadKindLabel = "odigos.io/workload-kind"

SourceGroupLabelPrefix = "odigos.io/group-"
)
259 changes: 259 additions & 0 deletions cli/cmd/sources.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
package cmd

import (
"fmt"
"os"

"github.com/odigos-io/odigos/api/k8sconsts"
"github.com/odigos-io/odigos/api/odigos/v1alpha1"
cmdcontext "github.com/odigos-io/odigos/cli/pkg/cmd_context"
"github.com/odigos-io/odigos/cli/pkg/confirm"

v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"

"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

var (
sourceFlags *pflag.FlagSet

namespaceFlagName = "namespace"

allNamespacesFlagName = "all-namespaces"
allNamespaceFlag bool

workloadKindFlagName = "workload-kind"
workloadKindFlag string

workloadNameFlagName = "workload-name"
workloadNameFlag string

workloadNamespaceFlagName = "workload-namespace"
workloadNamespaceFlag string

disableInstrumentationFlagName = "disable-instrumentation"
disableInstrumentationFlag bool

sourceGroupFlagName = "group"
sourceGroupFlag string

sourceSetGroupFlagName = "set-group"
sourceSetGroupFlag string

sourceRemoveGroupFlagName = "remove-group"
sourceRemoveGroupFlag string

sourceOtelServiceFlagName = "otel-service"
sourceOtelServiceFlag string
)

var sourcesCmd = &cobra.Command{
Use: "sources [command] [flags]",
Short: "Manage Odigos Sources in a cluster",
Long: "This command can be used to create, delete, or update Sources to configure workload or namespace auto-instrumentation",
Example: `
# Create a Source "foo-source" for deployment "foo" in namespace "default"
odigos sources create foo-source --workload-kind=Deployment --workload-name=foo --workload-namespace=default -n default
# Update all existing Sources in namespace "default" to disable instrumentation
odigos sources update --disable-instrumentation -n default
# Delete all Sources in group "mygroup"
odigos sources delete --group mygroup --all-namespaces
`,
}

var sourceCreateCmd = &cobra.Command{
Use: "create [name] [flags]",
Short: "Create an Odigos Source",
Long: "This command will create the named Source object for the provided workload.",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
ctx := cmd.Context()
client := cmdcontext.KubeClientFromContextOrExit(ctx)
disableInstrumentation := disableInstrumentationFlag
sourceName := args[0]

source := &v1alpha1.Source{
ObjectMeta: v1.ObjectMeta{
Name: sourceName,
Namespace: namespaceFlag,
},
Spec: v1alpha1.SourceSpec{
Workload: k8sconsts.PodWorkload{
Kind: k8sconsts.WorkloadKind(workloadKindFlag),
Name: workloadNameFlag,
Namespace: workloadNamespaceFlag,
},
DisableInstrumentation: disableInstrumentation,
OtelServiceName: sourceOtelServiceFlag,
},
}

if len(sourceGroupFlag) > 0 {
source.Labels = make(map[string]string)
source.Labels[k8sconsts.SourceGroupLabelPrefix+sourceGroupFlag] = "true"
}

_, err := client.OdigosClient.Sources(namespaceFlag).Create(ctx, source, v1.CreateOptions{})
if err != nil {
fmt.Printf("\033[31mERROR\033[0m Cannot create Source: %+v\n", err)
os.Exit(1)
}
fmt.Printf("Created Source %s\n", sourceName)
},
}

var sourceDeleteCmd = &cobra.Command{
Use: "delete [flags]",
Short: "Delete Odigos Sources",
Long: "This command will delete any Source objects that match the provided Workload info.",
Run: func(cmd *cobra.Command, args []string) {
ctx := cmd.Context()
client := cmdcontext.KubeClientFromContextOrExit(ctx)

namespaceText, providedWorkloadFlags, namespaceList, labelSet := parseSourceLabelFlags()

if !cmd.Flag("yes").Changed {
fmt.Printf("About to delete all Sources in %s that match:\n%s", namespaceText, providedWorkloadFlags)
confirmed, err := confirm.Ask("Are you sure?")
if err != nil || !confirmed {
fmt.Println("Aborting delete")
return
}
}

sources, err := client.OdigosClient.Sources(namespaceList).List(ctx, v1.ListOptions{LabelSelector: labelSet.AsSelector().String()})
if err != nil {
fmt.Printf("\033[31mERROR\033[0m Cannot list Sources: %+v\n", err)
os.Exit(1)
}

deletedCount := 0
for _, source := range sources.Items {
err := client.OdigosClient.Sources(source.GetNamespace()).Delete(ctx, source.GetName(), v1.DeleteOptions{})
if err != nil {
fmt.Printf("\033[31mERROR\033[0m Cannot delete Sources %s/%s: %+v\n", source.GetNamespace(), source.GetName(), err)
os.Exit(1)
}
fmt.Printf("Deleted Source %s/%s\n", source.GetNamespace(), source.GetName())
deletedCount++
}
fmt.Printf("Deleted %d Sources\n", deletedCount)
},
}

var sourceUpdateCmd = &cobra.Command{
Use: "update [flags]",
Short: "Update Odigos Sources",
Long: "This command will update any Source objects that match the provided Workload info.",
Run: func(cmd *cobra.Command, args []string) {
ctx := cmd.Context()
client := cmdcontext.KubeClientFromContextOrExit(ctx)

namespaceText, providedWorkloadFlags, namespaceList, labelSet := parseSourceLabelFlags()

if !cmd.Flag("yes").Changed {
fmt.Printf("About to update all Sources in %s that match:\n%s", namespaceText, providedWorkloadFlags)
confirmed, err := confirm.Ask("Are you sure?")
if err != nil || !confirmed {
fmt.Println("Aborting delete")
return
}
}

sources, err := client.OdigosClient.Sources(namespaceList).List(ctx, v1.ListOptions{LabelSelector: labelSet.AsSelector().String()})
if err != nil {
fmt.Printf("\033[31mERROR\033[0m Cannot list Sources: %+v\n", err)
os.Exit(1)
}

for _, source := range sources.Items {
source.Spec.DisableInstrumentation = disableInstrumentationFlag
if len(sourceRemoveGroupFlag) > 0 {
for label, value := range source.Labels {
if label == k8sconsts.SourceGroupLabelPrefix+sourceRemoveGroupFlag && value == "true" {
delete(source.Labels, k8sconsts.SourceGroupLabelPrefix+sourceRemoveGroupFlag)
}
}
}
if len(sourceSetGroupFlag) > 0 {
if source.Labels == nil {
source.Labels = make(map[string]string)
}
source.Labels[k8sconsts.SourceGroupLabelPrefix+sourceSetGroupFlag] = "true"
}

if len(sourceOtelServiceFlag) > 0 {
source.Spec.OtelServiceName = sourceOtelServiceFlag
}

_, err := client.OdigosClient.Sources(namespaceList).Update(ctx, &source, v1.UpdateOptions{})
if err != nil {
fmt.Printf("\033[31mERROR\033[0m Cannot update Sources %s/%s: %+v\n", source.GetNamespace(), source.GetName(), err)
os.Exit(1)
}
fmt.Printf("Updated Source %s/%s\n", source.GetNamespace(), source.GetName())
}
},
}

func parseSourceLabelFlags() (string, string, string, labels.Set) {
labelSet := labels.Set{}
providedWorkloadFlags := ""
if len(workloadKindFlag) > 0 {
providedWorkloadFlags = fmt.Sprintf("%s Workload Kind: %s\n", providedWorkloadFlags, workloadKindFlag)
labelSet[k8sconsts.WorkloadKindLabel] = workloadKindFlag
}
if len(workloadNameFlag) > 0 {
providedWorkloadFlags = fmt.Sprintf("%s Workload Name: %s\n", providedWorkloadFlags, workloadNameFlag)
labelSet[k8sconsts.WorkloadNameLabel] = workloadNameFlag
}
if len(workloadNamespaceFlag) > 0 {
providedWorkloadFlags = fmt.Sprintf("%s Workload Namespace: %s\n", providedWorkloadFlags, workloadNamespaceFlag)
labelSet[k8sconsts.WorkloadNamespaceLabel] = workloadNamespaceFlag
}
if len(sourceGroupFlag) > 0 {
providedWorkloadFlags = fmt.Sprintf("%s Source Group: %s\n", providedWorkloadFlags, sourceGroupFlag)
labelSet[k8sconsts.SourceGroupLabelPrefix+sourceGroupFlag] = "true"
}
namespaceList := namespaceFlag
namespaceText := fmt.Sprintf("namespace %s", namespaceFlag)
if allNamespaceFlag {
namespaceText = "all namespaces"
namespaceList = ""
}
return namespaceText, providedWorkloadFlags, namespaceList, labelSet
}

func init() {
sourceFlags = pflag.NewFlagSet("sourceFlags", pflag.ContinueOnError)
sourceFlags.StringVarP(&namespaceFlag, namespaceFlagName, "n", "default", "Kubernetes Namespace for Source")
sourceFlags.StringVar(&workloadKindFlag, workloadKindFlagName, "", "Kubernetes Kind for entity (one of: Deployment, DaemonSet, StatefulSet, Namespace)")
sourceFlags.StringVar(&workloadNameFlag, workloadNameFlagName, "", "Name of entity for Source")
sourceFlags.StringVar(&workloadNamespaceFlag, workloadNamespaceFlagName, "", "Namespace of entity for Source")
sourceFlags.StringVar(&sourceGroupFlag, sourceGroupFlagName, "", "Name of Source group to use")

rootCmd.AddCommand(sourcesCmd)
sourcesCmd.AddCommand(sourceCreateCmd)
sourcesCmd.AddCommand(sourceDeleteCmd)
sourcesCmd.AddCommand(sourceUpdateCmd)

sourceCreateCmd.Flags().AddFlagSet(sourceFlags)
sourceCreateCmd.Flags().BoolVar(&disableInstrumentationFlag, disableInstrumentationFlagName, false, "Disable instrumentation for Source")
sourceCreateCmd.Flags().StringVar(&sourceOtelServiceFlag, sourceOtelServiceFlagName, "", "OpenTelemetry service name to use for the Source")

sourceDeleteCmd.Flags().AddFlagSet(sourceFlags)
sourceDeleteCmd.Flags().Bool("yes", false, "skip the confirmation prompt")
sourceDeleteCmd.Flags().Bool(allNamespacesFlagName, false, "apply to all Kubernetes namespaces")

sourceUpdateCmd.Flags().AddFlagSet(sourceFlags)
sourceUpdateCmd.Flags().BoolVar(&disableInstrumentationFlag, disableInstrumentationFlagName, false, "Disable instrumentation for Source")
sourceUpdateCmd.Flags().StringVar(&sourceSetGroupFlag, sourceSetGroupFlagName, "", "Group name to be applied to the Source")
sourceUpdateCmd.Flags().StringVar(&sourceRemoveGroupFlag, sourceRemoveGroupFlagName, "", "Group name to be removed from the Source (if set)")
sourceUpdateCmd.Flags().Bool("yes", false, "skip the confirmation prompt")
sourceUpdateCmd.Flags().Bool(allNamespacesFlagName, false, "apply to all Kubernetes namespaces")
sourceUpdateCmd.Flags().StringVar(&sourceOtelServiceFlag, sourceOtelServiceFlagName, "", "OpenTelemetry service name to use for the Source")
}
2 changes: 1 addition & 1 deletion cli/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/odigos-io/odigos/k8sutils v0.0.0
github.com/odigos-io/odigos/profiles v0.0.0
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.32.1
k8s.io/apiextensions-apiserver v0.32.1
Expand All @@ -27,7 +28,6 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/moby/spdystream v0.5.0 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/x448/float16 v0.8.4 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
Expand Down
1 change: 1 addition & 0 deletions docs/cli/odigos.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Get started with Odigos today to effortlessly improve the observability of your
* [odigos install](/cli/odigos_install) - Install Odigos in your kubernetes cluster.
* [odigos pro](/cli/odigos_pro) - Manage Odigos onprem tier for enterprise users
* [odigos profile](/cli/odigos_profile) - Manage presets of applied profiles to your odigos installation
* [odigos sources](/cli/odigos_sources) - Manage Odigos Sources in a cluster
* [odigos ui](/cli/odigos_ui) - Start the Odigos UI
* [odigos uninstall](/cli/odigos_uninstall) - Revert all the changes made by the `odigos install` command.
This command will uninstall Odigos from your cluster. It will delete all Odigos objects
Expand Down
46 changes: 46 additions & 0 deletions docs/cli/odigos_sources.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
title: "odigos sources"
sidebarTitle: "odigos sources"
---
## odigos sources

Manage Odigos Sources in a cluster

### Synopsis

This command can be used to create, delete, or update Sources to configure workload or namespace auto-instrumentation

### Examples

```
# Create a Source "foo-source" for deployment "foo" in namespace "default"
odigos sources create foo-source --workload-kind=Deployment --workload-name=foo --workload-namespace=default -n default
# Update all existing Sources in namespace "default" to disable instrumentation
odigos sources update --disable-instrumentation -n default
# Delete all Sources in group "mygroup"
odigos sources delete --group mygroup --all-namespaces
```

### Options

```
-h, --help help for sources
```

### Options inherited from parent commands

```
--kube-context string (optional) name of the kubeconfig context to use
--kubeconfig string (optional) absolute path to the kubeconfig file (default "KUBECONFIG")
```

### SEE ALSO

* [odigos](/cli/odigos) - Automate OpenTelemetry Observability in Kubernetes
* [odigos sources create](/cli/odigos_sources_create) - Create an Odigos Source
* [odigos sources delete](/cli/odigos_sources_delete) - Delete Odigos Sources
* [odigos sources update](/cli/odigos_sources_update) - Update Odigos Sources
39 changes: 39 additions & 0 deletions docs/cli/odigos_sources_create.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
title: "odigos sources create"
sidebarTitle: "odigos sources create"
---
## odigos sources create

Create an Odigos Source

### Synopsis

This command will create the named Source object for the provided workload.

```
odigos sources create [name] [flags]
```

### Options

```
--disable-instrumentation Disable instrumentation for Source
--group string Name of Source group to use
-h, --help help for create
-n, --namespace string Kubernetes Namespace for Source (default "default")
--otel-service string OpenTelemetry service name to use for the Source
--workload-kind string Kubernetes Kind for entity (one of: Deployment, DaemonSet, StatefulSet, Namespace)
--workload-name string Name of entity for Source
--workload-namespace string Namespace of entity for Source
```

### Options inherited from parent commands

```
--kube-context string (optional) name of the kubeconfig context to use
--kubeconfig string (optional) absolute path to the kubeconfig file (default "KUBECONFIG")
```

### SEE ALSO

* [odigos sources](/cli/odigos_sources) - Manage Odigos Sources in a cluster
Loading

0 comments on commit 2b4759b

Please sign in to comment.