Skip to content

Commit

Permalink
feat: initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
tamirdavid1 committed Dec 22, 2024
1 parent ace5022 commit 212962e
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 34 deletions.
8 changes: 8 additions & 0 deletions cli/cmd/migrations/base_migration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package migrations

type Migration interface {
Name() string // Unique name of the migration
Description() string // A brief description of the migration
TriggerVersion() string // The version at which the migration becomes applicable
Execute() error // Code to execute the migration
}
30 changes: 0 additions & 30 deletions cli/cmd/migrations/json-patch.go

This file was deleted.

52 changes: 52 additions & 0 deletions cli/cmd/migrations/manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package migrations

import (
"fmt"

"github.com/odigos-io/odigos/cli/cmd/migrations/runtime_details_migration"
"github.com/odigos-io/odigos/cli/pkg/kube"

"golang.org/x/mod/semver"
)

type MigrationManager struct {
Migrations []Migration
}

func NewMigrationManager(client *kube.Client) *MigrationManager {
return &MigrationManager{
Migrations: []Migration{
&runtime_details_migration.MigrateRuntimeDetails{Client: client},
// Add more migrations here by referencing their structs
},
}
}
func (m *MigrationManager) Run(fromVersion, toVersion string) error {
// Ensure versions are valid semantic versions
if !semver.IsValid(fromVersion) {
return fmt.Errorf("invalid from version: %s", fromVersion)
}
if !semver.IsValid(toVersion) {
return fmt.Errorf("invalid to version: %s", toVersion)
}

for _, migration := range m.Migrations {
cutVersion := migration.TriggerVersion()
if !semver.IsValid(cutVersion) {
return fmt.Errorf("invalid cut version for migration %s: %s", migration.Name(), cutVersion)
}

// Check if migration should be executed
if true { //semver.Compare(fromVersion, cutVersion) < 0 && semver.Compare(toVersion, cutVersion) >= 0
fmt.Printf("Executing migration: %s - %s\n", migration.Name(), migration.Description())
if err := migration.Execute(); err != nil {
return fmt.Errorf("migration %s failed: %w", migration.Name(), err)
}
fmt.Printf("Migration %s completed successfully.\n", migration.Name())
} else {
fmt.Printf("Skipping migration: %s (cut version: %s, from: %s, to: %s)\n",
migration.Name(), cutVersion, fromVersion, toVersion)
}
}
return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package runtime_details_migration

import (
"context"
"fmt"
"strings"

"github.com/odigos-io/odigos/api/odigos/v1alpha1"
"github.com/odigos-io/odigos/cli/pkg/kube"
"github.com/odigos-io/odigos/k8sutils/pkg/envoverwrite"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)

type MigrateRuntimeDetails struct {
Client *kube.Client
}

func (m *MigrateRuntimeDetails) Name() string {
return "migrate-runtime-details"
}

func (m *MigrateRuntimeDetails) Description() string {
return "Migrate old RuntimeDetailsByContainer structure to the new format"
}

func (m *MigrateRuntimeDetails) TriggerVersion() string {
return "v1.0.139"
}

func (m *MigrateRuntimeDetails) Execute() error {
fmt.Println("Migrating RuntimeDetailsByContainer....")

gvr := schema.GroupVersionResource{Group: "odigos.io", Version: "v1alpha1", Resource: "instrumentationconfigs"}

ctx := context.TODO()
instrumentationConfigs, err := m.Client.Dynamic.Resource(gvr).List(ctx, metav1.ListOptions{})
if err != nil {
panic(fmt.Errorf("failed to list InstrumentationConfigs: %v", err))
}

workloadNamespaces := make(map[string]map[string][]string) // workloadType -> namespace -> []workloadNames
for _, item := range instrumentationConfigs.Items {
fmt.Printf("Found InstrumentationConfig: %s in namespace: %s\n", item.GetName(), item.GetNamespace())
IcName := item.GetName()
IcNamespace := item.GetNamespace()
parts := strings.Split(IcName, "-")
if len(parts) < 2 {
fmt.Printf("Skipping invalid InstrumentationConfig name: %s\n", IcName)
continue
}

workloadType := parts[0] // deployment/statefulset/aemonset
workloadName := strings.Join(parts[1:], "-")
if _, exists := workloadNamespaces[workloadType]; !exists {
workloadNamespaces[workloadType] = make(map[string][]string)
}
workloadNamespaces[workloadType][IcNamespace] = append(workloadNamespaces[workloadType][IcNamespace], workloadName)
}
for workloadType, namespaces := range workloadNamespaces {
switch workloadType {
case "deployment":
if err := fetchAndProcessDeployments(m.Client, namespaces); err != nil {
return err
}
case "statefulset":
if err := fetchAndProcessStatefulSets(m.Client, namespaces); err != nil {
return err
}
case "daemonset":
if err := fetchAndProcessDaemonSets(m.Client, namespaces); err != nil {
return err
}
default:
fmt.Printf("Unknown workload type: %s\n", workloadType)
}
}

return nil
}

func fetchAndProcessDeployments(clientset *kube.Client, namespaces map[string][]string) error {
for namespace, workloadNames := range namespaces {
fmt.Printf("Processing Deployments in namespace: %s\n", namespace)
deployments, err := clientset.AppsV1().Deployments(namespace).List(context.TODO(), metav1.ListOptions{})
if err != nil {
return fmt.Errorf("failed to list deployments in namespace %s: %v", namespace, err)
}

for _, dep := range deployments.Items {
if contains(workloadNames, dep.Name) {
fmt.Printf("Processing Deployment: %s in namespace: %s\n", dep.Name, dep.Namespace)
originalEnvVar, _ := envoverwrite.NewOrigWorkloadEnvValues(dep.Annotations)
allNil := originalEnvVar.AreAllEnvValuesNil()
if allNil {
// update instrumentationConfig object
}
instrumentationConfig, err := clientset.OdigosClient.InstrumentationConfigs(dep.Namespace).Get(context.TODO(), dep.Name, metav1.GetOptions{})
if err != nil {
fmt.Printf("Failed to get InstrumentationConfig: %v\n", err)
}
// TODO: Need to move the general operations to top level object and not per iteration.
// updating runtimeDetailsByContainer as Skipped - executed but nothing happen
for _, runtimeDetails := range instrumentationConfig.Status.RuntimeDetailsByContainer {
value := v1alpha1.ProcessingStateSkipped
runtimeDetails.RuntimeUpdateState = &value
}
for _, container := range dep.Spec.Template.Spec.Containers {
fmt.Printf("Processing container: %s\n", container.Name)
// Add your deployment-specific logic here
}
}
}
}
return nil
}

func fetchAndProcessStatefulSets(clientset *kube.Client, namespaces map[string][]string) error {
for namespace, workloadNames := range namespaces {
statefulSets, err := clientset.AppsV1().StatefulSets(namespace).List(context.TODO(), metav1.ListOptions{})
if err != nil {
return fmt.Errorf("failed to list statefulsets in namespace %s: %v", namespace, err)
}

for _, sts := range statefulSets.Items {
if contains(workloadNames, sts.Name) {
fmt.Printf("Processing StatefulSet: %s in namespace: %s\n", sts.Name, sts.Namespace)
// Add your statefulset-specific logic here
}
}
}
return nil
}

func fetchAndProcessDaemonSets(clientset *kube.Client, namespaces map[string][]string) error {
for namespace, workloadNames := range namespaces {
daemonSets, err := clientset.AppsV1().DaemonSets(namespace).List(context.TODO(), metav1.ListOptions{})
if err != nil {
return fmt.Errorf("failed to list daemonsets in namespace %s: %v", namespace, err)
}

for _, ds := range daemonSets.Items {
if contains(workloadNames, ds.Name) {
fmt.Printf("Processing DaemonSet: %s in namespace: %s\n", ds.Name, ds.Namespace)
// Add your daemonset-specific logic here
}
}
}
return nil
}

func contains(slice []string, item string) bool {
for _, v := range slice {
if v == item {
return true
}
}
return false
}
3 changes: 1 addition & 2 deletions cli/cmd/resources/applyresources.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,5 @@ func GetCurrentConfig(ctx context.Context, client *kube.Client, ns string) (*com
}

func GetDeprecatedConfig(ctx context.Context, client *kube.Client, ns string) (*v1alpha1.OdigosConfiguration, error) {
return client.OdigosClient.OdigosConfigurations(ns).Get(ctx, consts.OdigosConfigurationName, metav1.GetOptions{})
return client.OdigosClient.OdigosConfigurations(ns).Get(ctx, consts.OdigosConfigurationName, metav1.GetOptions{})
}

10 changes: 9 additions & 1 deletion cli/cmd/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"os"

"github.com/hashicorp/go-version"
"github.com/odigos-io/odigos/cli/cmd/migrations"
"github.com/odigos-io/odigos/cli/cmd/resources"
"github.com/odigos-io/odigos/cli/cmd/resources/odigospro"
cmdcontext "github.com/odigos-io/odigos/cli/pkg/cmd_context"
Expand Down Expand Up @@ -41,6 +42,7 @@ and apply any required migrations and adaptations.`,

var operation string

var currOdigosVersion string
skipVersionCheckFlag := cmd.Flag("skip-version-check")
if skipVersionCheckFlag == nil || !cmd.Flag("skip-version-check").Changed {

Expand All @@ -50,7 +52,7 @@ and apply any required migrations and adaptations.`,
os.Exit(1)
}

