@@ -24,6 +24,7 @@ import (
2424 "k8s.io/apimachinery/pkg/runtime"
2525 "k8s.io/apimachinery/pkg/types"
2626 "k8s.io/apimachinery/pkg/util/intstr"
27+ "k8s.io/apimachinery/pkg/version"
2728 "k8s.io/client-go/tools/record"
2829 "k8s.io/utils/ptr"
2930 "sigs.k8s.io/controller-runtime/pkg/client"
@@ -37,8 +38,10 @@ import (
3738 "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1"
3839 "github.com/DataDog/datadog-operator/internal/controller/datadogagent/common"
3940 "github.com/DataDog/datadog-operator/internal/controller/datadogagent/experimental"
41+ "github.com/DataDog/datadog-operator/internal/controller/datadogagent/store"
4042 agenttestutils "github.com/DataDog/datadog-operator/internal/controller/datadogagent/testutils"
4143 "github.com/DataDog/datadog-operator/internal/controller/datadogagentinternal"
44+ "github.com/DataDog/datadog-operator/pkg/agentprofile"
4245 "github.com/DataDog/datadog-operator/pkg/condition"
4346 "github.com/DataDog/datadog-operator/pkg/constants"
4447 "github.com/DataDog/datadog-operator/pkg/controller/utils/comparison"
@@ -62,6 +65,7 @@ type testCase struct {
6265 profilesEnabled bool // For DDAI tests
6366 introspectionEnabled bool // For introspection tests
6467 clusterProvider string // For control plane monitoring tests: provider returned by the injected detector
68+ platformInfo * kubernetes.PlatformInfo
6569}
6670
6771// ddaiReconcilerOptionsFromDDA mirrors setup.go wiring so DDAI tests behave like production
@@ -75,6 +79,13 @@ func ddaiReconcilerOptionsFromDDA(opts ReconcilerOptions) datadogagentinternal.R
7579 }
7680}
7781
82+ func platformInfoForTest (tt testCase ) kubernetes.PlatformInfo {
83+ if tt .platformInfo != nil {
84+ return * tt .platformInfo
85+ }
86+ return kubernetes.PlatformInfo {}
87+ }
88+
7889// runTestCases runs test cases
7990func runTestCases (t * testing.T , tests []testCase , testFunc func (t * testing.T , tt testCase , opts ReconcilerOptions )) {
8091 for _ , tt := range tests {
@@ -111,12 +122,13 @@ func runDDAReconcilerTest(t *testing.T, tt testCase, opts ReconcilerOptions) {
111122 forwarders := dummyManager {}
112123
113124 c := buildClient (t , tt , s )
125+ platformInfo := platformInfoForTest (tt )
114126
115127 // Create reconciler
116128 r := & Reconciler {
117129 client : c ,
118130 scheme : s ,
119- platformInfo : kubernetes. PlatformInfo {} ,
131+ platformInfo : platformInfo ,
120132 recorder : recorder ,
121133 log : logf .Log .WithName (tt .name ),
122134 forwarders : forwarders ,
@@ -127,7 +139,7 @@ func runDDAReconcilerTest(t *testing.T, tt testCase, opts ReconcilerOptions) {
127139 ri := datadogagentinternal .NewReconciler (
128140 ddaiReconcilerOptionsFromDDA (opts ),
129141 c ,
130- kubernetes. PlatformInfo {} ,
142+ platformInfo ,
131143 s ,
132144 recorder ,
133145 forwarders )
@@ -184,12 +196,13 @@ func runFullReconcilerTest(t *testing.T, tt testCase, opts ReconcilerOptions) {
184196 forwarders := dummyManager {}
185197
186198 c := buildClient (t , tt , s )
199+ platformInfo := platformInfoForTest (tt )
187200
188201 // Create reconciler
189202 r := & Reconciler {
190203 client : c ,
191204 scheme : s ,
192- platformInfo : kubernetes. PlatformInfo {} ,
205+ platformInfo : platformInfo ,
193206 recorder : recorder ,
194207 log : logf .Log .WithName (tt .name ),
195208 forwarders : forwarders ,
@@ -200,7 +213,7 @@ func runFullReconcilerTest(t *testing.T, tt testCase, opts ReconcilerOptions) {
200213 ri := datadogagentinternal .NewReconciler (
201214 ddaiReconcilerOptionsFromDDA (opts ),
202215 c ,
203- kubernetes. PlatformInfo {} ,
216+ platformInfo ,
204217 s ,
205218 recorder ,
206219 forwarders )
@@ -1834,6 +1847,157 @@ func Test_COSProviderOverrides(t *testing.T) {
18341847 runTestCases (t , tests , runFullReconcilerTest )
18351848}
18361849
1850+ func Test_ProfileAPMOverrideAddsDDAOwnedLocalAgentServicePort (t * testing.T ) {
1851+ const resourcesName = "foo"
1852+ const resourcesNamespace = "bar"
1853+ const profileName = "apm-profile"
1854+ defaultRequeueDuration := 15 * time .Second
1855+
1856+ dda := testutils .NewInitializedDatadogAgentBuilder (resourcesNamespace , resourcesName ).
1857+ WithAPMEnabled (false ).
1858+ BuildWithDefaults ()
1859+ localAgentServiceName := constants .GetLocalAgentServiceName (resourcesName , & dda .Spec )
1860+ platformInfo := kubernetes .NewPlatformInfoFromVersionMaps (& version.Info {GitVersion : "1.32.0" }, nil , nil )
1861+
1862+ newAPMProfile := func (name string , apm * v2alpha1.APMFeatureConfig ) * v1alpha1.DatadogAgentProfile {
1863+ return & v1alpha1.DatadogAgentProfile {
1864+ ObjectMeta : metav1.ObjectMeta {
1865+ Name : name ,
1866+ Namespace : resourcesNamespace ,
1867+ },
1868+ Spec : v1alpha1.DatadogAgentProfileSpec {
1869+ ProfileAffinity : & v1alpha1.ProfileAffinity {
1870+ ProfileNodeAffinity : []corev1.NodeSelectorRequirement {
1871+ {
1872+ Key : "profile" ,
1873+ Operator : corev1 .NodeSelectorOpIn ,
1874+ Values : []string {name },
1875+ },
1876+ },
1877+ },
1878+ Config : & v2alpha1.DatadogAgentSpec {
1879+ Features : & v2alpha1.DatadogFeatures {
1880+ APM : apm ,
1881+ },
1882+ },
1883+ },
1884+ }
1885+ }
1886+ profile := newAPMProfile (profileName , & v2alpha1.APMFeatureConfig {
1887+ Enabled : ptr .To (true ),
1888+ })
1889+ conflictingProfileA := newAPMProfile ("apm-profile-a" , & v2alpha1.APMFeatureConfig {
1890+ Enabled : ptr .To (true ),
1891+ HostPortConfig : & v2alpha1.HostPortConfig {
1892+ Enabled : ptr .To (true ),
1893+ Port : ptr.To [int32 ](8126 ),
1894+ },
1895+ })
1896+ conflictingProfileB := newAPMProfile ("apm-profile-b" , & v2alpha1.APMFeatureConfig {
1897+ Enabled : ptr .To (true ),
1898+ HostPortConfig : & v2alpha1.HostPortConfig {
1899+ Enabled : ptr .To (true ),
1900+ Port : ptr.To [int32 ](9126 ),
1901+ },
1902+ })
1903+
1904+ tests := []testCase {
1905+ {
1906+ name : "profile APM override adds trace port to DDA-owned local Agent Service" ,
1907+ clientBuilder : fake .NewClientBuilder ().
1908+ WithStatusSubresource (& v2alpha1.DatadogAgent {}, & v1alpha1.DatadogAgentProfile {}, & v1alpha1.DatadogAgentInternal {}).
1909+ WithObjects (profile ),
1910+ loadFunc : func (c client.Client ) * v2alpha1.DatadogAgent {
1911+ ddaCopy := dda .DeepCopy ()
1912+ _ = c .Create (context .TODO (), ddaCopy )
1913+ return ddaCopy
1914+ },
1915+ profilesEnabled : true ,
1916+ platformInfo : & platformInfo ,
1917+ want : reconcile.Result {RequeueAfter : defaultRequeueDuration },
1918+ wantErr : false ,
1919+ wantFunc : func (t * testing.T , c client.Client ) {
1920+ service := & corev1.Service {}
1921+ err := c .Get (context .TODO (), types.NamespacedName {Namespace : resourcesNamespace , Name : localAgentServiceName }, service )
1922+ assert .NoError (t , err )
1923+ assert .Equal (t , "true" , service .Labels [store .ManagedByDDAControllerLabelKey ])
1924+
1925+ apmPort := findServicePortByName (service .Spec .Ports , constants .DefaultApmPortName )
1926+ assert .NotNil (t , apmPort )
1927+ assert .Equal (t , corev1 .ProtocolTCP , apmPort .Protocol )
1928+ assert .Equal (t , int32 (constants .DefaultApmPort ), apmPort .Port )
1929+ assert .Equal (t , intstr .FromInt (int (constants .DefaultApmPort )), apmPort .TargetPort )
1930+
1931+ defaultDDAI := & v1alpha1.DatadogAgentInternal {}
1932+ err = c .Get (context .TODO (), types.NamespacedName {Namespace : resourcesNamespace , Name : resourcesName }, defaultDDAI )
1933+ assert .NoError (t , err )
1934+ assert .False (t , ptr .Deref (defaultDDAI .Spec .Features .APM .Enabled , true ))
1935+
1936+ profileDDAI := & v1alpha1.DatadogAgentInternal {}
1937+ err = c .Get (context .TODO (), types.NamespacedName {Namespace : resourcesNamespace , Name : profileName }, profileDDAI )
1938+ assert .NoError (t , err )
1939+ assert .True (t , ptr .Deref (profileDDAI .Spec .Features .APM .Enabled , false ))
1940+ },
1941+ },
1942+ {
1943+ name : "conflicting profile APM override rejects conflicting profile and reconciles accepted profile" ,
1944+ clientBuilder : fake .NewClientBuilder ().
1945+ WithStatusSubresource (& v2alpha1.DatadogAgent {}, & v1alpha1.DatadogAgentProfile {}, & v1alpha1.DatadogAgentInternal {}).
1946+ WithObjects (conflictingProfileA , conflictingProfileB ),
1947+ loadFunc : func (c client.Client ) * v2alpha1.DatadogAgent {
1948+ ddaCopy := dda .DeepCopy ()
1949+ _ = c .Create (context .TODO (), ddaCopy )
1950+ return ddaCopy
1951+ },
1952+ profilesEnabled : true ,
1953+ platformInfo : & platformInfo ,
1954+ want : reconcile.Result {RequeueAfter : defaultRequeueDuration },
1955+ wantErr : false ,
1956+ wantFunc : func (t * testing.T , c client.Client ) {
1957+ service := & corev1.Service {}
1958+ err := c .Get (context .TODO (), types.NamespacedName {Namespace : resourcesNamespace , Name : localAgentServiceName }, service )
1959+ assert .NoError (t , err )
1960+ assert .Equal (t , "true" , service .Labels [store .ManagedByDDAControllerLabelKey ])
1961+
1962+ apmPort := findServicePortByName (service .Spec .Ports , constants .DefaultApmPortName )
1963+ assert .NotNil (t , apmPort )
1964+ assert .Equal (t , int32 (8126 ), apmPort .Port )
1965+ assert .Equal (t , intstr .FromInt (int (constants .DefaultApmPort )), apmPort .TargetPort )
1966+
1967+ appliedProfile := & v1alpha1.DatadogAgentProfile {}
1968+ err = c .Get (context .TODO (), types.NamespacedName {Namespace : resourcesNamespace , Name : "apm-profile-a" }, appliedProfile )
1969+ assert .NoError (t , err )
1970+ assert .Equal (t , metav1 .ConditionTrue , appliedProfile .Status .Applied )
1971+
1972+ conflictingProfile := & v1alpha1.DatadogAgentProfile {}
1973+ err = c .Get (context .TODO (), types.NamespacedName {Namespace : resourcesNamespace , Name : "apm-profile-b" }, conflictingProfile )
1974+ assert .NoError (t , err )
1975+ assert .Equal (t , metav1 .ConditionFalse , conflictingProfile .Status .Applied )
1976+ assert .Contains (t , profileConditionMessage (conflictingProfile .Status .Conditions , agentprofile .AppliedConditionType ), "port \" traceport\" conflicts" )
1977+
1978+ appliedDDAI := & v1alpha1.DatadogAgentInternal {}
1979+ err = c .Get (context .TODO (), types.NamespacedName {Namespace : resourcesNamespace , Name : "apm-profile-a" }, appliedDDAI )
1980+ assert .NoError (t , err )
1981+
1982+ conflictingDDAI := & v1alpha1.DatadogAgentInternal {}
1983+ err = c .Get (context .TODO (), types.NamespacedName {Namespace : resourcesNamespace , Name : "apm-profile-b" }, conflictingDDAI )
1984+ assert .True (t , apierrors .IsNotFound (err ), "conflicting profile DDAI should not be rendered" )
1985+ },
1986+ },
1987+ }
1988+
1989+ runTestCases (t , tests , runFullReconcilerTest )
1990+ }
1991+
1992+ func profileConditionMessage (conditions []metav1.Condition , conditionType string ) string {
1993+ for _ , condition := range conditions {
1994+ if condition .Type == conditionType {
1995+ return condition .Message
1996+ }
1997+ }
1998+ return ""
1999+ }
2000+
18372001func verifyDaemonsetContainers (t * testing.T , c client.Client , resourcesNamespace , dsName string , expectedContainers []string ) {
18382002 ds := & appsv1.DaemonSet {}
18392003 err := c .Get (context .TODO (), types.NamespacedName {Namespace : resourcesNamespace , Name : dsName }, ds )
0 commit comments