-
Notifications
You must be signed in to change notification settings - Fork 1.5k
CORS-4005: refactor worker manifest serialization #10407
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -9,12 +9,12 @@ import ( | |||||
|
|
||||||
| "github.com/pkg/errors" | ||||||
| "github.com/sirupsen/logrus" | ||||||
| meta "k8s.io/apimachinery/pkg/api/meta" | ||||||
| "k8s.io/apimachinery/pkg/runtime" | ||||||
| "k8s.io/apimachinery/pkg/runtime/serializer" | ||||||
| "k8s.io/apimachinery/pkg/util/intstr" | ||||||
| "k8s.io/utils/pointer" | ||||||
| capz "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" | ||||||
| ipamv1 "sigs.k8s.io/cluster-api/api/ipam/v1beta1" //nolint:staticcheck //CORS-3563 | ||||||
| capz "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" //nolint:staticcheck //CORS-3563 | ||||||
| "sigs.k8s.io/yaml" | ||||||
|
|
||||||
| configv1 "github.com/openshift/api/config/v1" | ||||||
|
|
@@ -325,14 +325,11 @@ func (w *Worker) Generate(ctx context.Context, dependencies asset.Parents) error | |||||
| dependencies.Get(clusterID, installConfig, rhcosImage, rhcosRelease, wign) | ||||||
|
|
||||||
| workerUserDataSecretName := "worker-user-data" | ||||||
|
|
||||||
| machines := []machinev1beta1.Machine{} | ||||||
| machineConfigs := []*mcfgv1.MachineConfig{} | ||||||
| machineSets := []runtime.Object{} | ||||||
| var ipClaims []ipamv1.IPAddressClaim | ||||||
| var ipAddrs []ipamv1.IPAddress | ||||||
| var ipClaims, ipAddrs, machines, machineSets []runtime.Object | ||||||
| var err error | ||||||
| ic := installConfig.Config | ||||||
|
|
||||||
| for _, pool := range ic.Compute { | ||||||
| pool := pool // this makes golint happy... G601: Implicit memory aliasing in for loop. (gosec) | ||||||
| if pool.Hyperthreading == types.HyperthreadingDisabled { | ||||||
|
|
@@ -727,9 +724,15 @@ func (w *Worker) Generate(ctx context.Context, dependencies asset.Parents) error | |||||
| return errors.Wrap(err, "failed to create worker machine objects") | ||||||
| } | ||||||
|
|
||||||
| machines = data.Machines | ||||||
| ipClaims = data.IPClaims | ||||||
| ipAddrs = data.IPAddresses | ||||||
| for _, m := range data.Machines { | ||||||
| machines = append(machines, &m) | ||||||
| } | ||||||
| for _, c := range data.IPClaims { | ||||||
| ipClaims = append(ipClaims, &c) | ||||||
| } | ||||||
| for _, a := range data.IPAddresses { | ||||||
| ipAddrs = append(ipAddrs, &a) | ||||||
| } | ||||||
|
|
||||||
| logrus.Debugf("Generated %v worker machines.", len(machines)) | ||||||
|
|
||||||
|
|
@@ -801,58 +804,17 @@ func (w *Worker) Generate(ctx context.Context, dependencies asset.Parents) error | |||||
| return errors.Wrap(err, "failed to create MachineConfig manifests for worker machines") | ||||||
| } | ||||||
|
|
||||||
| w.MachineSetFiles = make([]*asset.File, len(machineSets)) | ||||||
| padFormat := fmt.Sprintf("%%0%dd", len(fmt.Sprintf("%d", len(machineSets)))) | ||||||
| for i, machineSet := range machineSets { | ||||||
| data, err := yaml.Marshal(machineSet) | ||||||
| if err != nil { | ||||||
| return errors.Wrapf(err, "marshal worker %d", i) | ||||||
| } | ||||||
|
|
||||||
| padded := fmt.Sprintf(padFormat, i) | ||||||
| w.MachineSetFiles[i] = &asset.File{ | ||||||
| Filename: filepath.Join(directory, fmt.Sprintf(workerMachineSetFileName, padded)), | ||||||
| Data: data, | ||||||
| } | ||||||
| if w.MachineSetFiles, err = serialize(machineSets, workerMachineSetFileName, false); err != nil { | ||||||
| return fmt.Errorf("failed to serialize worker machine sets: %w", err) | ||||||
| } | ||||||
|
|
||||||
| w.IPClaimFiles = make([]*asset.File, len(ipClaims)) | ||||||
| for i, claim := range ipClaims { | ||||||
| data, err := yaml.Marshal(claim) | ||||||
| if err != nil { | ||||||
| return errors.Wrapf(err, "marshal ip claim %v", claim.Name) | ||||||
| } | ||||||
|
|
||||||
| w.IPClaimFiles[i] = &asset.File{ | ||||||
| Filename: filepath.Join(directory, fmt.Sprintf(ipClaimFileName, claim.Name)), | ||||||
| Data: data, | ||||||
| } | ||||||
| if w.IPClaimFiles, err = serialize(ipClaims, ipClaimFileName, true); err != nil { | ||||||
| return fmt.Errorf("failed to serialize worker ip claims: %w", err) | ||||||
| } | ||||||
|
|
||||||
| w.IPAddrFiles = make([]*asset.File, len(ipAddrs)) | ||||||
| for i, address := range ipAddrs { | ||||||
| data, err := yaml.Marshal(address) | ||||||
| if err != nil { | ||||||
| return errors.Wrapf(err, "marshal ip claim %v", address.Name) | ||||||
| } | ||||||
|
|
||||||
| w.IPAddrFiles[i] = &asset.File{ | ||||||
| Filename: filepath.Join(directory, fmt.Sprintf(ipAddressFileName, address.Name)), | ||||||
| Data: data, | ||||||
| } | ||||||
| if w.IPAddrFiles, err = serialize(ipAddrs, ipAddressFileName, true); err != nil { | ||||||
| return fmt.Errorf("failed to serialize worker ip addresses: %w", err) | ||||||
| } | ||||||
| w.MachineFiles = make([]*asset.File, len(machines)) | ||||||
| for i, machineDef := range machines { | ||||||
| data, err := yaml.Marshal(machineDef) | ||||||
| if err != nil { | ||||||
| return errors.Wrapf(err, "marshal master %d", i) | ||||||
| } | ||||||
|
|
||||||
| padded := fmt.Sprintf(padFormat, i) | ||||||
| w.MachineFiles[i] = &asset.File{ | ||||||
| Filename: filepath.Join(directory, fmt.Sprintf(workerMachineFileName, padded)), | ||||||
| Data: data, | ||||||
| } | ||||||
| if w.MachineFiles, err = serialize(machines, workerMachineFileName, false); err != nil { | ||||||
| return fmt.Errorf("failed to serialize worker machines: %w", err) | ||||||
| } | ||||||
| return nil | ||||||
| } | ||||||
|
|
@@ -966,3 +928,33 @@ func (w *Worker) MachineSets() ([]machinev1beta1.MachineSet, error) { | |||||
|
|
||||||
| return machineSets, nil | ||||||
| } | ||||||
|
|
||||||
| // serialize marshals a list of runtime.Object manifests into asset files. | ||||||
| // When useObjectName is true, the object's metadata name is used in the filename, | ||||||
| // e.g. "99_openshift-machine-api_claim-cluster-worker-0-claim-0-0.yaml". | ||||||
| // When false, a zero-padded index is used instead, | ||||||
| // e.g. "99_openshift-cluster-api_worker-machineset-0.yaml". | ||||||
| func serialize(manifests []runtime.Object, fileName string, useObjectName bool) ([]*asset.File, error) { | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
nit: It's actually a name template, right? Probably clearer to use it this way. |
||||||
| files := make([]*asset.File, len(manifests)) | ||||||
| padFormat := fmt.Sprintf("%%0%dd", len(fmt.Sprintf("%d", len(manifests)))) | ||||||
| for i, m := range manifests { | ||||||
| data, err := yaml.Marshal(m) | ||||||
| if err != nil { | ||||||
| return nil, fmt.Errorf("marshaling %s: %w", fmt.Sprintf(fileName, i), err) | ||||||
| } | ||||||
|
|
||||||
| key := fmt.Sprintf(padFormat, i) | ||||||
| if useObjectName { | ||||||
| accessor, err := meta.Accessor(m) | ||||||
| if err != nil { | ||||||
| return nil, fmt.Errorf("accessing object metadata: %w", err) | ||||||
| } | ||||||
| key = accessor.GetName() | ||||||
| } | ||||||
| files[i] = &asset.File{ | ||||||
| Filename: filepath.Join(directory, fmt.Sprintf(fileName, key)), | ||||||
|
Comment on lines
+937
to
+955
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "serialize() error path:"
sed -n '937,945p' pkg/asset/machines/worker.go
echo
echo "Filename format definitions used by the changed call sites:"
rg -n -C1 'workerMachineSetFileName =|workerMachineFileName =|ipClaimFileName\s*=|ipAddressFileName\s*=' pkg/asset/machinesRepository: openshift/installer Length of output: 1544 🏁 Script executed: cat -n pkg/asset/machines/worker.go | sed -n '937,960p'Repository: openshift/installer Length of output: 974 Move key and filename computation before the marshal call to fix the error message. Line 943 uses Suggested fix func serialize(manifests []runtime.Object, fileName string, useObjectName bool) ([]*asset.File, error) {
files := make([]*asset.File, len(manifests))
padFormat := fmt.Sprintf("%%0%dd", len(fmt.Sprintf("%d", len(manifests))))
for i, m := range manifests {
- data, err := yaml.Marshal(m)
- if err != nil {
- return nil, fmt.Errorf("marshaling %s: %w", fmt.Sprintf(fileName, i), err)
- }
-
key := fmt.Sprintf(padFormat, i)
if useObjectName {
accessor, err := meta.Accessor(m)
if err != nil {
return nil, fmt.Errorf("accessing object metadata: %w", err)
}
key = accessor.GetName()
}
+ filename := filepath.Join(directory, fmt.Sprintf(fileName, key))
+
+ data, err := yaml.Marshal(m)
+ if err != nil {
+ return nil, fmt.Errorf("marshaling %s: %w", filename, err)
+ }
files[i] = &asset.File{
- Filename: filepath.Join(directory, fmt.Sprintf(fileName, key)),
+ Filename: filename,
Data: data,
}
}
return files, nil
}🤖 Prompt for AI Agents
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 here. It should only affect error message, but makes sense to fix 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Failed to handle agent chat message. Please try again. |
||||||
| Data: data, | ||||||
| } | ||||||
| } | ||||||
| return files, nil | ||||||
| } | ||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: openshift/installer
Length of output: 483
Fix pointer aliasing in range loops before serialization
At Lines 731, 734, and 737, taking
&m,&c, and&acaptures reused range variables. All appended pointers will reference the same memory location, ending up with slices containing repeated pointers to the last iterated object instead of distinct elements.Proposed fix
🤖 Prompt for AI Agents
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No fix needed. The module uses Go 1.25, and since Go 1.22, range variables are scoped per iteration — each m, c, and a is a fresh variable, so &m, &c, and &a point to distinct instances. There's no aliasing bug here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See https://go.dev/doc/go1.22#language for release note that contains the fix for pointer aliasing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.