@@ -14,6 +14,7 @@ import (
1414 "time"
1515
1616 apicommon "github.com/DataDog/datadog-operator/api/datadoghq/common"
17+ "github.com/DataDog/datadog-operator/api/datadoghq/v1alpha1"
1718 "github.com/DataDog/datadog-operator/api/datadoghq/v2alpha1"
1819 apiutils "github.com/DataDog/datadog-operator/api/utils"
1920 common "github.com/DataDog/datadog-operator/internal/controller/datadogagent/common"
@@ -1550,3 +1551,381 @@ func verifyPDB(t *testing.T, c client.Client) error {
15501551 assert .Nil (t , ccrPDB .Spec .MinAvailable )
15511552 return nil
15521553}
1554+
1555+ func Test_DDAI_ReconcileV3 (t * testing.T ) {
1556+ const resourcesName = "foo"
1557+ const resourcesNamespace = "bar"
1558+
1559+ // Register operator types with the runtime scheme.
1560+ s := agenttestutils .TestScheme ()
1561+ // Load CRD from config folder
1562+ crd , err := getDDAICRDFromConfig (s )
1563+ assert .NoError (t , err )
1564+ eventBroadcaster := record .NewBroadcaster ()
1565+ recorder := eventBroadcaster .NewRecorder (s , corev1.EventSource {Component : "Test_DDAI_ReconcileV3" })
1566+
1567+ forwarders := dummyManager {}
1568+ logf .SetLogger (zap .New (zap .UseDevMode (true )))
1569+
1570+ defaultRequeueDuration := 15 * time .Second
1571+
1572+ dda := testutils .NewInitializedDatadogAgentBuilder (resourcesNamespace , resourcesName ).BuildWithDefaults ()
1573+
1574+ tests := []struct {
1575+ name string
1576+ profilesEnabled bool
1577+ profile * v1alpha1.DatadogAgentProfile
1578+ loadFunc func (c client.Client ) * v2alpha1.DatadogAgent
1579+ want reconcile.Result
1580+ wantErr bool
1581+ wantFunc func (t * testing.T , c client.Client ) error
1582+ }{
1583+ {
1584+ name : "[ddai] Create DDAI from minimal DDA" ,
1585+ loadFunc : func (c client.Client ) * v2alpha1.DatadogAgent {
1586+ _ = c .Create (context .TODO (), dda )
1587+ return dda
1588+ },
1589+ want : reconcile.Result {RequeueAfter : defaultRequeueDuration },
1590+ wantErr : false ,
1591+ wantFunc : func (t * testing.T , c client.Client ) error {
1592+ expectedDDAI := getBaseDDAI (dda )
1593+ expectedDDAI .Annotations = map [string ]string {
1594+ constants .MD5DDAIDeploymentAnnotationKey : "db25da8b5c8cd681d92f0049101605d6" ,
1595+ }
1596+
1597+ return verifyDDAI (t , c , []v1alpha1.DatadogAgentInternal {expectedDDAI })
1598+ },
1599+ },
1600+ {
1601+ name : "[ddai] Create DDAI from customized DDA" ,
1602+ loadFunc : func (c client.Client ) * v2alpha1.DatadogAgent {
1603+ ddaCustom := testutils .NewInitializedDatadogAgentBuilder (resourcesNamespace , resourcesName ).
1604+ WithDCAToken ("abcdefghijklmnopqrstuvwxyz" ).
1605+ WithCredentialsFromSecret ("custom-secret" , "api" , "custom-secret2" , "app" ).
1606+ WithComponentOverride (v2alpha1 .NodeAgentComponentName , v2alpha1.DatadogAgentComponentOverride {
1607+ Labels : map [string ]string {
1608+ "custom-label" : "custom-value" ,
1609+ },
1610+ }).
1611+ WithClusterChecksEnabled (true ).
1612+ WithClusterChecksUseCLCEnabled (true ).
1613+ BuildWithDefaults ()
1614+ _ = c .Create (context .TODO (), ddaCustom )
1615+ return ddaCustom
1616+ },
1617+ want : reconcile.Result {RequeueAfter : defaultRequeueDuration },
1618+ wantErr : false ,
1619+ wantFunc : func (t * testing.T , c client.Client ) error {
1620+ baseDDAI := getBaseDDAI (dda )
1621+ expectedDDAI := baseDDAI .DeepCopy ()
1622+ expectedDDAI .Annotations = map [string ]string {
1623+ constants .MD5DDAIDeploymentAnnotationKey : "ecf20e786d34265b5ad2a2e841837b55" ,
1624+ }
1625+ expectedDDAI .Spec .Features .ClusterChecks .UseClusterChecksRunners = apiutils .NewBoolPointer (true )
1626+ expectedDDAI .Spec .Global .Credentials = & v2alpha1.DatadogCredentials {
1627+ APISecret : & v2alpha1.SecretConfig {
1628+ SecretName : "custom-secret" ,
1629+ KeyName : "api" ,
1630+ },
1631+ AppSecret : & v2alpha1.SecretConfig {
1632+ SecretName : "custom-secret2" ,
1633+ KeyName : "app" ,
1634+ },
1635+ }
1636+ expectedDDAI .Spec .Global .ClusterAgentTokenSecret = & v2alpha1.SecretConfig {
1637+ SecretName : "foo-token" ,
1638+ KeyName : "token" ,
1639+ }
1640+ expectedDDAI .Spec .Override = map [v2alpha1.ComponentName ]* v2alpha1.DatadogAgentComponentOverride {
1641+ v2alpha1 .NodeAgentComponentName : {
1642+ Labels : map [string ]string {
1643+ "custom-label" : "custom-value" ,
1644+ constants .MD5AgentDeploymentProviderLabelKey : "" ,
1645+ },
1646+ Annotations : map [string ]string {
1647+ "checksum/dca-token-custom-config" : "0c85492446fadac292912bb6d5fc3efd" ,
1648+ },
1649+ },
1650+ v2alpha1 .ClusterAgentComponentName : {
1651+ Annotations : map [string ]string {
1652+ "checksum/dca-token-custom-config" : "0c85492446fadac292912bb6d5fc3efd" ,
1653+ },
1654+ },
1655+ v2alpha1 .ClusterChecksRunnerComponentName : {
1656+ Annotations : map [string ]string {
1657+ "checksum/dca-token-custom-config" : "0c85492446fadac292912bb6d5fc3efd" ,
1658+ },
1659+ },
1660+ }
1661+
1662+ return verifyDDAI (t , c , []v1alpha1.DatadogAgentInternal {* expectedDDAI })
1663+ },
1664+ },
1665+ {
1666+ name : "[ddai] Create DDAI from minimal DDA and default profile" ,
1667+ loadFunc : func (c client.Client ) * v2alpha1.DatadogAgent {
1668+ _ = c .Create (context .TODO (), dda )
1669+ return dda
1670+ },
1671+ profilesEnabled : true ,
1672+ want : reconcile.Result {RequeueAfter : defaultRequeueDuration },
1673+ wantErr : false ,
1674+ wantFunc : func (t * testing.T , c client.Client ) error {
1675+ return verifyDDAI (t , c , []v1alpha1.DatadogAgentInternal {getDefaultDDAI (dda )})
1676+ },
1677+ },
1678+ {
1679+ name : "[ddai] Create DDAI from minimal DDA and user created profile" ,
1680+ loadFunc : func (c client.Client ) * v2alpha1.DatadogAgent {
1681+ _ = c .Create (context .TODO (), dda )
1682+ return dda
1683+ },
1684+ profilesEnabled : true ,
1685+ profile : & v1alpha1.DatadogAgentProfile {
1686+ ObjectMeta : metav1.ObjectMeta {
1687+ Name : "foo-profile" ,
1688+ Namespace : resourcesNamespace ,
1689+ },
1690+ Spec : v1alpha1.DatadogAgentProfileSpec {
1691+ ProfileAffinity : & v1alpha1.ProfileAffinity {
1692+ ProfileNodeAffinity : []corev1.NodeSelectorRequirement {
1693+ {
1694+ Key : "foo" ,
1695+ Operator : corev1 .NodeSelectorOpIn ,
1696+ Values : []string {"foo-profile" },
1697+ },
1698+ },
1699+ },
1700+ Config : & v2alpha1.DatadogAgentSpec {
1701+ Override : map [v2alpha1.ComponentName ]* v2alpha1.DatadogAgentComponentOverride {
1702+ v2alpha1 .NodeAgentComponentName : {
1703+ Labels : map [string ]string {
1704+ "foo" : "bar" ,
1705+ },
1706+ },
1707+ },
1708+ },
1709+ },
1710+ },
1711+ want : reconcile.Result {RequeueAfter : defaultRequeueDuration },
1712+ wantErr : false ,
1713+ wantFunc : func (t * testing.T , c client.Client ) error {
1714+ profileDDAI := getBaseDDAI (dda )
1715+ profileDDAI .Name = "foo-profile"
1716+ profileDDAI .Annotations = map [string ]string {
1717+ constants .MD5DDAIDeploymentAnnotationKey : "74a9d7cc65524e555ad895710ab603dd" ,
1718+ }
1719+ profileDDAI .Labels [constants .ProfileLabelKey ] = "foo-profile"
1720+ profileDDAI .Spec .Override = map [v2alpha1.ComponentName ]* v2alpha1.DatadogAgentComponentOverride {
1721+ v2alpha1 .ClusterAgentComponentName : {
1722+ Disabled : apiutils .NewBoolPointer (true ),
1723+ },
1724+ v2alpha1 .ClusterChecksRunnerComponentName : {
1725+ Disabled : apiutils .NewBoolPointer (true ),
1726+ },
1727+ v2alpha1 .NodeAgentComponentName : {
1728+ Labels : map [string ]string {
1729+ constants .MD5AgentDeploymentProviderLabelKey : "" ,
1730+ "foo" : "bar" ,
1731+ constants .ProfileLabelKey : "foo-profile" ,
1732+ },
1733+ Affinity : & corev1.Affinity {
1734+ NodeAffinity : & corev1.NodeAffinity {
1735+ RequiredDuringSchedulingIgnoredDuringExecution : & corev1.NodeSelector {
1736+ NodeSelectorTerms : []corev1.NodeSelectorTerm {
1737+ {
1738+ MatchExpressions : []corev1.NodeSelectorRequirement {
1739+ {
1740+ Key : "foo" ,
1741+ Operator : corev1 .NodeSelectorOpIn ,
1742+ Values : []string {"foo-profile" },
1743+ },
1744+ {
1745+ Key : constants .ProfileLabelKey ,
1746+ Operator : corev1 .NodeSelectorOpIn ,
1747+ Values : []string {"foo-profile" },
1748+ },
1749+ },
1750+ },
1751+ },
1752+ },
1753+ },
1754+ PodAntiAffinity : & corev1.PodAntiAffinity {
1755+ RequiredDuringSchedulingIgnoredDuringExecution : []corev1.PodAffinityTerm {
1756+ {
1757+ LabelSelector : & metav1.LabelSelector {
1758+ MatchExpressions : []metav1.LabelSelectorRequirement {
1759+ {
1760+ Key : apicommon .AgentDeploymentComponentLabelKey ,
1761+ Operator : metav1 .LabelSelectorOpIn ,
1762+ Values : []string {string (apicommon .CoreAgentContainerName )},
1763+ },
1764+ },
1765+ },
1766+ TopologyKey : "kubernetes.io/hostname" ,
1767+ },
1768+ },
1769+ },
1770+ },
1771+ },
1772+ }
1773+
1774+ return verifyDDAI (t , c , []v1alpha1.DatadogAgentInternal {getDefaultDDAI (dda ), profileDDAI })
1775+ },
1776+ },
1777+ }
1778+
1779+ for _ , tt := range tests {
1780+ t .Run (tt .name , func (t * testing.T ) {
1781+ objs := []client.Object {crd }
1782+ if tt .profile != nil {
1783+ objs = append (objs , tt .profile )
1784+ }
1785+ r := & Reconciler {
1786+ client : fake .NewClientBuilder ().WithStatusSubresource (& v2alpha1.DatadogAgent {}, & v1alpha1.DatadogAgentProfile {}, & v1alpha1.DatadogAgentInternal {}).WithObjects (objs ... ).Build (),
1787+ scheme : s ,
1788+ recorder : recorder ,
1789+ log : logf .Log .WithName (tt .name ),
1790+ forwarders : forwarders ,
1791+ options : ReconcilerOptions {
1792+ DatadogAgentInternalEnabled : true ,
1793+ DatadogAgentProfileEnabled : tt .profilesEnabled ,
1794+ },
1795+ }
1796+
1797+ var dda * v2alpha1.DatadogAgent
1798+ if tt .loadFunc != nil {
1799+ dda = tt .loadFunc (r .client )
1800+ }
1801+
1802+ got , err := r .Reconcile (context .TODO (), dda )
1803+ if tt .wantErr {
1804+ assert .Error (t , err , "ReconcileDatadogAgent.Reconcile() expected an error" )
1805+ } else {
1806+ assert .NoError (t , err , "ReconcileDatadogAgent.Reconcile() unexpected error: %v" , err )
1807+ }
1808+
1809+ assert .Equal (t , tt .want , got , "ReconcileDatadogAgent.Reconcile() unexpected result" )
1810+
1811+ if tt .wantFunc != nil {
1812+ err := tt .wantFunc (t , r .client )
1813+ assert .NoError (t , err , "ReconcileDatadogAgent.Reconcile() wantFunc validation error: %v" , err )
1814+ }
1815+ })
1816+ }
1817+ }
1818+
1819+ func verifyDDAI (t * testing.T , c client.Client , expectedDDAI []v1alpha1.DatadogAgentInternal ) error {
1820+ ddaiList := v1alpha1.DatadogAgentInternalList {}
1821+ if err := c .List (context .TODO (), & ddaiList ); err != nil {
1822+ return err
1823+ }
1824+ assert .Equal (t , len (expectedDDAI ), len (ddaiList .Items ))
1825+ for i := range ddaiList .Items {
1826+ // clear managed fields
1827+ ddaiList .Items [i ].ObjectMeta .ManagedFields = nil
1828+ // type meta is only added when merging ddais
1829+ ddaiList .Items [i ].TypeMeta = metav1.TypeMeta {}
1830+ }
1831+ assert .ElementsMatch (t , expectedDDAI , ddaiList .Items )
1832+ return nil
1833+ }
1834+
1835+ func getBaseDDAI (dda * v2alpha1.DatadogAgent ) v1alpha1.DatadogAgentInternal {
1836+ expectedDDAI := v1alpha1.DatadogAgentInternal {
1837+ ObjectMeta : metav1.ObjectMeta {
1838+ Name : dda .Name ,
1839+ Namespace : dda .Namespace ,
1840+ ResourceVersion : "1" ,
1841+ Labels : map [string ]string {
1842+ apicommon .DatadogAgentNameLabelKey : dda .Name ,
1843+ },
1844+ OwnerReferences : []metav1.OwnerReference {
1845+ {
1846+ APIVersion : "datadoghq.com/v2alpha1" ,
1847+ Kind : "DatadogAgent" ,
1848+ Name : dda .Name ,
1849+ Controller : apiutils .NewBoolPointer (true ),
1850+ BlockOwnerDeletion : apiutils .NewBoolPointer (true ),
1851+ },
1852+ },
1853+ },
1854+ Spec : v2alpha1.DatadogAgentSpec {
1855+ Features : dda .Spec .Features ,
1856+ Global : dda .Spec .Global ,
1857+ Override : map [v2alpha1.ComponentName ]* v2alpha1.DatadogAgentComponentOverride {
1858+ v2alpha1 .NodeAgentComponentName : {
1859+ Labels : map [string ]string {
1860+ constants .MD5AgentDeploymentProviderLabelKey : "" ,
1861+ },
1862+ },
1863+ },
1864+ },
1865+ }
1866+
1867+ expectedDDAI .Spec .Global .Credentials = & v2alpha1.DatadogCredentials {
1868+ APISecret : & v2alpha1.SecretConfig {
1869+ SecretName : "foo-secret" ,
1870+ KeyName : "api_key" ,
1871+ },
1872+ AppSecret : & v2alpha1.SecretConfig {
1873+ SecretName : "foo-secret" ,
1874+ KeyName : "app_key" ,
1875+ },
1876+ }
1877+
1878+ expectedDDAI .Spec .Global .ClusterAgentTokenSecret = & v2alpha1.SecretConfig {
1879+ SecretName : "foo-token" ,
1880+ KeyName : "token" ,
1881+ }
1882+
1883+ return expectedDDAI
1884+ }
1885+
1886+ func getDefaultDDAI (dda * v2alpha1.DatadogAgent ) v1alpha1.DatadogAgentInternal {
1887+ expectedDDAI := getBaseDDAI (dda )
1888+ expectedDDAI .Annotations = map [string ]string {
1889+ constants .MD5DDAIDeploymentAnnotationKey : "8b985778b07536be633b3f49cb113e02" ,
1890+ }
1891+ expectedDDAI .Spec .Override = map [v2alpha1.ComponentName ]* v2alpha1.DatadogAgentComponentOverride {
1892+ v2alpha1 .NodeAgentComponentName : {
1893+ Labels : map [string ]string {
1894+ constants .MD5AgentDeploymentProviderLabelKey : "" ,
1895+ },
1896+ Affinity : & corev1.Affinity {
1897+ NodeAffinity : & corev1.NodeAffinity {
1898+ RequiredDuringSchedulingIgnoredDuringExecution : & corev1.NodeSelector {
1899+ NodeSelectorTerms : []corev1.NodeSelectorTerm {
1900+ {
1901+ MatchExpressions : []corev1.NodeSelectorRequirement {
1902+ {
1903+ Key : constants .ProfileLabelKey ,
1904+ Operator : corev1 .NodeSelectorOpDoesNotExist ,
1905+ },
1906+ },
1907+ },
1908+ },
1909+ },
1910+ },
1911+ PodAntiAffinity : & corev1.PodAntiAffinity {
1912+ RequiredDuringSchedulingIgnoredDuringExecution : []corev1.PodAffinityTerm {
1913+ {
1914+ LabelSelector : & metav1.LabelSelector {
1915+ MatchExpressions : []metav1.LabelSelectorRequirement {
1916+ {
1917+ Key : apicommon .AgentDeploymentComponentLabelKey ,
1918+ Operator : metav1 .LabelSelectorOpIn ,
1919+ Values : []string {string (apicommon .CoreAgentContainerName )},
1920+ },
1921+ },
1922+ },
1923+ TopologyKey : "kubernetes.io/hostname" ,
1924+ },
1925+ },
1926+ },
1927+ },
1928+ },
1929+ }
1930+ return expectedDDAI
1931+ }
0 commit comments