@@ -239,6 +239,162 @@ var _ = Describe("AggregatesController", func() {
239239 })
240240 })
241241
242+ Context ("During onboarding Handover phase with traits not ready" , func () {
243+ BeforeEach (func (ctx SpecContext ) {
244+ By ("Setting onboarding condition to Handover without TraitsUpdated" )
245+ hypervisor := & kvmv1.Hypervisor {}
246+ Expect (k8sClient .Get (ctx , hypervisorName , hypervisor )).To (Succeed ())
247+ meta .SetStatusCondition (& hypervisor .Status .Conditions , metav1.Condition {
248+ Type : kvmv1 .ConditionTypeOnboarding ,
249+ Status : metav1 .ConditionTrue ,
250+ Reason : kvmv1 .ConditionReasonHandover ,
251+ Message : "Waiting for other controllers to take over" ,
252+ })
253+ Expect (k8sClient .Status ().Update (ctx , hypervisor )).To (Succeed ())
254+
255+ By ("Setting desired aggregates" )
256+ Expect (k8sClient .Get (ctx , hypervisorName , hypervisor )).To (Succeed ())
257+ hypervisor .Spec .Aggregates = []string {"zone-a" , "prod-agg" }
258+ Expect (k8sClient .Update (ctx , hypervisor )).To (Succeed ())
259+
260+ By ("Mocking GetAggregates to return aggregates without host" )
261+ aggregateList := `{
262+ "aggregates": [
263+ {
264+ "name": "zone-a",
265+ "availability_zone": "zone-a",
266+ "deleted": false,
267+ "id": 1,
268+ "uuid": "uuid-zone-a",
269+ "hosts": []
270+ },
271+ {
272+ "name": "tenant_filter_tests",
273+ "availability_zone": "",
274+ "deleted": false,
275+ "id": 99,
276+ "uuid": "uuid-test",
277+ "hosts": []
278+ }
279+ ]
280+ }`
281+ fakeServer .Mux .HandleFunc ("GET /os-aggregates" , func (w http.ResponseWriter , r * http.Request ) {
282+ w .Header ().Add ("Content-Type" , "application/json" )
283+ w .WriteHeader (http .StatusOK )
284+ fmt .Fprint (w , aggregateList )
285+ })
286+
287+ By ("Mocking AddHost for zone and test aggregates" )
288+ fakeServer .Mux .HandleFunc ("POST /os-aggregates/1/action" , func (w http.ResponseWriter , r * http.Request ) {
289+ w .Header ().Add ("Content-Type" , "application/json" )
290+ w .WriteHeader (http .StatusOK )
291+ fmt .Fprint (w , `{"aggregate": {"name": "zone-a", "id": 1, "uuid": "uuid-zone-a", "hosts": ["hv-test"]}}` )
292+ })
293+ fakeServer .Mux .HandleFunc ("POST /os-aggregates/99/action" , func (w http.ResponseWriter , r * http.Request ) {
294+ w .Header ().Add ("Content-Type" , "application/json" )
295+ w .WriteHeader (http .StatusOK )
296+ fmt .Fprint (w , `{"aggregate": {"name": "tenant_filter_tests", "id": 99, "uuid": "uuid-test", "hosts": ["hv-test"]}}` )
297+ })
298+ })
299+
300+ It ("should keep test aggregates and set WaitingForTraits condition" , func (ctx SpecContext ) {
301+ updated := & kvmv1.Hypervisor {}
302+ Expect (aggregatesController .Client .Get (ctx , hypervisorName , updated )).To (Succeed ())
303+
304+ aggregateNames := make ([]string , len (updated .Status .Aggregates ))
305+ for i , agg := range updated .Status .Aggregates {
306+ aggregateNames [i ] = agg .Name
307+ }
308+
309+ Expect (aggregateNames ).To (ConsistOf ("zone-a" , testAggregateName ))
310+ Expect (meta .IsStatusConditionFalse (updated .Status .Conditions , kvmv1 .ConditionTypeAggregatesUpdated )).To (BeTrue ())
311+ cond := meta .FindStatusCondition (updated .Status .Conditions , kvmv1 .ConditionTypeAggregatesUpdated )
312+ Expect (cond ).NotTo (BeNil ())
313+ Expect (cond .Reason ).To (Equal (kvmv1 .ConditionReasonWaitingForTraits ))
314+ })
315+ })
316+
317+ Context ("During onboarding Handover phase with traits ready" , func () {
318+ BeforeEach (func (ctx SpecContext ) {
319+ By ("Setting onboarding condition to Handover with TraitsUpdated=True" )
320+ hypervisor := & kvmv1.Hypervisor {}
321+ Expect (k8sClient .Get (ctx , hypervisorName , hypervisor )).To (Succeed ())
322+ meta .SetStatusCondition (& hypervisor .Status .Conditions , metav1.Condition {
323+ Type : kvmv1 .ConditionTypeOnboarding ,
324+ Status : metav1 .ConditionTrue ,
325+ Reason : kvmv1 .ConditionReasonHandover ,
326+ Message : "Waiting for other controllers to take over" ,
327+ })
328+ meta .SetStatusCondition (& hypervisor .Status .Conditions , metav1.Condition {
329+ Type : kvmv1 .ConditionTypeTraitsUpdated ,
330+ Status : metav1 .ConditionTrue ,
331+ Reason : kvmv1 .ConditionReasonSucceeded ,
332+ Message : "Traits updated successfully" ,
333+ })
334+ Expect (k8sClient .Status ().Update (ctx , hypervisor )).To (Succeed ())
335+
336+ By ("Setting desired aggregates" )
337+ Expect (k8sClient .Get (ctx , hypervisorName , hypervisor )).To (Succeed ())
338+ hypervisor .Spec .Aggregates = []string {"zone-a" , "prod-agg" }
339+ Expect (k8sClient .Update (ctx , hypervisor )).To (Succeed ())
340+
341+ By ("Mocking GetAggregates" )
342+ aggregateList := `{
343+ "aggregates": [
344+ {
345+ "name": "zone-a",
346+ "availability_zone": "zone-a",
347+ "deleted": false,
348+ "id": 1,
349+ "uuid": "uuid-zone-a",
350+ "hosts": []
351+ },
352+ {
353+ "name": "prod-agg",
354+ "availability_zone": "",
355+ "deleted": false,
356+ "id": 2,
357+ "uuid": "uuid-prod-agg",
358+ "hosts": []
359+ }
360+ ]
361+ }`
362+ fakeServer .Mux .HandleFunc ("GET /os-aggregates" , func (w http.ResponseWriter , r * http.Request ) {
363+ w .Header ().Add ("Content-Type" , "application/json" )
364+ w .WriteHeader (http .StatusOK )
365+ fmt .Fprint (w , aggregateList )
366+ })
367+
368+ By ("Mocking AddHost for both spec aggregates" )
369+ fakeServer .Mux .HandleFunc ("POST /os-aggregates/1/action" , func (w http.ResponseWriter , r * http.Request ) {
370+ w .Header ().Add ("Content-Type" , "application/json" )
371+ w .WriteHeader (http .StatusOK )
372+ fmt .Fprint (w , `{"aggregate": {"name": "zone-a", "id": 1, "uuid": "uuid-zone-a", "hosts": ["hv-test"]}}` )
373+ })
374+ fakeServer .Mux .HandleFunc ("POST /os-aggregates/2/action" , func (w http.ResponseWriter , r * http.Request ) {
375+ w .Header ().Add ("Content-Type" , "application/json" )
376+ w .WriteHeader (http .StatusOK )
377+ fmt .Fprint (w , `{"aggregate": {"name": "prod-agg", "id": 2, "uuid": "uuid-prod-agg", "hosts": ["hv-test"]}}` )
378+ })
379+ })
380+
381+ It ("should apply spec aggregates and set Succeeded condition" , func (ctx SpecContext ) {
382+ updated := & kvmv1.Hypervisor {}
383+ Expect (aggregatesController .Client .Get (ctx , hypervisorName , updated )).To (Succeed ())
384+
385+ aggregateNames := make ([]string , len (updated .Status .Aggregates ))
386+ for i , agg := range updated .Status .Aggregates {
387+ aggregateNames [i ] = agg .Name
388+ }
389+
390+ Expect (aggregateNames ).To (ConsistOf ("zone-a" , "prod-agg" ))
391+ Expect (meta .IsStatusConditionTrue (updated .Status .Conditions , kvmv1 .ConditionTypeAggregatesUpdated )).To (BeTrue ())
392+ cond := meta .FindStatusCondition (updated .Status .Conditions , kvmv1 .ConditionTypeAggregatesUpdated )
393+ Expect (cond ).NotTo (BeNil ())
394+ Expect (cond .Reason ).To (Equal (kvmv1 .ConditionReasonSucceeded ))
395+ })
396+ })
397+
242398 Context ("During normal operations" , func () {
243399 BeforeEach (func (ctx SpecContext ) {
244400 By ("Setting desired aggregates" )
0 commit comments