Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions butane/config/openshift/v4_18/translate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -513,3 +513,39 @@ func TestValidateSupport(t *testing.T) {
})
}
}

// TestMachineConfigYAMLLargeSizeMiB is the OCPBUGS-114735 / #2309 regression:
// MachineConfig YAML must encode sizeMiB >= 1e6 as a plain integer.
func TestMachineConfigYAMLLargeSizeMiB(t *testing.T) {
in := `variant: openshift
version: 4.18.0
metadata:
name: 98-master-partition
labels:
machineconfiguration.openshift.io/role: master
storage:
disks:
- device: /dev/disk/by-id/virtio-targetdisk
partitions:
- number: 4
label: root
size_mib: 8389000
resize: true
- number: 5
label: var
size_mib: 0
- number: 6
label: odf-1
size_mib: 1231872
`
out, r, err := ToConfigBytes([]byte(in), common.TranslateBytesOptions{})
assert.NoError(t, err)
assert.False(t, r.IsFatal())
got := string(out)
assert.Contains(t, got, "sizeMiB: 8389000")
assert.Contains(t, got, "sizeMiB: 1231872")
assert.Contains(t, got, "sizeMiB: 0")
assert.NotContains(t, got, "8.389e+06")
assert.NotContains(t, got, "1.231872e+06")
assert.NotContains(t, got, "e+")
}
47 changes: 45 additions & 2 deletions butane/config/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ func TranslateBytesYAML(input []byte, container interface{}, translateMethod str
return jsonCfg, r, err
}

var ifaceCfg interface{}
if err := json.Unmarshal(jsonCfg, &ifaceCfg); err != nil {
ifaceCfg, err := unmarshalJSONForYAML(jsonCfg)
if err != nil {
return []byte{}, r, err
}

Expand All @@ -174,6 +174,49 @@ func TranslateBytesYAML(input []byte, container interface{}, translateMethod str
return yamlCfg, r, err
}

// unmarshalJSONForYAML decodes JSON into a generic structure suitable for
// YAML encoding. Integers are preserved as int64 so yaml.v3 does not emit
// scientific notation for values >= 1e6 (e.g. sizeMiB: 8.389e+06).
func unmarshalJSONForYAML(jsonCfg []byte) (interface{}, error) {
dec := json.NewDecoder(bytes.NewReader(jsonCfg))
dec.UseNumber()
var ifaceCfg interface{}
if err := dec.Decode(&ifaceCfg); err != nil {
return nil, err
}
return convertJSONNumbers(ifaceCfg), nil
}

// convertJSONNumbers walks a decoded JSON tree and replaces json.Number
// values with int64 when possible, otherwise float64. json.Unmarshal into
// interface{} otherwise uses float64, and yaml.v3 then formats values >= 1e6
// with strconv.FormatFloat 'g' as scientific notation.
func convertJSONNumbers(v interface{}) interface{} {
switch x := v.(type) {
case map[string]interface{}:
for k, val := range x {
x[k] = convertJSONNumbers(val)
}
return x
case []interface{}:
for i, val := range x {
x[i] = convertJSONNumbers(val)
}
return x
case json.Number:
if i, err := x.Int64(); err == nil {
return i
}
f, err := x.Float64()
if err != nil {
return x.String()
}
return f
default:
return v
}
}

// Report an ErrFieldElided warning for any non-zero top-level fields in the
// specified output struct. The caller will probably want to use
// translate.PrefixReport() to reparent the report into the right place in
Expand Down
22 changes: 22 additions & 0 deletions butane/config/util/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
package util

import (
"bytes"
"fmt"
"strings"
"testing"

"github.com/coreos/ignition/v2/butane/config/common"
Expand All @@ -24,6 +26,7 @@ import (
"github.com/coreos/vcontext/path"
"github.com/coreos/vcontext/report"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
)

func TestSnake(t *testing.T) {
Expand Down Expand Up @@ -119,3 +122,22 @@ func TestTranslateReportPaths(t *testing.T) {
assert.Equal(t, makeReport(false), r, "TranslateReportPaths changed original report")
assert.Equal(t, makeReport(true), r2, "TranslateReportPaths returned incorrect report")
}

func TestUnmarshalJSONForYAMLIntegers(t *testing.T) {
jsonCfg := []byte(`{"sizeMiB":8389000,"startMiB":2048,"values":[1000000],"ratio":1.5}`)
v, err := unmarshalJSONForYAML(jsonCfg)
assert.NoError(t, err)

var buf bytes.Buffer
enc := yaml.NewEncoder(&buf)
enc.SetIndent(2)
assert.NoError(t, enc.Encode(v))
assert.NoError(t, enc.Close())
out := buf.String()

assert.Contains(t, out, "sizeMiB: 8389000")
assert.Contains(t, out, "startMiB: 2048")
assert.Contains(t, out, "- 1000000")
assert.Contains(t, out, "ratio: 1.5")
assert.False(t, strings.Contains(out, "e+"), "YAML must not use scientific notation: %s", out)
}
4 changes: 4 additions & 0 deletions docs/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ nav_order: 9

### Bug fixes

- Encode large integer fields such as `sizeMiB` as decimal numbers in
MachineConfig YAML, instead of scientific notation
([#2309](https://github.com/coreos/ignition/issues/2309))
([OCPBUGS-114735](https://redhat.atlassian.net/browse/OCPBUGS-114735))

## Ignition 2.27.0 (2026-08-26)

Expand Down