currOdigosVersion := cm.Data["ODIGOS_VERSION"]
currOdigosVersion = cm.Data["ODIGOS_VERSION"]
if currOdigosVersion == "" {
fmt.Println("Odigos upgrade failed - unable to read the current Odigos version for migration")
os.Exit(1)
Expand Down Expand Up @@ -126,6 +128,12 @@ and apply any required migrations and adaptations.`,
fmt.Println("Odigos upgrade failed - unable to cleanup old Odigos resources.")
os.Exit(1)
}
manager := migrations.NewMigrationManager(client)
// Run migrations
if err := manager.Run(currOdigosVersion, versionFlag); err != nil {
fmt.Printf("Upgrade failed: %v\n", err)
return
}
},
}

Expand Down
1 change: 1 addition & 0 deletions cli/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ require (
go.opentelemetry.io/otel v1.29.0 // indirect
go.opentelemetry.io/otel/trace v1.29.0 // indirect
go.uber.org/multierr v1.11.0
golang.org/x/mod v0.22.0
golang.org/x/net v0.30.0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/sys v0.26.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions cli/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
Expand Down
15 changes: 14 additions & 1 deletion k8sutils/pkg/envoverwrite/origenv.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
// original manifest values for the env vars of a workload
// This is specific to k8s as it assumes there is OriginalEnv per container
type OrigWorkloadEnvValues struct {
origManifestValues map[string]envOverwrite.OriginalEnv
origManifestValues map[string]envOverwrite.OriginalEnv //container name -> env name -> original value
modifiedSinceCreated bool
}

Expand Down Expand Up @@ -108,3 +108,16 @@ func (o *OrigWorkloadEnvValues) DeleteFromObj(obj metav1.Object) bool {
delete(currentAnnotations, consts.ManifestEnvOriginalValAnnotation)
return true
}

// AreAllEnvValuesNil iterates over all containers in origManifestValues
// and checks if all their keys' values are nil. Returns true if all values are nil.
func (o *OrigWorkloadEnvValues) AreAllEnvValuesNil() bool {
for _, envMap := range o.origManifestValues {
for _, originalValue := range envMap {
if originalValue != nil {
return false
}
}
}
return true
}

0 comments on commit 212962e

Please sign in to comment.