From 01cef4b7be372d60a5cb7bfc09de04f2c838dfdc Mon Sep 17 00:00:00 2001 From: Eden Federman Date: Tue, 17 Dec 2024 09:15:11 +0200 Subject: [PATCH] .NET support for musl-based containers (#1987) --- .../odigos.io_instrumentationconfigs.yaml | 5 ++ .../odigos.io_instrumentedapplications.yaml | 5 ++ .../v1alpha1/runtimedetailsbycontainer.go | 9 +++ .../v1alpha1/instrumentedapplication_types.go | 1 + api/odigos/v1alpha1/zz_generated.deepcopy.go | 5 ++ common/instrumentationdevice.go | 21 +++++- common/instrumentationdevice_test.go | 71 +++++++++++++++++- common/libc_types.go | 9 +++ docs/instrumentations/dotnet/dotnet.mdx | 58 +++++++++++++++ docs/instrumentations/java/java.mdx | 2 +- docs/mint.json | 6 ++ .../odigos.io_instrumentationconfigs.yaml | 5 ++ .../odigos.io_instrumentedapplications.yaml | 5 ++ .../instrumentation/instrumentation.go | 13 +++- odiglet/Dockerfile | 6 +- .../instrumentation/instrumentlang/dotnet.go | 4 +- odiglet/pkg/instrumentation/lister.go | 24 +++++- odiglet/pkg/instrumentation/plugin.go | 24 +++--- .../pkg/kube/runtime_details/inspection.go | 14 ++++ procdiscovery/pkg/inspectors/dotnet/dotnet.go | 25 ++++--- procdiscovery/pkg/libc/utils.go | 69 +++++++++++++++++ .../01-assert-apps-installed.yaml | 15 +++- .../01-assert-runtime-detected.yaml | 19 ++++- .../01-assert-workloads.yaml | 29 ++++++++ .../01-generate-traffic.yaml | 2 + .../01-install-test-apps.yaml | 40 +++++++++- .../02-assert-workload-update.yaml | 35 +++++++++ .../02-update-workload-manifests.yaml | 27 +++++++ .../workload-lifecycle/03-wait-for-trace.yaml | 2 +- .../e2e/workload-lifecycle/chainsaw-test.yaml | 4 +- .../services/dotnet-musl-server/Dockerfile | 11 +++ .../services/dotnet-musl-server/Program.cs | 6 ++ .../dotnet-musl-server.csproj | 10 +++ ...otnet-musl-server.csproj.nuget.dgspec.json | 69 +++++++++++++++++ .../dotnet-musl-server.csproj.nuget.g.props | 15 ++++ .../dotnet-musl-server.csproj.nuget.g.targets | 2 + .../obj/project.assets.json | 74 +++++++++++++++++++ .../obj/project.nuget.cache | 8 ++ 38 files changed, 708 insertions(+), 41 deletions(-) create mode 100644 common/libc_types.go create mode 100644 docs/instrumentations/dotnet/dotnet.mdx create mode 100644 procdiscovery/pkg/libc/utils.go create mode 100644 tests/e2e/workload-lifecycle/services/dotnet-musl-server/Dockerfile create mode 100644 tests/e2e/workload-lifecycle/services/dotnet-musl-server/Program.cs create mode 100644 tests/e2e/workload-lifecycle/services/dotnet-musl-server/dotnet-musl-server.csproj create mode 100644 tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/dotnet-musl-server.csproj.nuget.dgspec.json create mode 100644 tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/dotnet-musl-server.csproj.nuget.g.props create mode 100644 tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/dotnet-musl-server.csproj.nuget.g.targets create mode 100644 tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/project.assets.json create mode 100644 tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/project.nuget.cache diff --git a/api/config/crd/bases/odigos.io_instrumentationconfigs.yaml b/api/config/crd/bases/odigos.io_instrumentationconfigs.yaml index fdfd06cea..0a58751f1 100644 --- a/api/config/crd/bases/odigos.io_instrumentationconfigs.yaml +++ b/api/config/crd/bases/odigos.io_instrumentationconfigs.yaml @@ -462,6 +462,11 @@ spec: - unknown - ignored type: string + libCType: + enum: + - glibc + - musl + type: string otherAgent: properties: name: diff --git a/api/config/crd/bases/odigos.io_instrumentedapplications.yaml b/api/config/crd/bases/odigos.io_instrumentedapplications.yaml index 696bd689b..83e7156d7 100644 --- a/api/config/crd/bases/odigos.io_instrumentedapplications.yaml +++ b/api/config/crd/bases/odigos.io_instrumentedapplications.yaml @@ -114,6 +114,11 @@ spec: - unknown - ignored type: string + libCType: + enum: + - glibc + - musl + type: string otherAgent: properties: name: diff --git a/api/generated/odigos/applyconfiguration/odigos/v1alpha1/runtimedetailsbycontainer.go b/api/generated/odigos/applyconfiguration/odigos/v1alpha1/runtimedetailsbycontainer.go index 4fcb2f4d3..14d4b53d3 100644 --- a/api/generated/odigos/applyconfiguration/odigos/v1alpha1/runtimedetailsbycontainer.go +++ b/api/generated/odigos/applyconfiguration/odigos/v1alpha1/runtimedetailsbycontainer.go @@ -29,6 +29,7 @@ type RuntimeDetailsByContainerApplyConfiguration struct { RuntimeVersion *string `json:"runtimeVersion,omitempty"` EnvVars []EnvVarApplyConfiguration `json:"envVars,omitempty"` OtherAgent *OtherAgentApplyConfiguration `json:"otherAgent,omitempty"` + LibCType *common.LibCType `json:"libCType,omitempty"` } // RuntimeDetailsByContainerApplyConfiguration constructs a declarative configuration of the RuntimeDetailsByContainer type for use with @@ -81,3 +82,11 @@ func (b *RuntimeDetailsByContainerApplyConfiguration) WithOtherAgent(value *Othe b.OtherAgent = value return b } + +// WithLibCType sets the LibCType field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the LibCType field is set to the value of the last call. +func (b *RuntimeDetailsByContainerApplyConfiguration) WithLibCType(value common.LibCType) *RuntimeDetailsByContainerApplyConfiguration { + b.LibCType = &value + return b +} diff --git a/api/odigos/v1alpha1/instrumentedapplication_types.go b/api/odigos/v1alpha1/instrumentedapplication_types.go index c3011f6be..3077d6dca 100644 --- a/api/odigos/v1alpha1/instrumentedapplication_types.go +++ b/api/odigos/v1alpha1/instrumentedapplication_types.go @@ -50,6 +50,7 @@ type RuntimeDetailsByContainer struct { RuntimeVersion string `json:"runtimeVersion,omitempty"` EnvVars []EnvVar `json:"envVars,omitempty"` OtherAgent *OtherAgent `json:"otherAgent,omitempty"` + LibCType *common.LibCType `json:"libCType,omitempty"` } // +kubebuilder:object:generate=true diff --git a/api/odigos/v1alpha1/zz_generated.deepcopy.go b/api/odigos/v1alpha1/zz_generated.deepcopy.go index f825166ae..bc2dbb747 100644 --- a/api/odigos/v1alpha1/zz_generated.deepcopy.go +++ b/api/odigos/v1alpha1/zz_generated.deepcopy.go @@ -1222,6 +1222,11 @@ func (in *RuntimeDetailsByContainer) DeepCopyInto(out *RuntimeDetailsByContainer *out = new(OtherAgent) **out = **in } + if in.LibCType != nil { + in, out := &in.LibCType, &out.LibCType + *out = new(common.LibCType) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RuntimeDetailsByContainer. diff --git a/common/instrumentationdevice.go b/common/instrumentationdevice.go index 5b6671778..1d04057e7 100644 --- a/common/instrumentationdevice.go +++ b/common/instrumentationdevice.go @@ -21,18 +21,31 @@ const OdigosResourceNamespace = "instrumentation.odigos.io" // the native Java SDK will be named "java-native-community". // the ebpf Java enterprise sdk will be named "java-ebpf-enterprise". -func InstrumentationPluginName(language ProgrammingLanguage, otelSdk OtelSdk) string { - return string(language) + "-" + string(otelSdk.SdkType) + "-" + string(otelSdk.SdkTier) +func InstrumentationPluginName(language ProgrammingLanguage, otelSdk OtelSdk, libc *LibCType) string { + result := string(language) + "-" + string(otelSdk.SdkType) + "-" + string(otelSdk.SdkTier) + + // If musl libc type recorded - we use different plugin name + if libc != nil && *libc == Musl { + result = "musl-" + result + } + + return result } func InstrumentationPluginNameToComponents(pluginName string) (ProgrammingLanguage, OtelSdk) { components := strings.Split(pluginName, "-") + if len(components) > 3 { + // This is a musl libc plugin + pluginName = strings.Join(components[1:], "-") + components = strings.Split(pluginName, "-") + } + otelSdk := OtelSdk{SdkType: OtelSdkType(components[1]), SdkTier: OtelSdkTier(components[2])} return ProgrammingLanguage(components[0]), otelSdk } -func InstrumentationDeviceName(language ProgrammingLanguage, otelSdk OtelSdk) OdigosInstrumentationDevice { - pluginName := InstrumentationPluginName(language, otelSdk) +func InstrumentationDeviceName(language ProgrammingLanguage, otelSdk OtelSdk, libc *LibCType) OdigosInstrumentationDevice { + pluginName := InstrumentationPluginName(language, otelSdk, libc) return OdigosInstrumentationDevice(OdigosResourceNamespace + "/" + pluginName) } diff --git a/common/instrumentationdevice_test.go b/common/instrumentationdevice_test.go index 470ef770d..095dbd382 100644 --- a/common/instrumentationdevice_test.go +++ b/common/instrumentationdevice_test.go @@ -10,7 +10,35 @@ func TestInstrumentationPluginName(t *testing.T) { SdkType: NativeOtelSdkType, SdkTier: CommunityOtelSdkTier, } - pluginName := InstrumentationPluginName(language, otelSdk) + pluginName := InstrumentationPluginName(language, otelSdk, nil) + want := "dotnet-native-community" + if pluginName != want { + t.Errorf("InstrumentationPluginName() = %v, want %v", pluginName, want) + } +} + +func TestInstrumentationPluginNameMusl(t *testing.T) { + language := DotNetProgrammingLanguage + otelSdk := OtelSdk{ + SdkType: NativeOtelSdkType, + SdkTier: CommunityOtelSdkTier, + } + musl := Musl + pluginName := InstrumentationPluginName(language, otelSdk, &musl) + want := "musl-dotnet-native-community" + if pluginName != want { + t.Errorf("InstrumentationPluginName() = %v, want %v", pluginName, want) + } +} + +func TestInstrumentationPluginNameGlib(t *testing.T) { + language := DotNetProgrammingLanguage + otelSdk := OtelSdk{ + SdkType: NativeOtelSdkType, + SdkTier: CommunityOtelSdkTier, + } + glib := Glibc + pluginName := InstrumentationPluginName(language, otelSdk, &glib) want := "dotnet-native-community" if pluginName != want { t.Errorf("InstrumentationPluginName() = %v, want %v", pluginName, want) @@ -23,21 +51,56 @@ func TestInstrumentationDeviceName(t *testing.T) { SdkType: EbpfOtelSdkType, SdkTier: EnterpriseOtelSdkTier, } - deviceName := InstrumentationDeviceName(language, otelSdk) + deviceName := InstrumentationDeviceName(language, otelSdk, nil) want := "instrumentation.odigos.io/java-ebpf-enterprise" if string(deviceName) != want { t.Errorf("InstrumentationDeviceName() = %v, want %v", deviceName, want) } } -func TestInstrumentationDeviceNameToComponents(t *testing.T) { +func TestInstrumentationDeviceNameGlib(t *testing.T) { + language := JavaProgrammingLanguage + otelSdk := OtelSdk{ + SdkType: EbpfOtelSdkType, + SdkTier: EnterpriseOtelSdkTier, + } + glib := Glibc + deviceName := InstrumentationDeviceName(language, otelSdk, &glib) + want := "instrumentation.odigos.io/java-ebpf-enterprise" + if string(deviceName) != want { + t.Errorf("InstrumentationDeviceName() = %v, want %v", deviceName, want) + } +} +func TestInstrumentationDeviceNameToComponents(t *testing.T) { language := GoProgrammingLanguage otelSdkType := EbpfOtelSdkType otelSdkTier := CommunityOtelSdkTier sdk := OtelSdk{SdkType: otelSdkType, SdkTier: otelSdkTier} - deviceName := InstrumentationDeviceName(language, sdk) + deviceName := InstrumentationDeviceName(language, sdk, nil) + gotLanguage, gotSdk := InstrumentationDeviceNameToComponents(string(deviceName)) + + if gotLanguage != language { + t.Errorf("InstrumentationDeviceNameToComponents() gotLanguage = %v, want %v", gotLanguage, language) + } + if gotSdk.SdkType != otelSdkType { + t.Errorf("InstrumentationDeviceNameToComponents() gotOtelSdkType = %v, want %v", gotSdk.SdkType, otelSdkType) + } + if gotSdk.SdkTier != otelSdkTier { + t.Errorf("InstrumentationDeviceNameToComponents() gotOtelSdkTier = %v, want %v", gotSdk.SdkTier, otelSdkTier) + } +} + +func TestInstrumentationDeviceNameToComponentsMusl(t *testing.T) { + + language := DotNetProgrammingLanguage + otelSdkType := NativeOtelSdkType + otelSdkTier := CommunityOtelSdkTier + sdk := OtelSdk{SdkType: otelSdkType, SdkTier: otelSdkTier} + + musl := Musl + deviceName := InstrumentationDeviceName(language, sdk, &musl) gotLanguage, gotSdk := InstrumentationDeviceNameToComponents(string(deviceName)) if gotLanguage != language { diff --git a/common/libc_types.go b/common/libc_types.go new file mode 100644 index 000000000..a8896f945 --- /dev/null +++ b/common/libc_types.go @@ -0,0 +1,9 @@ +package common + +// +kubebuilder:validation:Enum=glibc;musl +type LibCType string + +const ( + Glibc LibCType = "glibc" + Musl LibCType = "musl" +) diff --git a/docs/instrumentations/dotnet/dotnet.mdx b/docs/instrumentations/dotnet/dotnet.mdx new file mode 100644 index 000000000..334280bc2 --- /dev/null +++ b/docs/instrumentations/dotnet/dotnet.mdx @@ -0,0 +1,58 @@ +--- +title: ".NET Native Instrumentation" +sidebarTitle: "Native instrumentation" +--- + +## Supported Versions + +The minimal supported version of .NET Framework is **4.6.2**. + +The following CPU architectures are supported: +- amd64 (x86_64) +- arm64 + +## Instrumentation Libraries + +The following .NET modules will be auto instrumented by Odigos: + +### Application Frameworks + +| Framework | Tracing Support | Metrics Support | Notes | +|---------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------:|:-----------------------------------------------------------------------------:|----------------------------------------------------------------------------------------------------------| +| [ASP.NET](https://docs.microsoft.com/aspnet/overview) | Yes | Yes | | +| [ASP.NET Core](https://docs.microsoft.com/aspnet/core/introduction-to-aspnet-core?view=aspnetcore-6.0) | Yes | Yes | | + +### Databases + +| Library | Tracing Support | Metrics Support | Notes | +|----------------------------------------------------------------------------------------------------|-----------------|-------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [Microsoft.Data.SqlClient](https://www.nuget.org/packages/Microsoft.Data.SqlClient) | Yes | | | +| [System.Data.SqlClient](https://www.nuget.org/packages/System.Data.SqlClient) | Yes | | | +| [MySql.Data](https://dev.mysql.com/doc/connector-net/en/connector-net-introduction.html) | Partial | | This is the official [MySQL](https://dev.mysql.com/) library. | +| [MySqlConnector](https://mysqlconnector.net/) | Yes | | Seems to be the [recommended library for MariaDB](https://mariadb.com/kb/en/mysqlconnector-for-ado-net/). | +| [Npgsql](https://www.npgsql.org/) | Yes | | | +| [Microsoft.Data.SqlLite](https://docs.microsoft.com/dotnet/standard/data/sqlite/?tabs=netcore-cli) | | | | +| [MongoDB.Driver](https://www.nuget.org/packages/mongodb.driver) | Yes | | | +| [StackExchange.Redis](https://stackexchange.github.io/StackExchange.Redis/) | Partial | | | +| [Elasticsearch-net](https://github.com/elastic/elasticsearch-net) | Yes | | 8.0.0+ only. | +| [Oracle.ManagedDataAccess.Core](https://www.nuget.org/packages/Oracle.ManagedDataAccess.Core) | Yes | | 23.4.0+ only. | +| [Oracle.ManagedDataAccess](https://www.nuget.org/packages/Oracle.ManagedDataAccess) | Yes | | 23.4.0+ only. | +| [AWSSDK.DynamoDBv2](https://www.nuget.org/packages/AWSSDK.DynamoDBv2) | | | | +| [Microsoft.Azure.Cosmos](https://www.nuget.org/packages/Microsoft.Azure.Cosmos) | | | | + +### Inter-process communication (IPC) + +| Library | Tracing Support | Metrics Support | Notes | +|-----------------------------------------------------------------------------------|-------------------------------------------------|-----------------|--------------------------------------------------------------------------------------------------------| +| [HttpClient](https://docs.microsoft.com/dotnet/api/system.net.http.httpclient) | Yes | Yes | | +| [HttpWebRequest](https://docs.microsoft.com/dotnet/api/system.net.httpwebrequest) | Yes | Yes | | +| [WCF](https://docs.microsoft.com/dotnet/framework/wcf/whats-wcf) | Yes (Client adn Service side on .NET Framework) | | | +| [CoreWCF](https://github.com/CoreWCF/CoreWCF) | | | | +| [RestSharp](https://restsharp.dev/) | | | This library may be implicitly supported by instrumenting the underlying HttpClient or HttpWebRequest. | +| [gRPC-dotnet](https://github.com/grpc/grpc-dotnet) | Partial | | Client and service support should be added. | +| [GraphQL](https://www.nuget.org/packages/GraphQL/) | Partial | | | +| [GraphQL Client](https://github.com/graphql-dotnet/graphql-client) | | | | +| [RabbitMQ](https://www.nuget.org/packages/RabbitMQ.Client) | Yes | | `RabbitMQ.Client` 7.0.0+ has native support for traces. | +| [Kafka](https://www.nuget.org/packages/Confluent.Kafka) | | | | +| [NServiceBus](https://docs.particular.net/nservicebus/) | Yes | Yes | | +| [MassTransit](https://masstransit-project.com/) | Yes | | | diff --git a/docs/instrumentations/java/java.mdx b/docs/instrumentations/java/java.mdx index 620685660..1ce67ae81 100644 --- a/docs/instrumentations/java/java.mdx +++ b/docs/instrumentations/java/java.mdx @@ -3,7 +3,7 @@ title: "Java Native Instrumentation" sidebarTitle: "Native instrumentation" --- - Native Java Instrumentation is currently the default settings of Odigos OS. + Native Java Instrumentation is currently the default settings of Odigos open-source version. ## Supported Versions diff --git a/docs/mint.json b/docs/mint.json index 6bc2508a5..4ff543be3 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -125,6 +125,12 @@ "instrumentations/java/java", "instrumentations/java/ebpf" ] + }, + { + "group": ".NET", + "pages": [ + "instrumentations/dotnet/dotnet" + ] } ] }, diff --git a/helm/odigos/templates/crds/odigos.io_instrumentationconfigs.yaml b/helm/odigos/templates/crds/odigos.io_instrumentationconfigs.yaml index fdfd06cea..0a58751f1 100644 --- a/helm/odigos/templates/crds/odigos.io_instrumentationconfigs.yaml +++ b/helm/odigos/templates/crds/odigos.io_instrumentationconfigs.yaml @@ -462,6 +462,11 @@ spec: - unknown - ignored type: string + libCType: + enum: + - glibc + - musl + type: string otherAgent: properties: name: diff --git a/helm/odigos/templates/crds/odigos.io_instrumentedapplications.yaml b/helm/odigos/templates/crds/odigos.io_instrumentedapplications.yaml index 696bd689b..83e7156d7 100644 --- a/helm/odigos/templates/crds/odigos.io_instrumentedapplications.yaml +++ b/helm/odigos/templates/crds/odigos.io_instrumentedapplications.yaml @@ -114,6 +114,11 @@ spec: - unknown - ignored type: string + libCType: + enum: + - glibc + - musl + type: string otherAgent: properties: name: diff --git a/instrumentor/instrumentation/instrumentation.go b/instrumentor/instrumentation/instrumentation.go index 4745a06a4..f5afd09b4 100644 --- a/instrumentor/instrumentation/instrumentation.go +++ b/instrumentor/instrumentation/instrumentation.go @@ -41,6 +41,7 @@ func ApplyInstrumentationDevicesToPodTemplate(original *corev1.PodTemplateSpec, for _, container := range original.Spec.Containers { containerLanguage := getLanguageOfContainer(runtimeDetails, container.Name) containerHaveOtherAgent := getContainerOtherAgents(runtimeDetails, container.Name) + libcType := getLibCTypeOfContainer(runtimeDetails, container.Name) // By default, Odigos does not run alongside other agents. // However, if configured in the odigos-config, it can be allowed to run in parallel. @@ -70,7 +71,7 @@ func ApplyInstrumentationDevicesToPodTemplate(original *corev1.PodTemplateSpec, return fmt.Errorf("%w for language: %s, container:%s", ErrNoDefaultSDK, containerLanguage, container.Name), deviceApplied, deviceSkippedDueToOtherAgent } - instrumentationDeviceName := common.InstrumentationDeviceName(containerLanguage, otelSdk) + instrumentationDeviceName := common.InstrumentationDeviceName(containerLanguage, otelSdk, libcType) if container.Resources.Limits == nil { container.Resources.Limits = make(map[corev1.ResourceName]resource.Quantity) } @@ -174,6 +175,16 @@ func getContainerOtherAgents(instrumentation *odigosv1.InstrumentedApplication, return nil } +func getLibCTypeOfContainer(instrumentation *odigosv1.InstrumentedApplication, containerName string) *common.LibCType { + for _, l := range instrumentation.Spec.RuntimeDetails { + if l.ContainerName == containerName { + return l.LibCType + } + } + + return nil +} + // getEnvVarsOfContainer returns the env vars which are defined for the given container and are used for instrumentation purposes. // This function also returns env vars which are declared in the container build. func getEnvVarsOfContainer(instrumentation *odigosv1.InstrumentedApplication, containerName string) map[string]string { diff --git a/odiglet/Dockerfile b/odiglet/Dockerfile index e3dfa774a..8470da66d 100644 --- a/odiglet/Dockerfile +++ b/odiglet/Dockerfile @@ -72,7 +72,11 @@ RUN if [ "$TARGETARCH" = "arm64" ]; then \ RUN ARCH_SUFFIX=$(cat /tmp/arch_suffix) && \ wget https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases/download/${DOTNET_OTEL_VERSION}/opentelemetry-dotnet-instrumentation-linux-glibc-${ARCH_SUFFIX}.zip && \ unzip opentelemetry-dotnet-instrumentation-linux-glibc-${ARCH_SUFFIX}.zip && \ - rm opentelemetry-dotnet-instrumentation-linux-glibc-${ARCH_SUFFIX}.zip + rm opentelemetry-dotnet-instrumentation-linux-glibc-${ARCH_SUFFIX}.zip && \ + mv linux-$ARCH_SUFFIX linux-glibc-$ARCH_SUFFIX && \ + wget https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/releases/download/${DOTNET_OTEL_VERSION}/opentelemetry-dotnet-instrumentation-linux-musl-${ARCH_SUFFIX}.zip && \ + unzip opentelemetry-dotnet-instrumentation-linux-musl-${ARCH_SUFFIX}.zip "linux-musl-$ARCH_SUFFIX/*" -d . && \ + rm opentelemetry-dotnet-instrumentation-linux-musl-${ARCH_SUFFIX}.zip FROM --platform=$BUILDPLATFORM keyval/odiglet-base:v1.7 AS builder WORKDIR /go/src/github.com/odigos-io/odigos diff --git a/odiglet/pkg/instrumentation/instrumentlang/dotnet.go b/odiglet/pkg/instrumentation/instrumentlang/dotnet.go index f296d3d8d..a5cf0fafe 100644 --- a/odiglet/pkg/instrumentation/instrumentlang/dotnet.go +++ b/odiglet/pkg/instrumentation/instrumentlang/dotnet.go @@ -15,7 +15,7 @@ const ( profilerEndVar = "CORECLR_PROFILER" profilerId = "{918728DD-259F-4A6A-AC2B-B85E1B658318}" profilerPathEnv = "CORECLR_PROFILER_PATH" - profilerPath = "/var/odigos/dotnet/linux-%s/OpenTelemetry.AutoInstrumentation.Native.so" + profilerPath = "/var/odigos/dotnet/linux-glibc-%s/OpenTelemetry.AutoInstrumentation.Native.so" serviceNameEnv = "OTEL_SERVICE_NAME" collectorUrlEnv = "OTEL_EXPORTER_OTLP_ENDPOINT" tracerHomeEnv = "OTEL_DOTNET_AUTO_HOME" @@ -35,7 +35,7 @@ func DotNet(deviceId string, uniqueDestinationSignals map[common.ObservabilitySi Envs: map[string]string{ enableProfilingEnvVar: "1", profilerEndVar: profilerId, - profilerPathEnv: fmt.Sprintf(profilerPath, getArch()), // TODO(edenfed): Support both musl and glibc. Requires improved language detection + profilerPathEnv: fmt.Sprintf(profilerPath, getArch()), tracerHomeEnv: tracerHome, collectorUrlEnv: fmt.Sprintf("http://%s:%d", env.Current.NodeIP, consts.OTLPHttpPort), serviceNameEnv: deviceId, diff --git a/odiglet/pkg/instrumentation/lister.go b/odiglet/pkg/instrumentation/lister.go index 84cb4ae58..2eb890072 100644 --- a/odiglet/pkg/instrumentation/lister.go +++ b/odiglet/pkg/instrumentation/lister.go @@ -3,6 +3,11 @@ package instrumentation import ( "context" + odigosclientset "github.com/odigos-io/odigos/api/generated/odigos/clientset/versioned" + "k8s.io/client-go/rest" + + "github.com/odigos-io/odigos/procdiscovery/pkg/libc" + "github.com/kubevirt/device-plugin-manager/pkg/dpm" "github.com/odigos-io/odigos/common" "github.com/odigos-io/odigos/odiglet/pkg/env" @@ -49,14 +54,29 @@ func NewLister(ctx context.Context, clientset *kubernetes.Clientset, otelSdksLsf isEbpfSupported := env.Current.IsEBPFSupported() + cfg, err := rest.InClusterConfig() + if err != nil { + log.Logger.Error(err, "Failed to init Kubernetes API client") + } + odigosKubeClient, err := odigosclientset.NewForConfig(cfg) + if err != nil { + log.Logger.Error(err, "Failed to init odigos client") + } + availablePlugins := map[string]dpm.PluginInterface{} for lang, otelSdkLsfMap := range otelSdksLsf { for otelSdk, lsf := range otelSdkLsfMap { if otelSdk.SdkType == common.EbpfOtelSdkType && !isEbpfSupported { continue } - pluginName := common.InstrumentationPluginName(lang, otelSdk) - availablePlugins[pluginName] = NewPlugin(maxPods, lsf) + pluginName := common.InstrumentationPluginName(lang, otelSdk, nil) + availablePlugins[pluginName] = NewPlugin(maxPods, lsf, odigosKubeClient) + + if libc.ShouldInspectForLanguage(lang) { + musl := common.Musl + pluginNameMusl := common.InstrumentationPluginName(lang, otelSdk, &musl) + availablePlugins[pluginNameMusl] = NewMuslPlugin(lang, maxPods, lsf, odigosKubeClient) + } } } diff --git a/odiglet/pkg/instrumentation/plugin.go b/odiglet/pkg/instrumentation/plugin.go index 699d5e7e4..1c3d3a89b 100644 --- a/odiglet/pkg/instrumentation/plugin.go +++ b/odiglet/pkg/instrumentation/plugin.go @@ -4,6 +4,8 @@ import ( "context" "errors" + "github.com/odigos-io/odigos/procdiscovery/pkg/libc" + "github.com/kubevirt/device-plugin-manager/pkg/dpm" odigosclientset "github.com/odigos-io/odigos/api/generated/odigos/clientset/versioned" "github.com/odigos-io/odigos/common" @@ -13,7 +15,6 @@ import ( "github.com/odigos-io/odigos/odiglet/pkg/log" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/rest" "k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1" ) @@ -26,18 +27,9 @@ type plugin struct { odigosKubeClient *odigosclientset.Clientset } -func NewPlugin(maxPods int64, lsf LangSpecificFunc) dpm.PluginInterface { +func NewPlugin(maxPods int64, lsf LangSpecificFunc, odigosKubeClient *odigosclientset.Clientset) dpm.PluginInterface { idManager := devices.NewIDManager(maxPods) - cfg, err := rest.InClusterConfig() - if err != nil { - log.Logger.Error(err, "Failed to init Kubernetes API client") - } - odigosKubeClient, err := odigosclientset.NewForConfig(cfg) - if err != nil { - log.Logger.Error(err, "Failed to init odigos client") - } - return &plugin{ idsManager: idManager, stopCh: make(chan struct{}), @@ -46,6 +38,16 @@ func NewPlugin(maxPods int64, lsf LangSpecificFunc) dpm.PluginInterface { } } +func NewMuslPlugin(lang common.ProgrammingLanguage, maxPods int64, lsf LangSpecificFunc, odigosKubeClient *odigosclientset.Clientset) dpm.PluginInterface { + wrappedLsf := func(deviceId string, uniqueDestinationSignals map[common.ObservabilitySignal]struct{}) *v1beta1.ContainerAllocateResponse { + res := lsf(deviceId, uniqueDestinationSignals) + libc.ModifyEnvVarsForMusl(lang, res.Envs) + return res + } + + return NewPlugin(maxPods, wrappedLsf, odigosKubeClient) +} + func (p *plugin) GetDevicePluginOptions(ctx context.Context, empty *v1beta1.Empty) (*v1beta1.DevicePluginOptions, error) { return &v1beta1.DevicePluginOptions{ PreStartRequired: false, diff --git a/odiglet/pkg/kube/runtime_details/inspection.go b/odiglet/pkg/kube/runtime_details/inspection.go index d0772de50..afb33d745 100644 --- a/odiglet/pkg/kube/runtime_details/inspection.go +++ b/odiglet/pkg/kube/runtime_details/inspection.go @@ -6,6 +6,8 @@ import ( "errors" "strings" + "github.com/odigos-io/odigos/procdiscovery/pkg/libc" + procdiscovery "github.com/odigos-io/odigos/procdiscovery/pkg/process" "github.com/odigos-io/odigos/odiglet/pkg/process" @@ -109,6 +111,7 @@ func runtimeInspection(pods []corev1.Pod, ignoredContainers []string) ([]odigosv envs := make([]odigosv1.EnvVar, 0) var detectedAgent *odigosv1.OtherAgent + var libcType *common.LibCType if inspectProc == nil { log.Logger.V(0).Info("unable to detect language for any process", "pod", pod.Name, "container", container.Name, "namespace", pod.Namespace) @@ -137,6 +140,16 @@ func runtimeInspection(pods []corev1.Pod, ignoredContainers []string) ([]odigosv detectedAgent = &odigosv1.OtherAgent{Name: otherAgentName} } } + + // Inspecting libc type is expensive and not relevant for all languages + if libc.ShouldInspectForLanguage(programLanguageDetails.Language) { + typeFound, err := libc.InspectType(inspectProc) + if err == nil { + libcType = typeFound + } else { + log.Logger.Error(err, "error inspecting libc type", "pod", pod.Name, "container", container.Name, "namespace", pod.Namespace) + } + } } var runtimeVersion string @@ -150,6 +163,7 @@ func runtimeInspection(pods []corev1.Pod, ignoredContainers []string) ([]odigosv RuntimeVersion: runtimeVersion, EnvVars: envs, OtherAgent: detectedAgent, + LibCType: libcType, } } } diff --git a/procdiscovery/pkg/inspectors/dotnet/dotnet.go b/procdiscovery/pkg/inspectors/dotnet/dotnet.go index b58724773..e10cfaa59 100644 --- a/procdiscovery/pkg/inspectors/dotnet/dotnet.go +++ b/procdiscovery/pkg/inspectors/dotnet/dotnet.go @@ -1,8 +1,10 @@ package dotnet import ( - "fmt" + "bufio" "os" + "path/filepath" + "strconv" "strings" "github.com/odigos-io/odigos/common" @@ -11,16 +13,19 @@ import ( type DotnetInspector struct{} -const ( - aspnet = "ASPNET" - dotnet = "DOTNET" -) - func (d *DotnetInspector) Inspect(p *process.Details) (common.ProgrammingLanguage, bool) { - data, err := os.ReadFile(fmt.Sprintf("/proc/%d/environ", p.ProcessID)) - if err == nil { - environ := string(data) - if strings.Contains(environ, aspnet) || strings.Contains(environ, dotnet) { + mapsPath := filepath.Join("/proc", strconv.Itoa(p.ProcessID), "maps") + f, err := os.Open(mapsPath) + if err != nil { + return "", false + } + defer f.Close() + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + // Check if the .NET core runtime library is present + if strings.Contains(line, "libcoreclr.so") { return common.DotNetProgrammingLanguage, true } } diff --git a/procdiscovery/pkg/libc/utils.go b/procdiscovery/pkg/libc/utils.go new file mode 100644 index 000000000..bffc12e14 --- /dev/null +++ b/procdiscovery/pkg/libc/utils.go @@ -0,0 +1,69 @@ +package libc + +import ( + "debug/elf" + "errors" + "fmt" + "strings" + + "github.com/odigos-io/odigos/common" + "github.com/odigos-io/odigos/procdiscovery/pkg/process" +) + +// ShouldInspectForLanguage returns true if we should inspect libc type for the given language +// Currently, we only inspect for .NET +func ShouldInspectForLanguage(lang common.ProgrammingLanguage) bool { + return lang == common.DotNetProgrammingLanguage +} + +// ModifyEnvVarsForMusl modifies the environment variables for the given language if musl libc is detected +func ModifyEnvVarsForMusl(lang common.ProgrammingLanguage, envs map[string]string) map[string]string { + if envs == nil { + return nil + } + + if !ShouldInspectForLanguage(lang) { + return envs + } + + if lang == common.DotNetProgrammingLanguage { + val, ok := envs["CORECLR_PROFILER_PATH"] + if ok { + envs["CORECLR_PROFILER_PATH"] = strings.Replace(val, "linux-glibc", "linux-musl", 1) + } + } + + return envs +} + +// InspectType inspects the given process for libc type +func InspectType(process *process.Details) (*common.LibCType, error) { + f, err := elf.Open(fmt.Sprintf("/proc/%d/exe", process.ProcessID)) + if err != nil { + return nil, err + } + + defer f.Close() + for _, prog := range f.Progs { + if prog.Type == elf.PT_INTERP { + interp := make([]byte, prog.Filesz) + _, err := prog.ReadAt(interp, 0) + if err != nil { + return nil, err + } + + // Check the interpreter path + interpPath := strings.Trim(string(interp), "\x00") + if strings.Contains(interpPath, "musl") { + musl := common.Musl + return &musl, nil + } else if strings.Contains(interpPath, "ld-linux") { + glibc := common.Glibc + return &glibc, nil + } + return nil, errors.New("unknown libc type") + } + } + + return nil, errors.New("unknown libc type") +} diff --git a/tests/e2e/workload-lifecycle/01-assert-apps-installed.yaml b/tests/e2e/workload-lifecycle/01-assert-apps-installed.yaml index 35b3666b4..a5cca08bc 100644 --- a/tests/e2e/workload-lifecycle/01-assert-apps-installed.yaml +++ b/tests/e2e/workload-lifecycle/01-assert-apps-installed.yaml @@ -272,4 +272,17 @@ status: restartCount: 0 started: true phase: Running ---- \ No newline at end of file +--- +apiVersion: v1 +kind: Pod +metadata: + labels: + app: dotnet-musl + namespace: default +status: + containerStatuses: + - name: dotnet-musl + ready: true + restartCount: 0 + started: true + phase: Running \ No newline at end of file diff --git a/tests/e2e/workload-lifecycle/01-assert-runtime-detected.yaml b/tests/e2e/workload-lifecycle/01-assert-runtime-detected.yaml index bf0b38a33..4750d0ba3 100644 --- a/tests/e2e/workload-lifecycle/01-assert-runtime-detected.yaml +++ b/tests/e2e/workload-lifecycle/01-assert-runtime-detected.yaml @@ -319,4 +319,21 @@ spec: runtimeDetails: - containerName: python-not-supported language: python - runtimeVersion: 3.6.15 \ No newline at end of file + runtimeVersion: 3.6.15 +--- +apiVersion: odigos.io/v1alpha1 +kind: InstrumentedApplication +metadata: + name: deployment-dotnet-musl + namespace: default + ownerReferences: + - apiVersion: apps/v1 + blockOwnerDeletion: true + controller: true + kind: Deployment + name: dotnet-musl +spec: + runtimeDetails: + - containerName: dotnet-musl + language: dotnet + libCType: musl \ No newline at end of file diff --git a/tests/e2e/workload-lifecycle/01-assert-workloads.yaml b/tests/e2e/workload-lifecycle/01-assert-workloads.yaml index be4488f08..47d89aaa9 100644 --- a/tests/e2e/workload-lifecycle/01-assert-workloads.yaml +++ b/tests/e2e/workload-lifecycle/01-assert-workloads.yaml @@ -541,6 +541,35 @@ spec: resources: limits: instrumentation.odigos.io/python-native-community: "1" +status: + availableReplicas: 1 + observedGeneration: 2 # the deployment spec changed when odigos resource was added + readyReplicas: 1 + replicas: 1 + updatedReplicas: 1 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + deployment.kubernetes.io/revision: "2" # the deployment spec changed when odigos resource was added + generation: 2 # the deployment spec changed when odigos resource was added + labels: + app: dotnet-musl + name: dotnet-musl + namespace: default +spec: + selector: + matchLabels: + app: dotnet-musl + template: + spec: + containers: + - image: dotnet-musl:v0.0.1 + name: dotnet-musl + resources: + limits: + instrumentation.odigos.io/musl-dotnet-native-community: "1" status: availableReplicas: 1 observedGeneration: 2 # the deployment spec changed when odigos resource was added diff --git a/tests/e2e/workload-lifecycle/01-generate-traffic.yaml b/tests/e2e/workload-lifecycle/01-generate-traffic.yaml index 5aa7bd7af..5b3cf2499 100644 --- a/tests/e2e/workload-lifecycle/01-generate-traffic.yaml +++ b/tests/e2e/workload-lifecycle/01-generate-traffic.yaml @@ -45,3 +45,5 @@ spec: curl -s --fail http://python-latest-version:3000/insert-random/ curl -s --fail http://python-min-version:3000/insert-random/ curl -s --fail http://python-not-supported:3000/insert-random/ + + curl -s --fail http://dotnet-musl:8080 \ No newline at end of file diff --git a/tests/e2e/workload-lifecycle/01-install-test-apps.yaml b/tests/e2e/workload-lifecycle/01-install-test-apps.yaml index c91317dfb..12af6d787 100644 --- a/tests/e2e/workload-lifecycle/01-install-test-apps.yaml +++ b/tests/e2e/workload-lifecycle/01-install-test-apps.yaml @@ -714,4 +714,42 @@ spec: ports: - protocol: TCP port: 3000 - targetPort: 8000 \ No newline at end of file + targetPort: 8000 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dotnet-musl + namespace: default + labels: + app: dotnet-musl +spec: + selector: + matchLabels: + app: dotnet-musl + template: + metadata: + labels: + app: dotnet-musl + spec: + containers: + - name: dotnet-musl + image: dotnet-musl:v0.0.1 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 + readinessProbe: + tcpSocket: + port: 8080 +--- +kind: Service +apiVersion: v1 +metadata: + name: dotnet-musl + namespace: default +spec: + selector: + app: dotnet-musl + ports: + - protocol: TCP + port: 8080 \ No newline at end of file diff --git a/tests/e2e/workload-lifecycle/02-assert-workload-update.yaml b/tests/e2e/workload-lifecycle/02-assert-workload-update.yaml index 345692fb7..2e6b0fc1d 100644 --- a/tests/e2e/workload-lifecycle/02-assert-workload-update.yaml +++ b/tests/e2e/workload-lifecycle/02-assert-workload-update.yaml @@ -481,4 +481,39 @@ status: observedGeneration: 2 readyReplicas: 1 replicas: 1 + updatedReplicas: 1 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + generation: 4 + name: dotnet-musl + namespace: default + labels: + app: dotnet-musl +spec: + selector: + matchLabels: + app: dotnet-musl + template: + metadata: + labels: + app: dotnet-musl + annotations: + odigos-test-step: "2" + spec: + containers: + - name: dotnet-musl + image: dotnet-musl:v0.0.1 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 + readinessProbe: + tcpSocket: + port: 8080 +status: + availableReplicas: 1 + observedGeneration: 4 + readyReplicas: 1 + replicas: 1 updatedReplicas: 1 \ No newline at end of file diff --git a/tests/e2e/workload-lifecycle/02-update-workload-manifests.yaml b/tests/e2e/workload-lifecycle/02-update-workload-manifests.yaml index 062681ba4..f3ea891b5 100644 --- a/tests/e2e/workload-lifecycle/02-update-workload-manifests.yaml +++ b/tests/e2e/workload-lifecycle/02-update-workload-manifests.yaml @@ -526,3 +526,30 @@ spec: failureThreshold: 3 successThreshold: 1 --- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dotnet-musl + namespace: default + labels: + app: dotnet-musl +spec: + selector: + matchLabels: + app: dotnet-musl + template: + metadata: + labels: + app: dotnet-musl + annotations: + odigos-test-step: "2" + spec: + containers: + - name: dotnet-musl + image: dotnet-musl:v0.0.1 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 + readinessProbe: + tcpSocket: + port: 8080 \ No newline at end of file diff --git a/tests/e2e/workload-lifecycle/03-wait-for-trace.yaml b/tests/e2e/workload-lifecycle/03-wait-for-trace.yaml index ab535094a..d8f63fa1f 100644 --- a/tests/e2e/workload-lifecycle/03-wait-for-trace.yaml +++ b/tests/e2e/workload-lifecycle/03-wait-for-trace.yaml @@ -4,4 +4,4 @@ description: This test waits for a trace that is generated from the successful i query: | { resource.k8s.cluster.name = "e2e-test-cluster" } expected: - count: 13 + count: 14 diff --git a/tests/e2e/workload-lifecycle/chainsaw-test.yaml b/tests/e2e/workload-lifecycle/chainsaw-test.yaml index acdd99b97..a4d33eacc 100644 --- a/tests/e2e/workload-lifecycle/chainsaw-test.yaml +++ b/tests/e2e/workload-lifecycle/chainsaw-test.yaml @@ -48,7 +48,9 @@ spec: kind load docker-image python-not-supported:v0.0.1 docker build -t python-min-version:v0.0.1 -f services/python-http-server/Dockerfile.python-min-version services/python-http-server kind load docker-image python-min-version:v0.0.1 - + + docker build -t dotnet-musl:v0.0.1 -f services/dotnet-musl-server/Dockerfile services/dotnet-musl-server + kind load docker-image dotnet-musl:v0.0.1 - name: Prepare destination try: - script: diff --git a/tests/e2e/workload-lifecycle/services/dotnet-musl-server/Dockerfile b/tests/e2e/workload-lifecycle/services/dotnet-musl-server/Dockerfile new file mode 100644 index 000000000..e0186e467 --- /dev/null +++ b/tests/e2e/workload-lifecycle/services/dotnet-musl-server/Dockerfile @@ -0,0 +1,11 @@ +FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build +WORKDIR /src +COPY . . +RUN dotnet restore +RUN dotnet publish -c Release -o /app + +FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine +WORKDIR /app +COPY --from=build /app . +EXPOSE 8080 +ENTRYPOINT ["dotnet", "dotnet-musl-server.dll"] diff --git a/tests/e2e/workload-lifecycle/services/dotnet-musl-server/Program.cs b/tests/e2e/workload-lifecycle/services/dotnet-musl-server/Program.cs new file mode 100644 index 000000000..c2dc41dbe --- /dev/null +++ b/tests/e2e/workload-lifecycle/services/dotnet-musl-server/Program.cs @@ -0,0 +1,6 @@ +var builder = WebApplication.CreateBuilder(args); +var app = builder.Build(); + +app.MapGet("/", () => "Hello World!"); + +app.Run("http://0.0.0.0:8080"); diff --git a/tests/e2e/workload-lifecycle/services/dotnet-musl-server/dotnet-musl-server.csproj b/tests/e2e/workload-lifecycle/services/dotnet-musl-server/dotnet-musl-server.csproj new file mode 100644 index 000000000..97c4f0efc --- /dev/null +++ b/tests/e2e/workload-lifecycle/services/dotnet-musl-server/dotnet-musl-server.csproj @@ -0,0 +1,10 @@ + + + + net8.0 + dotnet-musl-server + enable + enable + + + diff --git a/tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/dotnet-musl-server.csproj.nuget.dgspec.json b/tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/dotnet-musl-server.csproj.nuget.dgspec.json new file mode 100644 index 000000000..75ffb17b5 --- /dev/null +++ b/tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/dotnet-musl-server.csproj.nuget.dgspec.json @@ -0,0 +1,69 @@ +{ + "format": 1, + "restore": { + "/app/dotnet-musl-server.csproj": {} + }, + "projects": { + "/app/dotnet-musl-server.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/app/dotnet-musl-server.csproj", + "projectName": "dotnet-musl-server", + "projectPath": "/app/dotnet-musl-server.csproj", + "packagesPath": "/root/.nuget/packages/", + "outputPath": "/app/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/root/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "direct" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.AspNetCore.App": { + "privateAssets": "none" + }, + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/share/dotnet/sdk/8.0.404/PortableRuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/dotnet-musl-server.csproj.nuget.g.props b/tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/dotnet-musl-server.csproj.nuget.g.props new file mode 100644 index 000000000..112d2bbea --- /dev/null +++ b/tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/dotnet-musl-server.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /root/.nuget/packages/ + /root/.nuget/packages/ + PackageReference + 6.11.1 + + + + + \ No newline at end of file diff --git a/tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/dotnet-musl-server.csproj.nuget.g.targets b/tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/dotnet-musl-server.csproj.nuget.g.targets new file mode 100644 index 000000000..3dc06ef3c --- /dev/null +++ b/tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/dotnet-musl-server.csproj.nuget.g.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/project.assets.json b/tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/project.assets.json new file mode 100644 index 000000000..f72c9a95a --- /dev/null +++ b/tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/project.assets.json @@ -0,0 +1,74 @@ +{ + "version": 3, + "targets": { + "net8.0": {} + }, + "libraries": {}, + "projectFileDependencyGroups": { + "net8.0": [] + }, + "packageFolders": { + "/root/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/app/dotnet-musl-server.csproj", + "projectName": "dotnet-musl-server", + "projectPath": "/app/dotnet-musl-server.csproj", + "packagesPath": "/root/.nuget/packages/", + "outputPath": "/app/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/root/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "direct" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.AspNetCore.App": { + "privateAssets": "none" + }, + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/share/dotnet/sdk/8.0.404/PortableRuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/project.nuget.cache b/tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/project.nuget.cache new file mode 100644 index 000000000..220ca9bf3 --- /dev/null +++ b/tests/e2e/workload-lifecycle/services/dotnet-musl-server/obj/project.nuget.cache @@ -0,0 +1,8 @@ +{ + "version": 2, + "dgSpecHash": "9NJOUczYkvg=", + "success": true, + "projectFilePath": "/app/dotnet-musl-server.csproj", + "expectedPackageFiles": [], + "logs": [] +} \ No newline at end of file