Skip to content

Commit 0d829de

Browse files
committed
Add metric and traffic plugins
Signed-off-by: Rizwana777 <[email protected]>
1 parent a96aa79 commit 0d829de

File tree

7 files changed

+423
-82
lines changed

7 files changed

+423
-82
lines changed

api/v1alpha1/argorollouts_types.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,20 @@ type RolloutManagerSpec struct {
5252

5353
// SkipNotificationSecretDeployment lets you specify if the argo notification secret should be deployed
5454
SkipNotificationSecretDeployment bool `json:"skipNotificationSecretDeployment,omitempty"`
55+
56+
// Plugins specify the traffic and metric plugins in Argo Rollout
57+
Plugins Plugins `json:"plugins,omitempty"`
58+
}
59+
60+
type Plugin struct {
61+
Name string `json:"name"`
62+
Location string `json:"location"`
63+
SHA256 string `json:"sha256,omitempty"`
64+
}
65+
66+
type Plugins struct {
67+
TrafficManagement []Plugin `json:"trafficManagement,omitempty"`
68+
Metric []Plugin `json:"metric,omitempty"`
5569
}
5670

5771
// ArgoRolloutsNodePlacementSpec is used to specify NodeSelector and Tolerations for Rollouts workloads

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 41 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/argoproj.io_rolloutmanagers.yaml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,37 @@ spec:
286286
type: object
287287
type: array
288288
type: object
289+
plugins:
290+
properties:
291+
metric:
292+
items:
293+
properties:
294+
location:
295+
type: string
296+
name:
297+
type: string
298+
sha256:
299+
type: string
300+
required:
301+
- location
302+
- name
303+
type: object
304+
type: array
305+
trafficManagement:
306+
items:
307+
properties:
308+
location:
309+
type: string
310+
name:
311+
type: string
312+
sha256:
313+
type: string
314+
required:
315+
- location
316+
- name
317+
type: object
318+
type: array
319+
type: object
289320
skipNotificationSecretDeployment:
290321
description: SkipNotificationSecretDeployment lets you specify if
291322
the argo notification secret should be deployed

controllers/configmap.go

Lines changed: 111 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,24 @@ package rollouts
22

33
import (
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/
1521
const TrafficRouterPluginConfigMapKey = "trafficRouterPlugins"
22+
const MetricPluginConfigMapKey = "metricPlugins"
1623

1724
// Reconcile the Rollouts Default Config Map.
1825
func (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

Comments
 (0)