Skip to content

Commit

Permalink
[GEN-1335] feat: enterprise dynamic instrumentation (#1479)
Browse files Browse the repository at this point in the history
  • Loading branch information
alonkeyval authored Sep 2, 2024
1 parent 4e71626 commit 91859d9
Show file tree
Hide file tree
Showing 12 changed files with 607 additions and 35 deletions.
141 changes: 131 additions & 10 deletions frontend/endpoints/sources.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import (

"github.com/gin-gonic/gin"
"github.com/odigos-io/odigos/api/odigos/v1alpha1"
odigoscommon "github.com/odigos-io/odigos/common"
"github.com/odigos-io/odigos/common/consts"
"github.com/odigos-io/odigos/frontend/endpoints/common"
"github.com/odigos-io/odigos/frontend/kube"

"github.com/odigos-io/odigos/k8sutils/pkg/workload"
"golang.org/x/sync/errgroup"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand All @@ -22,8 +23,9 @@ type SourceLanguage struct {
}

type InstrumentedApplicationDetails struct {
Languages []SourceLanguage `json:"languages,omitempty"`
Conditions []metav1.Condition `json:"conditions,omitempty"`
Languages []SourceLanguage `json:"languages,omitempty"`
Conditions []metav1.Condition `json:"conditions,omitempty"`
InstrumentationOptions []v1alpha1.WorkloadInstrumentationConfig `json:"instrumentation_options,omitempty"`
}

// this object contains only part of the source fields. It is used to display the sources in the frontend
Expand All @@ -35,11 +37,13 @@ type ThinSource struct {

type Source struct {
ThinSource
ReportedName string `json:"reported_name,omitempty"`
ReportedName string `json:"reported_name,omitempty"`
InstrumentationConfig []v1alpha1.WorkloadInstrumentationConfig `json:"instrumentation_config,omitempty"`
}

type PatchSourceRequest struct {
ReportedName *string `json:"reported_name"`
ReportedName *string `json:"reported_name"`
InstrumentationConfig []v1alpha1.WorkloadInstrumentationConfig `json:"instrumentation_config,omitempty"`
}

func GetSources(c *gin.Context, odigosns string) {
Expand Down Expand Up @@ -143,6 +147,7 @@ func GetSource(c *gin.Context) {
}

instrumentedApplication, err := kube.DefaultClient.OdigosClient.InstrumentedApplications(ns).Get(c, k8sObjectName, metav1.GetOptions{})

if err == nil {
// valid instrumented application, grab the runtime details
ts.IaDetails = k8sInstrumentedAppToThinSource(instrumentedApplication).IaDetails
Expand All @@ -154,9 +159,18 @@ func GetSource(c *gin.Context) {
}
}

instrumentationConfig, err := kube.DefaultClient.OdigosClient.InstrumentationConfigs(ns).Get(context.Background(), instrumentedApplication.Name, metav1.GetOptions{})
if err != nil {
if !apierrors.IsNotFound(err) {
returnError(c, err)
return
}
}

c.JSON(200, Source{
ThinSource: ts,
ReportedName: reportedName,
ThinSource: ts,
InstrumentationConfig: instrumentationConfig.Spec.Config,
ReportedName: reportedName,
})
}

Expand All @@ -171,6 +185,12 @@ func PatchSource(c *gin.Context) {
return
}

tier, err := GetCurrentOdigosTier(c.Request.Context(), kube.DefaultClient, consts.DefaultOdigosNamespace)
if err != nil {
returnError(c, err)
return
}

if request.ReportedName != nil {

newReportedName := *request.ReportedName
Expand Down Expand Up @@ -218,6 +238,14 @@ func PatchSource(c *gin.Context) {
}
}

// Run instrumentation config logic only if the tier is "onprem"
if tier == odigoscommon.OnPremOdigosTier && request.InstrumentationConfig != nil {
if err := handleInstrumentationConfigRequest(c, ns, kind, name, request.InstrumentationConfig); err != nil {
returnError(c, err)
return
}
}

c.Status(200)
}

Expand All @@ -242,8 +270,26 @@ func DeleteSource(c *gin.Context) {
return
}

// Fetch the existing InstrumentationConfig
k8sObjectName := workload.CalculateWorkloadRuntimeObjectName(name, kind)
instrumentationConfig, err := kube.DefaultClient.OdigosClient.InstrumentationConfigs(ns).Get(context.Background(), k8sObjectName, metav1.GetOptions{})
if err != nil && !apierrors.IsNotFound(err) {
returnError(c, err)
return
}

// Reset the InstrumentationConfig if it exists
if err == nil {
instrumentationConfig.Spec.Config = []v1alpha1.WorkloadInstrumentationConfig{}
_, err = kube.DefaultClient.OdigosClient.InstrumentationConfigs(ns).Update(c.Request.Context(), instrumentationConfig, metav1.UpdateOptions{})
if err != nil {
returnError(c, err)
return
}
}

instrumented := false
err := setWorkloadInstrumentationLabel(c, ns, name, kindAsEnum, &instrumented)
err = setWorkloadInstrumentationLabel(c, ns, name, kindAsEnum, &instrumented)
if err != nil {
returnError(c, err)
return
Expand All @@ -252,6 +298,60 @@ func DeleteSource(c *gin.Context) {
c.JSON(200, gin.H{"message": "ok"})
}

func handleInstrumentationConfigRequest(c *gin.Context, ns, kind, name string, configs []v1alpha1.WorkloadInstrumentationConfig) error {
k8sObjectName := workload.CalculateWorkloadRuntimeObjectName(name, kind)

instrumentationConfigResource, err := kube.DefaultClient.OdigosClient.InstrumentationConfigs(ns).Get(c.Request.Context(), k8sObjectName, metav1.GetOptions{})
if err != nil && !apierrors.IsNotFound(err) {
return err
}

shouldInsert := apierrors.IsNotFound(err)

workloadOwner, _ := getWorkloadObject(c, ns, kind, name)

var workloadConfigs []v1alpha1.WorkloadInstrumentationConfig
for _, config := range configs {
workloadConfig := v1alpha1.WorkloadInstrumentationConfig{
OptionKey: config.OptionKey,
OptionValueBoolean: config.OptionValueBoolean,
SpanKind: config.SpanKind,
InstrumentationLibraries: config.InstrumentationLibraries,
}
workloadConfigs = append(workloadConfigs, workloadConfig)
}

newConfig := v1alpha1.InstrumentationConfig{
ObjectMeta: metav1.ObjectMeta{
Name: k8sObjectName,
Namespace: ns,
OwnerReferences: []metav1.OwnerReference{
{
APIVersion: "apps/v1",
Kind: kind,
Name: k8sObjectName,
UID: workloadOwner.GetUID(),
},
},
},
Spec: v1alpha1.InstrumentationConfigSpec{
Config: workloadConfigs,
},
}

if !shouldInsert {
newConfig.ResourceVersion = instrumentationConfigResource.ResourceVersion
}

if shouldInsert {
_, err = kube.DefaultClient.OdigosClient.InstrumentationConfigs(ns).Create(c.Request.Context(), &newConfig, metav1.CreateOptions{})
} else {
_, err = kube.DefaultClient.OdigosClient.InstrumentationConfigs(ns).Update(c.Request.Context(), &newConfig, metav1.UpdateOptions{})
}

return err
}

func k8sInstrumentedAppToThinSource(app *v1alpha1.InstrumentedApplication) ThinSource {
var source ThinSource
source.Name = app.OwnerReferences[0].Name
Expand All @@ -266,10 +366,31 @@ func k8sInstrumentedAppToThinSource(app *v1alpha1.InstrumentedApplication) ThinS
LastTransitionTime: condition.LastTransitionTime,
})
}

var instrumentationOptions []v1alpha1.WorkloadInstrumentationConfig

for _, option := range app.Spec.Options {
for _, libOptions := range option.InstrumentationLibraries {
for _, configOption := range libOptions.Options {
instrumentationOptions = append(instrumentationOptions, v1alpha1.WorkloadInstrumentationConfig{
OptionKey: configOption.OptionKey,
SpanKind: configOption.SpanKind,
InstrumentationLibraries: []v1alpha1.InstrumentationLibrary{
{
InstrumentationLibraryName: libOptions.LibraryName,
},
},
})
}
}
}

source.IaDetails = &InstrumentedApplicationDetails{
Languages: []SourceLanguage{},
Conditions: conditions,
Languages: []SourceLanguage{},
Conditions: conditions,
InstrumentationOptions: instrumentationOptions,
}

for _, language := range app.Spec.RuntimeDetails {
source.IaDetails.Languages = append(source.IaDetails.Languages, SourceLanguage{
ContainerName: language.ContainerName,
Expand Down
45 changes: 45 additions & 0 deletions frontend/endpoints/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,23 @@ import (
"errors"
"path"

"github.com/odigos-io/odigos/common"
"github.com/odigos-io/odigos/common/consts"
"github.com/odigos-io/odigos/frontend/kube"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)

const cdnUrl = "https://d15jtxgb40qetw.cloudfront.net"
const (
odigosProSecretName = "odigos-pro"
odigosCloudTokenEnvName = "ODIGOS_CLOUD_TOKEN"
odigosCloudApiKeySecretKey = "odigos-cloud-api-key"
odigosOnpremTokenEnvName = "ODIGOS_ONPREM_TOKEN"
odigosOnpremTokenSecretKey = "odigos-onprem-token"
)

func GetImageURL(image string) string {
return path.Join(cdnUrl, image)
Expand Down Expand Up @@ -50,3 +60,38 @@ func isObjectLabeledForInstrumentation(metav metav1.ObjectMeta) *bool {
}
return nsInstrumentationLabeled
}

func GetCurrentOdigosTier(ctx context.Context, client *kube.Client, ns string) (common.OdigosTier, error) {
sec, err := getCurrentOdigosProSecret(ctx, client, ns)
if err != nil {
return "", err
}
if sec == nil {
return common.CommunityOdigosTier, nil
}

if _, exists := sec.Data[odigosCloudApiKeySecretKey]; exists {
return common.CloudOdigosTier, nil
}
if _, exists := sec.Data[odigosOnpremTokenSecretKey]; exists {
return common.OnPremOdigosTier, nil
}
return common.CommunityOdigosTier, nil
}

func getCurrentOdigosProSecret(ctx context.Context, client *kube.Client, ns string) (*corev1.Secret, error) {
secret, err := client.CoreV1().Secrets(ns).Get(ctx, odigosProSecretName, metav1.GetOptions{})
if apierrors.IsNotFound(err) {
return nil, nil
}
if err != nil {
return nil, err
}

// apparently, k8s is not setting the type meta for the object obtained with Get.
secret.TypeMeta = metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
}
return secret, err
}
8 changes: 4 additions & 4 deletions frontend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
github.com/fatih/color v1.10.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
Expand All @@ -107,8 +107,8 @@ require (
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
Expand All @@ -132,7 +132,7 @@ require (
golang.org/x/term v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
Expand Down
21 changes: 10 additions & 11 deletions frontend/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxER
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
Expand Down Expand Up @@ -128,12 +128,12 @@ github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
Expand Down Expand Up @@ -334,13 +334,12 @@ golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
Expand All @@ -365,8 +364,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0=
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
Expand Down
1 change: 1 addition & 0 deletions frontend/webapp/components/lists/index.tsx
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { EmptyList } from './empty.list/empty.list';
export * from './step-list';
export * from './instrumentation-config-list';
Loading

0 comments on commit 91859d9

Please sign in to comment.