Skip to content

Commit 8710137

Browse files
Merge pull request openshift#7349 from jeffdyoung/OCPBUGS-15941
OCPBUGS-15941: ABI - Validate release image arch, add cpu_architectures to RELEASE_IMAGES
2 parents acaad71 + 19f298a commit 8710137

File tree

10 files changed

+206
-112
lines changed

10 files changed

+206
-112
lines changed

pkg/asset/agent/common.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package agent
22

33
import (
4+
"github.com/sirupsen/logrus"
5+
46
hiveext "github.com/openshift/assisted-service/api/hiveextension/v1beta1"
57
"github.com/openshift/installer/pkg/types"
68
"github.com/openshift/installer/pkg/types/baremetal"
@@ -56,3 +58,25 @@ func IsSupportedPlatform(platform hiveext.PlatformType) bool {
5658
}
5759
return false
5860
}
61+
62+
// DetermineReleaseImageArch returns the arch of the release image.
63+
func DetermineReleaseImageArch(pullSecret, pullSpec string) (string, error) {
64+
templateFilter := "-o=go-template={{if and .metadata.metadata (index . \"metadata\" \"metadata\" \"release.openshift.io/architecture\")}}{{index . \"metadata\" \"metadata\" \"release.openshift.io/architecture\"}}{{else}}{{.config.architecture}}{{end}}"
65+
66+
var getReleaseArch = []string{
67+
"oc",
68+
"adm",
69+
"release",
70+
"info",
71+
pullSpec,
72+
templateFilter,
73+
}
74+
75+
releaseArch, err := ExecuteOC(pullSecret, getReleaseArch)
76+
if err != nil {
77+
logrus.Errorf("Release Image arch could not be found: %s", err)
78+
return "", err
79+
}
80+
logrus.Debugf("Release Image arch is: %s", releaseArch)
81+
return releaseArch, nil
82+
}

