@@ -2,17 +2,24 @@ package rollouts
22
33import  (
44	"context" 
5+ 
56	"fmt" 
7+ 	"reflect" 
68
79	rolloutsmanagerv1alpha1 "github.com/argoproj-labs/argo-rollouts-manager/api/v1alpha1" 
810	"gopkg.in/yaml.v2" 
11+ 	appsv1 "k8s.io/api/apps/v1" 
912	corev1 "k8s.io/api/core/v1" 
13+ 
1014	"k8s.io/apimachinery/pkg/api/errors" 
1115	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 
16+ 	"k8s.io/apimachinery/pkg/types" 
17+ 	"sigs.k8s.io/controller-runtime/pkg/client" 
1218)
1319
1420// From https://argo-rollouts.readthedocs.io/en/stable/features/traffic-management/plugins/ 
1521const  TrafficRouterPluginConfigMapKey  =  "trafficRouterPlugins" 
22+ const  MetricPluginConfigMapKey  =  "metricPlugins" 
1623
1724// Reconcile the Rollouts Default Config Map. 
1825func  (r  * RolloutManagerReconciler ) reconcileConfigMap (ctx  context.Context , cr  rolloutsmanagerv1alpha1.RolloutManager ) error  {
@@ -33,18 +40,66 @@ func (r *RolloutManagerReconciler) reconcileConfigMap(ctx context.Context, cr ro
3340
3441	setRolloutsLabelsAndAnnotationsToObject (& desiredConfigMap .ObjectMeta , cr )
3542
36- 	trafficRouterPlugins  :=  [ ]pluginItem {
37- 		{
43+ 	trafficRouterPluginsMap  :=  map [ string ]pluginItem {
44+ 		OpenShiftRolloutPluginName :  {
3845			Name :     OpenShiftRolloutPluginName ,
3946			Location : r .OpenShiftRoutePluginLocation ,
4047		},
4148	}
42- 	pluginString , err  :=  yaml .Marshal (trafficRouterPlugins )
49+ 
50+ 	// Append traffic management plugins specified in RolloutManager CR 
51+ 	for  _ , plugin  :=  range  cr .Spec .Plugins .TrafficManagement  {
52+ 		// Prevent adding or modifying the OpenShiftRoutePluginName through the CR 
53+ 		if  plugin .Name  ==  OpenShiftRolloutPluginName  {
54+ 			return  fmt .Errorf ("the plugin %s cannot be modified or added through the RolloutManager CR" , OpenShiftRolloutPluginName )
55+ 		}
56+ 		// Check for duplicate traffic plugins 
57+ 		if  _ , exists  :=  trafficRouterPluginsMap [plugin .Name ]; ! exists  {
58+ 			trafficRouterPluginsMap [plugin .Name ] =  pluginItem {
59+ 				Name :     plugin .Name ,
60+ 				Location : plugin .Location ,
61+ 			}
62+ 		}
63+ 	}
64+ 
65+ 	// Convert traffic plugins map to slice 
66+ 	trafficRouterPlugins  :=  make ([]pluginItem , 0 , len (trafficRouterPluginsMap ))
67+ 	for  _ , plugin  :=  range  trafficRouterPluginsMap  {
68+ 		trafficRouterPlugins  =  append (trafficRouterPlugins , plugin )
69+ 	}
70+ 
71+ 	// Append metric plugins specified in RolloutManager CR 
72+ 	metricPluginsMap  :=  map [string ]pluginItem {}
73+ 	for  _ , plugin  :=  range  cr .Spec .Plugins .Metric  {
74+ 		// Check for duplicate metric plugins 
75+ 		if  _ , exists  :=  metricPluginsMap [plugin .Name ]; ! exists  {
76+ 			metricPluginsMap [plugin .Name ] =  pluginItem {
77+ 				Name :     plugin .Name ,
78+ 				Location : plugin .Location ,
79+ 				Sha256 :   plugin .SHA256 ,
80+ 			}
81+ 		}
82+ 	}
83+ 
84+ 	// Convert metric plugins map to slice 
85+ 	metricPlugins  :=  make ([]pluginItem , 0 , len (metricPluginsMap ))
86+ 	for  _ , plugin  :=  range  metricPluginsMap  {
87+ 		metricPlugins  =  append (metricPlugins , plugin )
88+ 	}
89+ 
90+ 	desiredTrafficRouterPluginString , err  :=  yaml .Marshal (trafficRouterPlugins )
4391	if  err  !=  nil  {
4492		return  fmt .Errorf ("error marshalling trafficRouterPlugin to string %s" , err )
4593	}
94+ 
95+ 	desiredMetricPluginString , err  :=  yaml .Marshal (metricPlugins )
96+ 	if  err  !=  nil  {
97+ 		return  fmt .Errorf ("error marshalling metricPlugins to string %s" , err )
98+ 	}
99+ 
46100	desiredConfigMap .Data  =  map [string ]string {
47- 		TrafficRouterPluginConfigMapKey : string (pluginString ),
101+ 		TrafficRouterPluginConfigMapKey : string (desiredTrafficRouterPluginString ),
102+ 		MetricPluginConfigMapKey :        string (desiredMetricPluginString ),
48103	}
49104
50105	actualConfigMap  :=  & corev1.ConfigMap {}
@@ -58,41 +113,66 @@ func (r *RolloutManagerReconciler) reconcileConfigMap(ctx context.Context, cr ro
58113		return  fmt .Errorf ("failed to get the serviceAccount associated with %s: %w" , desiredConfigMap .Name , err )
59114	}
60115
61- 	var  actualTrafficRouterPlugins  []pluginItem 
116+ 	// Unmarshal the existing plugin data from the actual ConfigMap 
117+ 	var  actualTrafficRouterPlugins , actualMetricPlugins  []pluginItem 
62118	if  err  =  yaml .Unmarshal ([]byte (actualConfigMap .Data [TrafficRouterPluginConfigMapKey ]), & actualTrafficRouterPlugins ); err  !=  nil  {
63- 		return  fmt .Errorf ("failed to unmarshal traffic router plugins from ConfigMap: %s" , err )
119+ 		return  fmt .Errorf ("failed to unmarshal traffic router plugins: %s" , err )
120+ 	}
121+ 	if  err  =  yaml .Unmarshal ([]byte (actualConfigMap .Data [MetricPluginConfigMapKey ]), & actualMetricPlugins ); err  !=  nil  {
122+ 		return  fmt .Errorf ("failed to unmarshal metric plugins: %s" , err )
64123	}
65124
66- 	// Check if the plugin already exists and if the URL is different, update the ConfigMap 
67- 	for  i , plugin  :=  range  actualTrafficRouterPlugins  {
68- 		if  plugin .Name  ==  OpenShiftRolloutPluginName  {
69- 			if  plugin .Location  !=  r .OpenShiftRoutePluginLocation  {
70- 				actualTrafficRouterPlugins [i ].Location  =  r .OpenShiftRoutePluginLocation 
71- 				pluginBytes , err  :=  yaml .Marshal (actualTrafficRouterPlugins )
72- 				if  err  !=  nil  {
73- 					return  fmt .Errorf ("error marshalling trafficRouterPlugin to string %s" , err )
74- 				}
75- 
76- 				actualConfigMap .Data  =  map [string ]string {
77- 					TrafficRouterPluginConfigMapKey : string (pluginBytes ),
78- 				}
79- 
80- 				return  r .Client .Update (ctx , actualConfigMap )
81- 			} else  {
82- 				// Plugin URL is the same, nothing to do 
83- 				return  nil 
84- 			}
125+ 	// Check if an update is needed by comparing desired and actual plugin configurations 
126+ 	updateNeeded  :=  ! reflect .DeepEqual (actualTrafficRouterPlugins , trafficRouterPlugins ) ||  ! reflect .DeepEqual (actualMetricPlugins , metricPlugins )
127+ 
128+ 	if  updateNeeded  {
129+ 		// Update the ConfigMap's plugin data with the new values 
130+ 		actualConfigMap .Data [TrafficRouterPluginConfigMapKey ] =  string (desiredTrafficRouterPluginString )
131+ 		actualConfigMap .Data [MetricPluginConfigMapKey ] =  string (desiredMetricPluginString )
132+ 
133+ 		// Update the ConfigMap in the cluster 
134+ 		if  err  :=  r .Client .Update (ctx , actualConfigMap ); err  !=  nil  {
135+ 			return  fmt .Errorf ("failed to update ConfigMap: %v" , err )
136+ 		}
137+ 		log .Info ("ConfigMap updated successfully" )
138+ 
139+ 		// Restarting rollouts pod only if configMap is updated 
140+ 		if  err  :=  r .restartRolloutsPod (ctx , cr .Namespace ); err  !=  nil  {
141+ 			return  err 
85142		}
86143	}
144+ 	log .Info ("No changes detected in ConfigMap, skipping update and pod restart" )
145+ 	return  nil 
146+ }
87147
88- 	updatedTrafficRouterPlugins  :=  append (actualTrafficRouterPlugins , trafficRouterPlugins ... )
148+ // restartRolloutsPod deletes the Rollouts Pod to trigger a restart 
149+ func  (r  * RolloutManagerReconciler ) restartRolloutsPod (ctx  context.Context , namespace  string ) error  {
150+ 	deployment  :=  & appsv1.Deployment {}
151+ 	if  err  :=  r .Client .Get (ctx , types.NamespacedName {Name : DefaultArgoRolloutsResourceName , Namespace : namespace }, deployment ); err  !=  nil  {
152+ 		return  fmt .Errorf ("failed to get deployment: %w" , err )
153+ 	}
89154
90- 	pluginString , err  =  yaml .Marshal (updatedTrafficRouterPlugins )
91- 	if  err  !=  nil  {
92- 		return  fmt .Errorf ("error marshalling trafficRouterPlugin to string %w" , err )
155+ 	podList  :=  & corev1.PodList {}
156+ 	listOpts  :=  []client.ListOption {
157+ 		client .InNamespace (namespace ),
158+ 		client .MatchingLabels (deployment .Spec .Selector .MatchLabels ),
159+ 	}
160+ 	if  err  :=  r .Client .List (ctx , podList , listOpts ... ); err  !=  nil  {
161+ 		return  fmt .Errorf ("failed to list Rollouts Pods: %w" , err )
93162	}
94163
95- 	actualConfigMap .Data [TrafficRouterPluginConfigMapKey ] =  string (pluginString )
164+ 	for  i  :=  range  podList .Items  {
165+ 		pod  :=  podList .Items [i ]
166+ 		log .Info ("Deleting Rollouts Pod" , "podName" , pod .Name )
167+ 		if  err  :=  r .Client .Delete (ctx , & pod ); err  !=  nil  {
168+ 			if  errors .IsNotFound (err ) {
169+ 				log .Info (fmt .Sprintf ("Pod %s already deleted" , pod .Name ))
170+ 				continue 
171+ 			}
172+ 			return  fmt .Errorf ("failed to delete Rollouts Pod %s: %w" , pod .Name , err )
173+ 		}
174+ 		log .Info ("Rollouts Pod deleted successfully" , "podName" , pod .Name )
175+ 	}
96176
97- 	return  r . Client . Update ( ctx ,  actualConfigMap ) 
177+ 	return  nil 
98178}
0 commit comments