Skip to content

Commit 6d4814a

Browse files
authored
Fix for rebase omitting os/arch config properties (#751) (#752)
* Quick fix for missing `os` and `architecture` config properties, required by config spec [1] * Also include unspec'd `os.version` property which is required for Windows images to run on Windows containers [2] This implementation takes these three properties from newBase, which most accurately defines the newly rebased image's os/architecture. If the properties were taken from original, it would prevent reuse of de-facto ABI-compatible top layers with differing old and new base images (i.e. data-only top layers rebased from amd64 to arm, Windows os.version upgrades). This does not address additional, optional config properties that are currently being omitted during rebase such as `author` and `created`. Fixes [#751] [1]: https://github.com/opencontainers/image-spec/blob/master/config.md#properties [2]: https://docs.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/version-compatibility#matching-container-host-version-with-container-image-versions Signed-off-by: Micah Young <[email protected]>
1 parent b0d31a1 commit 6d4814a

File tree

4 files changed

+62
-9
lines changed

4 files changed

+62
-9
lines changed

go.mod

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

go.sum

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

pkg/v1/mutate/rebase.go

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,23 +60,42 @@ func Rebase(orig, oldBase, newBase v1.Image) (v1.Image, error) {
6060
return nil, fmt.Errorf("failed to get config for original: %v", err)
6161
}
6262

63+
newConfig, err := newBase.ConfigFile()
64+
if err != nil {
65+
return nil, fmt.Errorf("could not get config for new base: %v", err)
66+
}
67+
6368
// Stitch together an image that contains:
6469
// - original image's config
70+
// - new base image's os/arch properties
6571
// - new base image's layers + top of original image's layers
6672
// - new base image's history + top of original image's history
6773
rebasedImage, err := Config(empty.Image, *origConfig.Config.DeepCopy())
6874
if err != nil {
6975
return nil, fmt.Errorf("failed to create empty image with original config: %v", err)
7076
}
77+
78+
// Add new config properties from existing images.
79+
rebasedConfig, err := rebasedImage.ConfigFile()
80+
if err != nil {
81+
return nil, fmt.Errorf("could not get config for rebased image: %v", err)
82+
}
83+
// OS/Arch properties from new base
84+
rebasedConfig.Architecture = newConfig.Architecture
85+
rebasedConfig.OS = newConfig.OS
86+
rebasedConfig.OSVersion = newConfig.OSVersion
87+
88+
// Apply config properties to rebased.
89+
rebasedImage, err = ConfigFile(rebasedImage, rebasedConfig)
90+
if err != nil {
91+
return nil, fmt.Errorf("failed to replace config for rebased image: %v", err)
92+
}
93+
7194
// Get new base layers and config for history.
7295
newBaseLayers, err := newBase.Layers()
7396
if err != nil {
7497
return nil, fmt.Errorf("could not get new base layers for new base: %v", err)
7598
}
76-
newConfig, err := newBase.ConfigFile()
77-
if err != nil {
78-
return nil, fmt.Errorf("could not get config for new base: %v", err)
79-
}
8099
// Add new base layers.
81100
rebasedImage, err = Append(rebasedImage, createAddendums(0, 0, newConfig.History, newBaseLayers)...)
82101
if err != nil {

pkg/v1/mutate/rebase_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,20 @@ func TestRebase(t *testing.T) {
9797
t.Log("New base:")
9898
newBaseLayerDigests := layerDigests(t, newBase)
9999

100+
// Add config file os/arch property fields
101+
newBaseConfigFile, err := newBase.ConfigFile()
102+
if err != nil {
103+
t.Fatalf("newBase.ConfigFile: %v", err)
104+
}
105+
newBaseConfigFile.Architecture = "arm"
106+
newBaseConfigFile.OS = "windows"
107+
newBaseConfigFile.OSVersion = "10.0.17763.1339"
108+
109+
newBase, err = mutate.ConfigFile(newBase, newBaseConfigFile)
110+
if err != nil {
111+
t.Fatalf("ConfigFile (newBase): %v", err)
112+
}
113+
100114
// Rebase original image onto new base.
101115
rebased, err := mutate.Rebase(orig, oldBase, newBase)
102116
if err != nil {
@@ -151,4 +165,15 @@ func TestRebase(t *testing.T) {
151165
t.Errorf("Layer %d mismatch, got %q, want %q", i, got, want)
152166
}
153167
}
168+
169+
// Compare ConfigFile property fields copied from new base.
170+
if rebasedConfig.Architecture != newBaseConfig.Architecture {
171+
t.Errorf("ConfigFile property Architecture mismatch, got %q, want %q", rebasedConfig.Architecture, newBaseConfig.Architecture)
172+
}
173+
if rebasedConfig.OS != newBaseConfig.OS {
174+
t.Errorf("ConfigFile property OS mismatch, got %q, want %q", rebasedConfig.OS, newBaseConfig.OS)
175+
}
176+
if rebasedConfig.OSVersion != newBaseConfig.OSVersion {
177+
t.Errorf("ConfigFile property OSVersion mismatch, got %q, want %q", rebasedConfig.OSVersion, newBaseConfig.OSVersion)
178+
}
154179
}

0 commit comments

Comments
 (0)