@@ -1045,7 +1045,7 @@ var _ = Describe("[sriov] operator", func() {
1045
1045
})
1046
1046
1047
1047
Describe ("Custom SriovNetworkNodePolicy" , func () {
1048
- BeforeEach (func () {
1048
+ AfterEach (func () {
1049
1049
err := namespaces .Clean (operatorNamespace , namespaces .Test , clients , discovery .Enabled ())
1050
1050
Expect (err ).ToNot (HaveOccurred ())
1051
1051
WaitForSRIOVStable ()
@@ -1722,6 +1722,111 @@ var _ = Describe("[sriov] operator", func() {
1722
1722
})
1723
1723
})
1724
1724
1725
+ Context ("Draining Daemons using SR-IOV" , func () {
1726
+ var node string
1727
+ resourceName := "drainresource"
1728
+ sriovNetworkName := "test-drainnetwork"
1729
+ var drainPolicy * sriovv1.SriovNetworkNodePolicy
1730
+
1731
+ BeforeEach (func () {
1732
+ isSingleNode , err := cluster .IsSingleNode (clients )
1733
+ Expect (err ).ToNot (HaveOccurred ())
1734
+ if isSingleNode {
1735
+ // TODO: change this when we add support for draining on single node
1736
+ Skip ("This test is not supported on single node as we don't drain on single node" )
1737
+ }
1738
+
1739
+ node = sriovInfos .Nodes [0 ]
1740
+ sriovDeviceList , err := sriovInfos .FindSriovDevices (node )
1741
+ Expect (err ).ToNot (HaveOccurred ())
1742
+ intf := sriovDeviceList [0 ]
1743
+ By ("Using device " + intf .Name + " on node " + node )
1744
+
1745
+ drainPolicy = & sriovv1.SriovNetworkNodePolicy {
1746
+ ObjectMeta : metav1.ObjectMeta {
1747
+ GenerateName : "test-drainpolicy" ,
1748
+ Namespace : operatorNamespace ,
1749
+ },
1750
+
1751
+ Spec : sriovv1.SriovNetworkNodePolicySpec {
1752
+ NodeSelector : map [string ]string {
1753
+ "kubernetes.io/hostname" : node ,
1754
+ },
1755
+ Mtu : 1500 ,
1756
+ NumVfs : 5 ,
1757
+ ResourceName : resourceName ,
1758
+ Priority : 99 ,
1759
+ NicSelector : sriovv1.SriovNetworkNicSelector {
1760
+ PfNames : []string {intf .Name },
1761
+ },
1762
+ DeviceType : "netdevice" ,
1763
+ },
1764
+ }
1765
+
1766
+ err = clients .Create (context .Background (), drainPolicy )
1767
+ Expect (err ).ToNot (HaveOccurred ())
1768
+
1769
+ WaitForSRIOVStable ()
1770
+ By ("waiting for the resources to be available" )
1771
+ Eventually (func () int64 {
1772
+ testedNode , err := clients .CoreV1Interface .Nodes ().Get (context .Background (), node , metav1.GetOptions {})
1773
+ Expect (err ).ToNot (HaveOccurred ())
1774
+ resNum := testedNode .Status .Allocatable [corev1 .ResourceName ("openshift.io/" + resourceName )]
1775
+ allocatable , _ := resNum .AsInt64 ()
1776
+ return allocatable
1777
+ }, 10 * time .Minute , time .Second ).Should (Equal (int64 (5 )))
1778
+
1779
+ sriovNetwork := & sriovv1.SriovNetwork {
1780
+ ObjectMeta : metav1.ObjectMeta {
1781
+ Name : sriovNetworkName ,
1782
+ Namespace : operatorNamespace ,
1783
+ },
1784
+ Spec : sriovv1.SriovNetworkSpec {
1785
+ ResourceName : resourceName ,
1786
+ IPAM : `{"type":"host-local","subnet":"10.10.10.0/24","rangeStart":"10.10.10.171","rangeEnd":"10.10.10.181"}` ,
1787
+ NetworkNamespace : namespaces .Test ,
1788
+ }}
1789
+
1790
+ // We need this to be able to run the connectivity checks on Mellanox cards
1791
+ if intf .DeviceID == "1015" {
1792
+ sriovNetwork .Spec .SpoofChk = off
1793
+ }
1794
+
1795
+ err = clients .Create (context .Background (), sriovNetwork )
1796
+
1797
+ Expect (err ).ToNot (HaveOccurred ())
1798
+ waitForNetAttachDef ("test-drainnetwork" , namespaces .Test )
1799
+
1800
+ createTestDaemonSet (node , []string {sriovNetworkName })
1801
+ })
1802
+
1803
+ It ("should reconcile managed VF if status is changed" , func () {
1804
+ By ("getting running config-daemon and test pod on the node" )
1805
+ daemonTestPod , err := findPodOnNodeWithLabelsAndNamespace (node , namespaces .Test , map [string ]string {"app" : "test" })
1806
+ Expect (err ).ToNot (HaveOccurred ())
1807
+ daemonConfigPod , err := findPodOnNodeWithLabelsAndNamespace (node , operatorNamespace , map [string ]string {"app" : "sriov-network-config-daemon" })
1808
+ Expect (err ).ToNot (HaveOccurred ())
1809
+
1810
+ By ("deleting the sriov policy to start a drain" )
1811
+ err = clients .Delete (context .Background (), drainPolicy )
1812
+ Expect (err ).ToNot (HaveOccurred ())
1813
+ WaitForSRIOVStable ()
1814
+
1815
+ tmpDaemon := & appsv1.DaemonSet {}
1816
+ By ("Checking the pod owned by a DaemonSet requesting sriov device was deleted " )
1817
+ Eventually (func (g Gomega ) bool {
1818
+ err = clients .Client .Get (context .Background (), runtimeclient.ObjectKey {Name : daemonTestPod .Name , Namespace : daemonTestPod .Namespace }, tmpDaemon )
1819
+ return err != nil && k8serrors .IsNotFound (err )
1820
+ }, time .Minute , 5 * time .Second ).Should (BeTrue ())
1821
+
1822
+ By ("Checking the pod owned by a DaemonSet not requesting an sriov device was not deleted" )
1823
+ Consistently (func (g Gomega ) bool {
1824
+ err = clients .Client .Get (context .Background (), runtimeclient.ObjectKey {Name : daemonConfigPod .Name , Namespace : daemonConfigPod .Namespace }, tmpDaemon )
1825
+ return err != nil && k8serrors .IsNotFound (err )
1826
+ }, time .Minute , 10 * time .Second ).Should (BeTrue ())
1827
+ })
1828
+ })
1829
+
1725
1830
})
1726
1831
})
1727
1832
@@ -1842,6 +1947,11 @@ func findMainSriovDevice(executorPod *corev1.Pod, sriovDevices []*sriovv1.Interf
1842
1947
1843
1948
func findUnusedSriovDevices (testNode string , sriovDevices []* sriovv1.InterfaceExt ) ([]* sriovv1.InterfaceExt , error ) {
1844
1949
createdPod := createCustomTestPod (testNode , []string {}, true , nil )
1950
+ defer func () {
1951
+ err := clients .Delete (context .Background (), createdPod )
1952
+ Expect (err ).ToNot (HaveOccurred ())
1953
+ }()
1954
+
1845
1955
filteredDevices := []* sriovv1.InterfaceExt {}
1846
1956
stdout , _ , err := pod .ExecCommand (clients , createdPod , "ip" , "route" )
1847
1957
Expect (err ).ToNot (HaveOccurred ())
@@ -1989,6 +2099,24 @@ func isDaemonsetScheduledOnNodes(nodeSelector, daemonsetLabelSelector string) bo
1989
2099
return true
1990
2100
}
1991
2101
2102
+ func findPodOnNodeWithLabelsAndNamespace (nodeName string , namespace string , labels map [string ]string ) (* corev1.Pod , error ) {
2103
+ podList := & corev1.PodList {}
2104
+ err := clients .List (context .Background (), podList , runtimeclient .MatchingLabels (labels ), & runtimeclient.ListOptions {Namespace : namespace }, runtimeclient.MatchingFields {"spec.nodeName" : nodeName })
2105
+ if err != nil {
2106
+ return nil , err
2107
+ }
2108
+
2109
+ if len (podList .Items ) == 0 {
2110
+ return nil , fmt .Errorf ("no pod found" )
2111
+ }
2112
+
2113
+ if len (podList .Items ) > 1 {
2114
+ return nil , fmt .Errorf ("multiple pods found" )
2115
+ }
2116
+
2117
+ return & podList .Items [0 ], nil
2118
+ }
2119
+
1992
2120
func createSriovPolicy (sriovDevice string , testNode string , numVfs int , resourceName string ) {
1993
2121
_ , err := network .CreateSriovPolicy (clients , "test-policy-" , operatorNamespace , sriovDevice , testNode , numVfs , resourceName , "netdevice" )
1994
2122
Expect (err ).ToNot (HaveOccurred ())
@@ -2017,7 +2145,6 @@ func createCustomTestPod(node string, networks []string, hostNetwork bool, podCa
2017
2145
node ,
2018
2146
)
2019
2147
}
2020
-
2021
2148
if len (podCapabilities ) != 0 {
2022
2149
if podDefinition .Spec .Containers [0 ].SecurityContext == nil {
2023
2150
podDefinition .Spec .Containers [0 ].SecurityContext = & corev1.SecurityContext {}
@@ -2034,6 +2161,41 @@ func createCustomTestPod(node string, networks []string, hostNetwork bool, podCa
2034
2161
return waitForPodRunning (createdPod )
2035
2162
}
2036
2163
2164
+ func createTestDaemonSet (node string , networks []string ) * appsv1.DaemonSet {
2165
+ podDefinition := pod .RedefineWithNodeSelector (
2166
+ pod .GetDefinition (),
2167
+ node ,
2168
+ )
2169
+
2170
+ // remove NET_ADMIN to not have issues in OCP
2171
+ podDefinition .Spec .Containers [0 ].SecurityContext = nil
2172
+
2173
+ daemonDefinition := & appsv1.DaemonSet {
2174
+ ObjectMeta : metav1.ObjectMeta {GenerateName : "test-" , Namespace : namespaces .Test },
2175
+ Spec : appsv1.DaemonSetSpec {
2176
+ Selector : & metav1.LabelSelector {
2177
+ MatchLabels : map [string ]string {
2178
+ "app" : "test" ,
2179
+ },
2180
+ },
2181
+ Template : corev1.PodTemplateSpec {
2182
+ ObjectMeta : metav1.ObjectMeta {
2183
+ Labels : map [string ]string {
2184
+ "app" : "test" ,
2185
+ },
2186
+ Annotations : map [string ]string {"k8s.v1.cni.cncf.io/networks" : strings .Join (networks , "," )},
2187
+ },
2188
+ Spec : podDefinition .Spec ,
2189
+ },
2190
+ },
2191
+ }
2192
+
2193
+ err := clients .Create (context .Background (), daemonDefinition )
2194
+ Expect (err ).ToNot (HaveOccurred ())
2195
+
2196
+ return waitForDaemonReady (daemonDefinition )
2197
+ }
2198
+
2037
2199
func pingPod (ip string , nodeSelector string , sriovNetworkAttachment string ) {
2038
2200
ipProtocolVersion := "6"
2039
2201
if len (strings .Split (ip , "." )) == 4 {
@@ -2376,6 +2538,18 @@ func waitForPodRunning(p *corev1.Pod) *corev1.Pod {
2376
2538
return ret
2377
2539
}
2378
2540
2541
+ func waitForDaemonReady (d * appsv1.DaemonSet ) * appsv1.DaemonSet {
2542
+ Eventually (func (g Gomega ) bool {
2543
+ err := clients .Get (context .Background (), runtimeclient.ObjectKey {Name : d .Name , Namespace : d .Namespace }, d )
2544
+ g .Expect (err ).ToNot (HaveOccurred ())
2545
+ g .Expect (d .Status .DesiredNumberScheduled ).To (BeNumerically (">" , 0 ))
2546
+ g .Expect (d .Status .CurrentNumberScheduled ).To (BeNumerically (">" , 0 ))
2547
+ return d .Status .DesiredNumberScheduled == d .Status .NumberReady
2548
+ }, 3 * time .Minute , 1 * time .Second ).Should (BeTrue (), "DaemonSet [%s/%s] should have running pods" , d .Namespace , d .Name )
2549
+
2550
+ return d
2551
+ }
2552
+
2379
2553
// assertNodeStateHasVFMatching asserts that the given node state has at least one VF matching the given fields
2380
2554
func assertNodeStateHasVFMatching (nodeName string , fields Fields ) {
2381
2555
EventuallyWithOffset (1 , func (g Gomega ) sriovv1.InterfaceExts {
0 commit comments