pkg/asset/agent/image/ignition.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/openshift/assisted-service/api/v1beta1"
2222
"github.com/openshift/assisted-service/models"
2323
"github.com/openshift/installer/pkg/asset"
24+
agentcommon "github.com/openshift/installer/pkg/asset/agent"
2425
"github.com/openshift/installer/pkg/asset/agent/agentconfig"
2526
"github.com/openshift/installer/pkg/asset/agent/manifests"
2627
"github.com/openshift/installer/pkg/asset/agent/mirror"
@@ -135,8 +136,20 @@ func (a *Ignition) Generate(dependencies asset.Parents) error {
135136
if infraEnv.Spec.CpuArchitecture != "" {
136137
archName = infraEnv.Spec.CpuArchitecture
137138
}
138-
139-
releaseImageList, err := releaseImageList(agentManifests.ClusterImageSet.Spec.ReleaseImage, archName)
139+
// Examine the release payload to see if its multi
140+
releaseArch, err := agentcommon.DetermineReleaseImageArch(agentManifests.GetPullSecretData(), agentManifests.ClusterImageSet.Spec.ReleaseImage)
141+
if err != nil {
142+
logrus.Warnf("Unable to validate the release image architecture, using infraEnv.Spec.CpuArchitecture for the release image arch")
143+
releaseArch = archName
144+
} else {
145+
releaseArch = arch.RpmArch(releaseArch)
146+
logrus.Debugf("Found Release Image Architecture: %s", releaseArch)
147+
}
148+
releaseArchs := []string{releaseArch}
149+
if releaseArch == "multi" {
150+
releaseArchs = []string{arch.RpmArch(types.ArchitectureARM64), arch.RpmArch(types.ArchitectureAMD64), arch.RpmArch(types.ArchitecturePPC64LE), arch.RpmArch(types.ArchitectureS390X)}
151+
}
152+
releaseImageList, err := releaseImageList(agentManifests.ClusterImageSet.Spec.ReleaseImage, releaseArch, releaseArchs)
140153
if err != nil {
141154
return err
142155
}

pkg/asset/agent/image/ignition_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func TestIgnition_getTemplateData(t *testing.T) {
6565
haveMirrorConfig := true
6666
publicContainerRegistries := "quay.io,registry.ci.openshift.org"
6767

68-
releaseImageList, err := releaseImageList(clusterImageSet.Spec.ReleaseImage, "x86_64")
68+
releaseImageList, err := releaseImageList(clusterImageSet.Spec.ReleaseImage, "x86_64", []string{"86_64"})
6969
assert.NoError(t, err)
7070

7171
arch := "x86_64"
Lines changed: 43 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"sigs.k8s.io/yaml"
2525

2626
operatorv1alpha1 "github.com/openshift/api/operator/v1alpha1"
27+
"github.com/openshift/installer/pkg/asset/agent"
2728
"github.com/openshift/installer/pkg/asset/agent/mirror"
2829
"github.com/openshift/installer/pkg/rhcos"
2930
"github.com/openshift/installer/pkg/rhcos/cache"
@@ -34,19 +35,19 @@ const (
3435
coreOsFileName = "/coreos/coreos-%s.iso"
3536
coreOsSha256FileName = "/coreos/coreos-%s.iso.sha256"
3637
coreOsStreamFileName = "/coreos/coreos-stream.json"
37-
//OcDefaultTries is the number of times to execute the oc command on failues
38+
// OcDefaultTries is the number of times to execute the oc command on failures.
3839
OcDefaultTries = 5
39-
// OcDefaultRetryDelay is the time between retries
40+
// OcDefaultRetryDelay is the time between retries.
4041
OcDefaultRetryDelay = time.Second * 5
4142
)
4243

43-
// Config is used to set up the retries for extracting the base ISO
44+
// Config is used to set up the retries for extracting the base ISO.
4445
type Config struct {
4546
MaxTries uint
4647
RetryDelay time.Duration
4748
}
4849

49-
// Release is the interface to use the oc command to the get image info
50+
// Release is the interface to use the oc command to the get image info.
5051
type Release interface {
5152
GetBaseIso(architecture string) (string, error)
5253
GetBaseIsoVersion(architecture string) (string, error)
@@ -60,7 +61,7 @@ type release struct {
6061
mirrorConfig []mirror.RegistriesConfig
6162
}
6263

63-
// NewRelease is used to set up the executor to run oc commands
64+
// NewRelease is used to set up the executor to run oc commands.
6465
func NewRelease(config Config, releaseImage string, pullSecret string, mirrorConfig []mirror.RegistriesConfig) Release {
6566
return &release{
6667
config: config,
@@ -70,13 +71,6 @@ func NewRelease(config Config, releaseImage string, pullSecret string, mirrorCon
7071
}
7172
}
7273

73-
const (
74-
templateGetImage = "oc adm release info --image-for=%s --filter-by-os=linux/%s --insecure=%t %s"
75-
templateGetImageWithIcsp = "oc adm release info --image-for=%s --filter-by-os=linux/%s --insecure=%t --icsp-file=%s %s"
76-
templateImageExtract = "oc image extract --path %s:%s --filter-by-os=linux/%s --confirm %s"
77-
templateImageExtractWithIcsp = "oc image extract --path %s:%s --filter-by-os=linux/%s --confirm --icsp-file=%s %s"
78-
)
79-
8074
// ExtractFile extracts the specified file from the given image name, and store it in the cache dir.
8175
func (r *release) ExtractFile(image string, filename string, architecture string) ([]string, error) {
8276
imagePullSpec, err := r.getImageFromRelease(image, architecture)
@@ -171,7 +165,6 @@ func (r *release) GetBaseIsoVersion(architecture string) (string, error) {
171165
func (r *release) getImageFromRelease(imageName string, architecture string) (string, error) {
172166
// This requires the 'oc' command so make sure its available
173167
_, err := exec.LookPath("oc")
174-
var cmd string
175168
if err != nil {
176169
if len(r.mirrorConfig) > 0 {
177170
logrus.Warning("Unable to validate mirror config because \"oc\" command is not available")
@@ -182,21 +175,32 @@ func (r *release) getImageFromRelease(imageName string, architecture string) (st
182175
}
183176

184177
archName := arch.GoArch(architecture)
185-
178+
imagefor := "--image-for=" + imageName
179+
filterbyos := "--filter-by-os=linux/" + archName
180+
insecure := "--insecure=true"
181+
182+
var cmd = []string{
183+
"oc",
184+
"adm",
185+
"release",
186+
"info",
187+
imagefor,
188+
filterbyos,
189+
insecure,
190+
}
186191
if len(r.mirrorConfig) > 0 {
187192
logrus.Debugf("Using mirror configuration")
188193
icspFile, err := getIcspFileFromRegistriesConfig(r.mirrorConfig)
189194
if err != nil {
190195
return "", err
191196
}
192197
defer removeIcspFile(icspFile)
193-
cmd = fmt.Sprintf(templateGetImageWithIcsp, imageName, archName, true, icspFile, r.releaseImage)
194-
} else {
195-
cmd = fmt.Sprintf(templateGetImage, imageName, archName, true, r.releaseImage)
198+
icspfile := "--icsp-file=" + icspFile
199+
cmd = append(cmd, icspfile)
196200
}
197-
201+
cmd = append(cmd, r.releaseImage)
198202
logrus.Debugf("Fetching image from OCP release (%s)", cmd)
199-
image, err := execute(r.pullSecret, cmd)
203+
image, err := agent.ExecuteOC(r.pullSecret, cmd)
200204
if err != nil {
201205
if strings.Contains(err.Error(), "unknown flag: --icsp-file") {
202206
logrus.Warning("Using older version of \"oc\" that does not support mirroring")
@@ -208,26 +212,36 @@ func (r *release) getImageFromRelease(imageName string, architecture string) (st
208212
}
209213

210214
func (r *release) extractFileFromImage(image, file, cacheDir string, architecture string) ([]string, error) {
211-
var cmd string
212215
archName := arch.GoArch(architecture)
216+
extractpath := "--path=" + file + ":" + cacheDir
217+
filterbyos := "--filter-by-os=linux/" + archName
218+
219+
var cmd = []string{
220+
"oc",
221+
"image",
222+
"extract",
223+
extractpath,
224+
filterbyos,
225+
"--confirm",
226+
}
227+
213228
if len(r.mirrorConfig) > 0 {
214229
icspFile, err := getIcspFileFromRegistriesConfig(r.mirrorConfig)
215230
if err != nil {
216231
return nil, err
217232
}
218233
defer removeIcspFile(icspFile)
219-
cmd = fmt.Sprintf(templateImageExtractWithIcsp, file, cacheDir, archName, icspFile, image)
220-
} else {
221-
cmd = fmt.Sprintf(templateImageExtract, file, cacheDir, archName, image)
234+
icspfile := "--icsp-file=" + icspFile
235+
cmd = append(cmd, icspfile)
222236
}
223237
path := filepath.Join(cacheDir, path.Base(file))
224238
// Remove file if it exists
225239
if err := removeCacheFile(path); err != nil {
226240
return nil, err
227241
}
228-
242+
cmd = append(cmd, image)
229243
logrus.Debugf("extracting %s to %s, %s", file, cacheDir, cmd)
230-
_, err := retry.Do(r.config.MaxTries, r.config.RetryDelay, execute, r.pullSecret, cmd)
244+
_, err := retry.Do(r.config.MaxTries, r.config.RetryDelay, agent.ExecuteOC, r.pullSecret, cmd)
231245
if err != nil {
232246
return nil, err
233247
}
@@ -244,7 +258,7 @@ func (r *release) extractFileFromImage(image, file, cacheDir string, architectur
244258
return matches, nil
245259
}
246260

247-
// Get hash from rhcos.json
261+
// Get hash from rhcos.json.
248262
func getHashFromInstaller(architecture string) (bool, string) {
249263
// Get hash from metadata in the installer
250264
ctx, cancel := context.WithTimeout(context.TODO(), 30*time.Second)
@@ -277,7 +291,7 @@ func matchingHash(imageSha []byte, sha string) bool {
277291
return false
278292
}
279293

280-
// Check if there is a different base ISO in the release payload
294+
// Check if there is a different base ISO in the release payload.
281295
func (r *release) verifyCacheFile(image, file, architecture string) (bool, error) {
282296
// Get hash of cached file
283297
f, err := os.Open(file)
@@ -343,44 +357,7 @@ func removeCacheFile(path string) error {
343357
return nil
344358
}
345359

346-
func execute(pullSecret, command string) (string, error) {
347-
ps, err := os.CreateTemp("", "registry-config")
348-
if err != nil {
349-
return "", err
350-
}
351-
defer func() {
352-
ps.Close()
353-
os.Remove(ps.Name())
354-
}()
355-
_, err = ps.Write([]byte(pullSecret))
356-
if err != nil {
357-
return "", err
358-
}
359-
// flush the buffer to ensure the file can be read
360-
ps.Close()
361-
executeCommand := command[:] + " --registry-config=" + ps.Name()
362-
args := strings.Split(executeCommand, " ")
363-
364-
var stdoutBytes, stderrBytes bytes.Buffer
365-
cmd := exec.Command(args[0], args[1:]...) //nolint:gosec
366-
cmd.Stdout = &stdoutBytes
367-
cmd.Stderr = &stderrBytes
368-
369-
err = cmd.Run()
370-
if err == nil {
371-
return strings.TrimSpace(stdoutBytes.String()), nil
372-
}
373-
374-
var exitErr *exec.ExitError
375-
if errors.As(err, &exitErr) {
376-
err = fmt.Errorf("command '%s' exited with non-zero exit code %d: %s\n%s", executeCommand, exitErr.ExitCode(), stdoutBytes.String(), stderrBytes.String())
377-
} else {
378-
err = fmt.Errorf("command '%s' failed: %w", executeCommand, err)
379-
}
380-
return "", err
381-
}
382-
383-
// Create a temporary file containing the ImageContentPolicySources
360+
// Create a temporary file containing the ImageContentPolicySources.
384361
func getIcspFileFromRegistriesConfig(mirrorConfig []mirror.RegistriesConfig) (string, error) {
385362
contents, err := getIcspContents(mirrorConfig)
386363
if err != nil {
@@ -406,7 +383,7 @@ func getIcspFileFromRegistriesConfig(mirrorConfig []mirror.RegistriesConfig) (st
406383
return icspFile.Name(), nil
407384
}
408385

409-
// Convert the data in registries.conf into ICSP format
386+
// Convert the data in registries.conf into ICSP format.
410387
func getIcspContents(mirrorConfig []mirror.RegistriesConfig) ([]byte, error) {
411388
icsp := operatorv1alpha1.ImageContentSourcePolicy{
412389
TypeMeta: metav1.TypeMeta{

pkg/asset/agent/image/releaseimage.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ import (
1010
)
1111

1212
type releaseImage struct {
13-
ReleaseVersion string `json:"openshift_version"`
14-
Arch string `json:"cpu_architecture"`
15-
PullSpec string `json:"url"`
16-
Tag string `json:"version"`
13+
ReleaseVersion string `json:"openshift_version"`
14+
Arch string `json:"cpu_architecture"`
15+
Archs []string `json:"cpu_architectures"`
16+
PullSpec string `json:"url"`
17+
Tag string `json:"version"`
1718
}
1819

1920
func isDigest(pullspec string) bool {
2021
return regexp.MustCompile(`.*sha256:[a-fA-F0-9]{64}$`).MatchString(pullspec)
2122
}
2223

23-
func releaseImageFromPullSpec(pullSpec, arch string) (releaseImage, error) {
24-
24+
func releaseImageFromPullSpec(pullSpec, arch string, archs []string) (releaseImage, error) {
2525
// When the pullspec it's a digest let's use the current version
2626
// stored in the installer
2727
if isDigest(pullSpec) {
@@ -33,6 +33,7 @@ func releaseImageFromPullSpec(pullSpec, arch string) (releaseImage, error) {
3333
return releaseImage{
3434
ReleaseVersion: versionString,
3535
Arch: arch,
36+
Archs: archs,
3637
PullSpec: pullSpec,
3738
Tag: versionString,
3839
}, nil
@@ -54,14 +55,14 @@ func releaseImageFromPullSpec(pullSpec, arch string) (releaseImage, error) {
5455
return releaseImage{
5556
ReleaseVersion: relVersion,
5657
Arch: arch,
58+
Archs: archs,
5759
PullSpec: pullSpec,
5860
Tag: tag,
5961
}, nil
6062
}
6163

62-
func releaseImageList(pullSpec, arch string) (string, error) {
63-
64-
relImage, err := releaseImageFromPullSpec(pullSpec, arch)
64+
func releaseImageList(pullSpec, arch string, archs []string) (string, error) {
65+
relImage, err := releaseImageFromPullSpec(pullSpec, arch, archs)
6566
if err != nil {
6667
return "", err
6768
}

pkg/asset/agent/image/releaseimage_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,37 +17,37 @@ func TestReleaseImageList(t *testing.T) {
1717
name: "4.10rc",
1818
pullSpec: "quay.io/openshift-release-dev/ocp-release:4.10.0-rc.1-x86_64",
1919
arch: "x86_64",
20-
result: "[{\"openshift_version\":\"4.10\",\"cpu_architecture\":\"x86_64\",\"url\":\"quay.io/openshift-release-dev/ocp-release:4.10.0-rc.1-x86_64\",\"version\":\"4.10.0-rc.1\"}]",
20+
result: "[{\"openshift_version\":\"4.10\",\"cpu_architecture\":\"x86_64\",\"cpu_architectures\":[\"x86_64\"],\"url\":\"quay.io/openshift-release-dev/ocp-release:4.10.0-rc.1-x86_64\",\"version\":\"4.10.0-rc.1\"}]",
2121
},
2222
{
2323
name: "pull-spec-includes-port-number",
2424
pullSpec: "quay.io:433/openshift-release-dev/ocp-release:4.10.0-rc.1-x86_64",
2525
arch: "x86_64",
26-
result: "[{\"openshift_version\":\"4.10\",\"cpu_architecture\":\"x86_64\",\"url\":\"quay.io:433/openshift-release-dev/ocp-release:4.10.0-rc.1-x86_64\",\"version\":\"4.10.0-rc.1\"}]",
26+
result: "[{\"openshift_version\":\"4.10\",\"cpu_architecture\":\"x86_64\",\"cpu_architectures\":[\"x86_64\"],\"url\":\"quay.io:433/openshift-release-dev/ocp-release:4.10.0-rc.1-x86_64\",\"version\":\"4.10.0-rc.1\"}]",
2727
},
2828
{
2929
name: "arm",
3030
pullSpec: "quay.io/openshift-release-dev/ocp-release:4.10.0-rc.1-aarch64",
3131
arch: "aarch64",
32-
result: "[{\"openshift_version\":\"4.10\",\"cpu_architecture\":\"aarch64\",\"url\":\"quay.io/openshift-release-dev/ocp-release:4.10.0-rc.1-aarch64\",\"version\":\"4.10.0-rc.1\"}]",
32+
result: "[{\"openshift_version\":\"4.10\",\"cpu_architecture\":\"aarch64\",\"cpu_architectures\":[\"aarch64\"],\"url\":\"quay.io/openshift-release-dev/ocp-release:4.10.0-rc.1-aarch64\",\"version\":\"4.10.0-rc.1\"}]",
3333
},
3434
{
3535
name: "4.11ci",
3636
pullSpec: "registry.ci.openshift.org/ocp/release:4.11.0-0.ci-2022-05-16-202609",
3737
arch: "x86_64",
38-
result: "[{\"openshift_version\":\"4.11\",\"cpu_architecture\":\"x86_64\",\"url\":\"registry.ci.openshift.org/ocp/release:4.11.0-0.ci-2022-05-16-202609\",\"version\":\"4.11.0-0.ci-2022-05-16-202609\"}]",
38+
result: "[{\"openshift_version\":\"4.11\",\"cpu_architecture\":\"x86_64\",\"cpu_architectures\":[\"x86_64\"],\"url\":\"registry.ci.openshift.org/ocp/release:4.11.0-0.ci-2022-05-16-202609\",\"version\":\"4.11.0-0.ci-2022-05-16-202609\"}]",
3939
},
4040
{
4141
name: "CI-ephemeral",
4242
pullSpec: "registry.build04.ci.openshift.org/ci-op-m7rfgytz/release@sha256:ebb203f24ee060d61bdb466696a9c20b3841f9929badf9b81fc99cbedc2a679e",
4343
arch: "x86_64",
44-
result: "[{\"openshift_version\":\"was not built correctly\",\"cpu_architecture\":\"x86_64\",\"url\":\"registry.build04.ci.openshift.org/ci-op-m7rfgytz/release@sha256:ebb203f24ee060d61bdb466696a9c20b3841f9929badf9b81fc99cbedc2a679e\",\"version\":\"was not built correctly\"}]",
44+
result: "[{\"openshift_version\":\"was not built correctly\",\"cpu_architecture\":\"x86_64\",\"cpu_architectures\":[\"x86_64\"],\"url\":\"registry.build04.ci.openshift.org/ci-op-m7rfgytz/release@sha256:ebb203f24ee060d61bdb466696a9c20b3841f9929badf9b81fc99cbedc2a679e\",\"version\":\"was not built correctly\"}]",
4545
},
4646
}
4747

4848
for _, tc := range cases {
4949
t.Run(tc.name, func(t *testing.T) {
50-
output, err := releaseImageList(tc.pullSpec, tc.arch)
50+
output, err := releaseImageList(tc.pullSpec, tc.arch, []string{tc.arch})
5151
assert.NoError(t, err)
5252
if err == nil {
5353
assert.Equal(t, tc.result, output)
@@ -65,7 +65,7 @@ func TestReleaseImageListErrors(t *testing.T) {
6565

6666
for _, tc := range cases {
6767
t.Run(tc, func(t *testing.T) {
68-
_, err := releaseImageList(tc, "x86_64")
68+
_, err := releaseImageList(tc, "x86_64", []string{"x86_64"})
6969
assert.Error(t, err)
7070
})
7171
}

0 commit comments

Comments
 (0)