Skip to content

Commit 4980371

Browse files
iamnitingrohan47
authored andcommitted
controllers: ensure CSV inherits hostNetwork from previous deployment
The webhook now mutates the ClusterServiceVersion (CSV) to set `hostNetwork` on deployments if the replaced CSV had it enabled. This ensures continuity of networking configuration across operator upgrades and avoids potential deployment issues caused by missing `hostNetwork` in the new CSV. Signed-off-by: Nitin Goyal <nigoyal@redhat.com> Signed-off-by: Rohan Gupta <rohgupta@redhat.com>
1 parent eff6fe3 commit 4980371

File tree

1 file changed

+64
-28
lines changed

1 file changed

+64
-28
lines changed

webhook/csv.go

Lines changed: 64 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525

2626
"github.com/go-logr/logr"
2727
opv1a1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
28-
"k8s.io/apimachinery/pkg/api/errors"
2928
"k8s.io/utils/ptr"
3029
ctrl "sigs.k8s.io/controller-runtime"
3130
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -47,6 +46,11 @@ type ClusterServiceVersionDeploymentScaler struct {
4746
odfOwnedCsvNames map[string]bool
4847
}
4948

49+
const (
50+
// keyReplicas is the key for the replicas in the defaults map
51+
keyReplicas = "replicas"
52+
)
53+
5054
//+kubebuilder:rbac:groups=operators.coreos.com,resources=clusterserviceversions,verbs=get;patch
5155
//+kubebuilder:rbac:groups="",resources=configmaps,verbs=get
5256

@@ -71,19 +75,35 @@ func (r *ClusterServiceVersionDeploymentScaler) Handle(ctx context.Context, req
7175
return admission.Allowed("csv is not managed by ODF")
7276
}
7377

74-
running, err := r.isPreviousCsvHasRunningDeployments(ctx, logger, csv)
75-
if err != nil {
76-
logger.Error(err, "failed getting replicas from csv")
77-
return admission.Errored(http.StatusInternalServerError, fmt.Errorf("failed getting replicas from csv: %v", err))
78+
var isPrevCsvFound bool
79+
if csv.Spec.Replaces != "" {
80+
prevCsv := &opv1a1.ClusterServiceVersion{}
81+
key := client.ObjectKey{Name: csv.Spec.Replaces, Namespace: csv.Namespace}
82+
if err := r.Client.Get(ctx, key, prevCsv); err != nil {
83+
if client.IgnoreNotFound(err) != nil {
84+
logger.Error(err, "failed to get previous CSV", "csv", csv.Spec.Replaces)
85+
return admission.Errored(http.StatusInternalServerError, fmt.Errorf("failed getting previous csv %q: %w", csv.Spec.Replaces, err))
86+
}
87+
} else {
88+
logger.Info("previous CSV found", "csv", csv.Spec.Replaces)
89+
isPrevCsvFound = true
90+
defaultsMap := map[string]any{}
91+
// in case previours csv has n deployments and current csv has n+1 deployments the the defaults map will be used to scale down replicas of the new deployment
92+
// also the defaults map can be used to set default values for new deployments in the future
93+
if r.isCsvHasRunningDeployments(prevCsv) {
94+
defaultsMap[keyReplicas] = 1
95+
} else {
96+
defaultsMap[keyReplicas] = 0
97+
}
98+
r.syncNewCsvWithPrevCsv(prevCsv, csv, defaultsMap)
99+
}
78100
}
79101

80-
if running {
81-
logger.Info("ignoring csv as the previous csv deployments are running")
82-
return admission.Allowed("previous csv deployments are running")
102+
if !isPrevCsvFound {
103+
logger.Info("scaling down deployments")
104+
r.scaleDownCsvDeployments(logger, csv)
83105
}
84106

85-
r.scaleDownCsvDeployments(logger, csv)
86-
87107
marshaledCsv, err := json.Marshal(csv)
88108
if err != nil {
89109
logger.Error(err, "failed marshaling csv")
@@ -123,35 +143,51 @@ func (r *ClusterServiceVersionDeploymentScaler) loadOdfConfigMapData(ctx context
123143
return nil
124144
}
125145

126-
func (r *ClusterServiceVersionDeploymentScaler) isPreviousCsvHasRunningDeployments(ctx context.Context, logger logr.Logger, csv *opv1a1.ClusterServiceVersion) (bool, error) {
146+
// syncNewCsvWithPrevCsv copies the required fields from the previous csv that are required after upgrade in the new csv
147+
func (r *ClusterServiceVersionDeploymentScaler) syncNewCsvWithPrevCsv(
148+
prevCsv *opv1a1.ClusterServiceVersion,
149+
newCsv *opv1a1.ClusterServiceVersion,
150+
defaultsMap map[string]any) {
127151

128-
if csv.Spec.Replaces == "" {
129-
logger.Info("csv.Spec.Replaces is not populated")
130-
return false, nil
131-
}
152+
prevDeployments := prevCsv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs
153+
newDeployments := newCsv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs
132154

133-
prevCsv := &opv1a1.ClusterServiceVersion{}
134-
key := client.ObjectKey{Name: csv.Spec.Replaces, Namespace: csv.Namespace}
155+
for i := range newDeployments {
156+
newDeployment := &newDeployments[i]
135157

136-
if err := r.Client.Get(ctx, key, prevCsv); errors.IsNotFound(err) {
137-
// new install where an previous csv does not exists
138-
return false, nil
139-
} else if err != nil {
140-
logger.Error(err, "failed getting previous csv")
141-
return false, err
158+
var deploymentFound bool
159+
160+
for j := range prevDeployments {
161+
prevDeployment := &prevDeployments[j]
162+
163+
if newDeployment.Name == prevDeployment.Name {
164+
newDeployment.Spec.Template.Spec.HostNetwork = prevDeployment.Spec.Template.Spec.HostNetwork
165+
newDeployment.Spec.Template.Spec.DNSPolicy = prevDeployment.Spec.Template.Spec.DNSPolicy
166+
newDeployment.Spec.Replicas = prevDeployment.Spec.Replicas
167+
deploymentFound = true
168+
break
169+
}
170+
}
171+
// if the deployment is not found in the previous csv, then the defaults map will be used to set values in the new csv
172+
if !deploymentFound {
173+
if val, ok := defaultsMap[keyReplicas].(int32); ok {
174+
newDeployment.Spec.Replicas = ptr.To(val)
175+
}
176+
}
142177
}
178+
}
179+
180+
func (r *ClusterServiceVersionDeploymentScaler) isCsvHasRunningDeployments(csv *opv1a1.ClusterServiceVersion) bool {
143181

144-
deployments := prevCsv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs
182+
deployments := csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs
145183
for i := range deployments {
146184
deployment := &deployments[i]
147185
if deployment.Spec.Replicas == nil || *deployment.Spec.Replicas > 0 {
148-
// upgrade case where an older csv is found with replica 1
149-
return true, nil
186+
return true
150187
}
151188
}
152189

153-
// upgrade case where an older csv is found with replica 0
154-
return false, nil
190+
return false
155191
}
156192

157193
func (r *ClusterServiceVersionDeploymentScaler) scaleDownCsvDeployments(logger logr.Logger, csv *opv1a1.ClusterServiceVersion) {

0 commit comments

Comments
 (0)