mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-23 23:50:12 -06:00
Improve stability on 32-bit architectures (#1154)
Signed-off-by: James Humphries <james@james-humphries.co.uk>
This commit is contained in:
parent
444b059d28
commit
92a055b60f
@ -25,6 +25,7 @@ BUG FIXES:
|
|||||||
* Don't check for version conflicts when doing a force-unlock ([#1123](https://github.com/opentofu/opentofu/pull/1123))
|
* Don't check for version conflicts when doing a force-unlock ([#1123](https://github.com/opentofu/opentofu/pull/1123))
|
||||||
* Fix Global Schema Cache not working in provider acceptance tests ([#1054](https://github.com/opentofu/opentofu/pull/1054))
|
* Fix Global Schema Cache not working in provider acceptance tests ([#1054](https://github.com/opentofu/opentofu/pull/1054))
|
||||||
* Fix `tofu show` and `tofu state show` not working with state files referencing Terraform registry providers in some instances ([#1141](https://github.com/opentofu/opentofu/pull/1141))
|
* Fix `tofu show` and `tofu state show` not working with state files referencing Terraform registry providers in some instances ([#1141](https://github.com/opentofu/opentofu/pull/1141))
|
||||||
|
* Improved stability on 32-bit architectures ([#1154](https://github.com/opentofu/opentofu/pull/1154))
|
||||||
|
|
||||||
## Previous Releases
|
## Previous Releases
|
||||||
|
|
||||||
|
@ -10,19 +10,26 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// String hashes a string to a unique hashcode.
|
// String hashes a string to a unique hashcode.
|
||||||
//
|
// Returns a non-negative integer representing the hashcode of the string.
|
||||||
// crc32 returns a uint32, but for our use we need
|
|
||||||
// a non negative integer. Here we cast to an integer
|
|
||||||
// and invert it if the result is negative.
|
|
||||||
func String(s string) int {
|
func String(s string) int {
|
||||||
v := int(crc32.ChecksumIEEE([]byte(s)))
|
// crc32 returns an uint32, so we need to massage it into an int.
|
||||||
if v >= 0 {
|
crc := crc32.ChecksumIEEE([]byte(s))
|
||||||
return v
|
// We need to first squash the result to 32 bits, embracing the overflow
|
||||||
|
// to ensure that there is no difference between 32 and 64-bit
|
||||||
|
// platforms.
|
||||||
|
squashed := int32(crc)
|
||||||
|
// convert into a generic int that is sized as per the architecture
|
||||||
|
systemSized := int(squashed)
|
||||||
|
|
||||||
|
// If the integer is negative, we return the absolute value of the
|
||||||
|
// integer. This is because we want to return a non-negative integer
|
||||||
|
if systemSized >= 0 {
|
||||||
|
return systemSized
|
||||||
}
|
}
|
||||||
if -v >= 0 {
|
if -systemSized >= 0 {
|
||||||
return -v
|
return -systemSized
|
||||||
}
|
}
|
||||||
// v == MinInt
|
// systemSized == MinInt
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,7 +410,7 @@ func TestConfigFieldReader_ComputedSet(t *testing.T) {
|
|||||||
[]string{"strSet"},
|
[]string{"strSet"},
|
||||||
FieldReadResult{
|
FieldReadResult{
|
||||||
Value: map[string]interface{}{
|
Value: map[string]interface{}{
|
||||||
"2356372769": "foo",
|
"1938594527": "foo",
|
||||||
},
|
},
|
||||||
Exists: true,
|
Exists: true,
|
||||||
Computed: false,
|
Computed: false,
|
||||||
|
@ -5,7 +5,6 @@ package schema
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
@ -1587,6 +1586,7 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
var testNilPtr *string
|
var testNilPtr *string
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
|
TestName string
|
||||||
Schema map[string]*Schema
|
Schema map[string]*Schema
|
||||||
State *tofu.InstanceState
|
State *tofu.InstanceState
|
||||||
Diff *tofu.InstanceDiff
|
Diff *tofu.InstanceDiff
|
||||||
@ -1600,8 +1600,8 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
// compared to GetValue
|
// compared to GetValue
|
||||||
GetPreProcess func(interface{}) interface{}
|
GetPreProcess func(interface{}) interface{}
|
||||||
}{
|
}{
|
||||||
// #0: Basic good
|
|
||||||
{
|
{
|
||||||
|
TestName: "Basic good",
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"availability_zone": &Schema{
|
"availability_zone": &Schema{
|
||||||
Type: TypeString,
|
Type: TypeString,
|
||||||
@ -1621,9 +1621,8 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
GetKey: "availability_zone",
|
GetKey: "availability_zone",
|
||||||
GetValue: "foo",
|
GetValue: "foo",
|
||||||
},
|
},
|
||||||
|
|
||||||
// #1: Basic int
|
|
||||||
{
|
{
|
||||||
|
TestName: "Basic int",
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"port": &Schema{
|
"port": &Schema{
|
||||||
Type: TypeInt,
|
Type: TypeInt,
|
||||||
@ -1643,9 +1642,8 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
GetKey: "port",
|
GetKey: "port",
|
||||||
GetValue: 80,
|
GetValue: 80,
|
||||||
},
|
},
|
||||||
|
|
||||||
// #2: Basic bool
|
|
||||||
{
|
{
|
||||||
|
TestName: "Basic bool, true",
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"vpc": &Schema{
|
"vpc": &Schema{
|
||||||
Type: TypeBool,
|
Type: TypeBool,
|
||||||
@ -1663,9 +1661,8 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
GetKey: "vpc",
|
GetKey: "vpc",
|
||||||
GetValue: true,
|
GetValue: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
// #3
|
|
||||||
{
|
{
|
||||||
|
TestName: "Basic bool, false",
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"vpc": &Schema{
|
"vpc": &Schema{
|
||||||
Type: TypeBool,
|
Type: TypeBool,
|
||||||
@ -1683,9 +1680,8 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
GetKey: "vpc",
|
GetKey: "vpc",
|
||||||
GetValue: false,
|
GetValue: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
// #4: Invalid type
|
|
||||||
{
|
{
|
||||||
|
TestName: "Invalid type",
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"availability_zone": &Schema{
|
"availability_zone": &Schema{
|
||||||
Type: TypeString,
|
Type: TypeString,
|
||||||
@ -1706,9 +1702,8 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
GetKey: "availability_zone",
|
GetKey: "availability_zone",
|
||||||
GetValue: "",
|
GetValue: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
// #5: List of primitives, set list
|
|
||||||
{
|
{
|
||||||
|
TestName: "List of primitives, set list",
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ports": &Schema{
|
"ports": &Schema{
|
||||||
Type: TypeList,
|
Type: TypeList,
|
||||||
@ -1727,9 +1722,8 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
GetKey: "ports",
|
GetKey: "ports",
|
||||||
GetValue: []interface{}{1, 2, 5},
|
GetValue: []interface{}{1, 2, 5},
|
||||||
},
|
},
|
||||||
|
|
||||||
// #6: List of primitives, set list with error
|
|
||||||
{
|
{
|
||||||
|
TestName: "List of primitives, set list with error",
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ports": &Schema{
|
"ports": &Schema{
|
||||||
Type: TypeList,
|
Type: TypeList,
|
||||||
@ -1749,9 +1743,8 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
GetKey: "ports",
|
GetKey: "ports",
|
||||||
GetValue: []interface{}{},
|
GetValue: []interface{}{},
|
||||||
},
|
},
|
||||||
|
|
||||||
// #7: Set a list of maps
|
|
||||||
{
|
{
|
||||||
|
TestName: "Set a list of maps",
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"config_vars": &Schema{
|
"config_vars": &Schema{
|
||||||
Type: TypeList,
|
Type: TypeList,
|
||||||
@ -1788,9 +1781,8 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// #8: Set, with list
|
|
||||||
{
|
{
|
||||||
|
TestName: "Set, with list",
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ports": &Schema{
|
"ports": &Schema{
|
||||||
Type: TypeSet,
|
Type: TypeSet,
|
||||||
@ -1818,9 +1810,8 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
GetKey: "ports",
|
GetKey: "ports",
|
||||||
GetValue: []interface{}{100, 125},
|
GetValue: []interface{}{100, 125},
|
||||||
},
|
},
|
||||||
|
|
||||||
// #9: Set, with Set
|
|
||||||
{
|
{
|
||||||
|
TestName: " Set, with Set",
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ports": &Schema{
|
"ports": &Schema{
|
||||||
Type: TypeSet,
|
Type: TypeSet,
|
||||||
@ -1853,9 +1844,8 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
GetKey: "ports",
|
GetKey: "ports",
|
||||||
GetValue: []interface{}{1, 2},
|
GetValue: []interface{}{1, 2},
|
||||||
},
|
},
|
||||||
|
|
||||||
// #10: Set single item
|
|
||||||
{
|
{
|
||||||
|
TestName: "Set single item",
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ports": &Schema{
|
"ports": &Schema{
|
||||||
Type: TypeSet,
|
Type: TypeSet,
|
||||||
@ -1883,9 +1873,8 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
GetKey: "ports",
|
GetKey: "ports",
|
||||||
GetValue: []interface{}{100, 80},
|
GetValue: []interface{}{100, 80},
|
||||||
},
|
},
|
||||||
|
|
||||||
// #11: Set with nested set
|
|
||||||
{
|
{
|
||||||
|
TestName: "Set with nested set",
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ports": &Schema{
|
"ports": &Schema{
|
||||||
Type: TypeSet,
|
Type: TypeSet,
|
||||||
@ -1951,9 +1940,8 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
return v
|
return v
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// #12: List of floats, set list
|
|
||||||
{
|
{
|
||||||
|
TestName: "List of floats, set list",
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ratios": &Schema{
|
"ratios": &Schema{
|
||||||
Type: TypeList,
|
Type: TypeList,
|
||||||
@ -1972,16 +1960,20 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
GetKey: "ratios",
|
GetKey: "ratios",
|
||||||
GetValue: []interface{}{1.0, 2.2, 5.5},
|
GetValue: []interface{}{1.0, 2.2, 5.5},
|
||||||
},
|
},
|
||||||
|
|
||||||
// #12: Set of floats, set list
|
|
||||||
{
|
{
|
||||||
|
TestName: "Set of floats, set list",
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ratios": &Schema{
|
"ratios": &Schema{
|
||||||
Type: TypeSet,
|
Type: TypeSet,
|
||||||
Computed: true,
|
Computed: true,
|
||||||
Elem: &Schema{Type: TypeFloat},
|
Elem: &Schema{Type: TypeFloat},
|
||||||
Set: func(a interface{}) int {
|
Set: func(a interface{}) int {
|
||||||
return int(math.Float64bits(a.(float64)))
|
// Because we want to be safe on a 32-bit and 64-bit system,
|
||||||
|
// we can just set a "scale factor" here that's always larger than the number of
|
||||||
|
// decimal places we expect to see., and then multiply by that to cast to int
|
||||||
|
// otherwise we could get clashes in unique ids
|
||||||
|
scaleFactor := 100000
|
||||||
|
return int(a.(float64) * float64(scaleFactor))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1996,9 +1988,8 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
GetKey: "ratios",
|
GetKey: "ratios",
|
||||||
GetValue: []interface{}{1.0, 2.2, 5.5},
|
GetValue: []interface{}{1.0, 2.2, 5.5},
|
||||||
},
|
},
|
||||||
|
|
||||||
// #13: Basic pointer
|
|
||||||
{
|
{
|
||||||
|
TestName: "Basic pointer",
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"availability_zone": &Schema{
|
"availability_zone": &Schema{
|
||||||
Type: TypeString,
|
Type: TypeString,
|
||||||
@ -2018,9 +2009,8 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
GetKey: "availability_zone",
|
GetKey: "availability_zone",
|
||||||
GetValue: "foo",
|
GetValue: "foo",
|
||||||
},
|
},
|
||||||
|
|
||||||
// #14: Basic nil value
|
|
||||||
{
|
{
|
||||||
|
TestName: "Basic nil value",
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"availability_zone": &Schema{
|
"availability_zone": &Schema{
|
||||||
Type: TypeString,
|
Type: TypeString,
|
||||||
@ -2040,9 +2030,8 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
GetKey: "availability_zone",
|
GetKey: "availability_zone",
|
||||||
GetValue: "",
|
GetValue: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
// #15: Basic nil pointer
|
|
||||||
{
|
{
|
||||||
|
TestName: "Basic nil pointer",
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"availability_zone": &Schema{
|
"availability_zone": &Schema{
|
||||||
Type: TypeString,
|
Type: TypeString,
|
||||||
@ -2062,9 +2051,8 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
GetKey: "availability_zone",
|
GetKey: "availability_zone",
|
||||||
GetValue: "",
|
GetValue: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
// #16: Set in a list
|
|
||||||
{
|
{
|
||||||
|
TestName: "Set in a list",
|
||||||
Schema: map[string]*Schema{
|
Schema: map[string]*Schema{
|
||||||
"ports": &Schema{
|
"ports": &Schema{
|
||||||
Type: TypeList,
|
Type: TypeList,
|
||||||
@ -2131,29 +2119,31 @@ func TestResourceDataSet(t *testing.T) {
|
|||||||
os.Setenv(PanicOnErr, "")
|
os.Setenv(PanicOnErr, "")
|
||||||
defer os.Setenv(PanicOnErr, oldEnv)
|
defer os.Setenv(PanicOnErr, oldEnv)
|
||||||
|
|
||||||
for i, tc := range cases {
|
for _, tc := range cases {
|
||||||
d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff)
|
t.Run(tc.TestName, func(t *testing.T) {
|
||||||
if err != nil {
|
d, err := schemaMap(tc.Schema).Data(tc.State, tc.Diff)
|
||||||
t.Fatalf("err: %s", err)
|
if err != nil {
|
||||||
}
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
err = d.Set(tc.Key, tc.Value)
|
err = d.Set(tc.Key, tc.Value)
|
||||||
if err != nil != tc.Err {
|
if err != nil != tc.Err {
|
||||||
t.Fatalf("%d err: %s", i, err)
|
t.Fatalf("unexpected err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
v := d.Get(tc.GetKey)
|
v := d.Get(tc.GetKey)
|
||||||
if s, ok := v.(*Set); ok {
|
if s, ok := v.(*Set); ok {
|
||||||
v = s.List()
|
v = s.List()
|
||||||
}
|
}
|
||||||
|
|
||||||
if tc.GetPreProcess != nil {
|
if tc.GetPreProcess != nil {
|
||||||
v = tc.GetPreProcess(v)
|
v = tc.GetPreProcess(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(v, tc.GetValue) {
|
if !reflect.DeepEqual(v, tc.GetValue) {
|
||||||
t.Fatalf("Get Bad: %d\n\n%#v", i, v)
|
t.Fatalf("Got unexpected value\nactual: %#v\nexpected:%#v", v, tc.GetValue)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ func testDiffCases(t *testing.T, oldPrefix string, oldOffset int, computed bool)
|
|||||||
NewComputed: true,
|
NewComputed: true,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result["foo.2800005064"] = &tofu.ResourceAttrDiff{
|
result["foo.1494962232"] = &tofu.ResourceAttrDiff{
|
||||||
Old: "",
|
Old: "",
|
||||||
New: "qux",
|
New: "qux",
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,10 @@ func upgradeAttributesV2ToV3(instanceState *InstanceState) error {
|
|||||||
// First, detect "obvious" maps - which have non-numeric keys (mostly).
|
// First, detect "obvious" maps - which have non-numeric keys (mostly).
|
||||||
hasNonNumericKeys := false
|
hasNonNumericKeys := false
|
||||||
for _, key := range actualKeysMatching {
|
for _, key := range actualKeysMatching {
|
||||||
if _, err := strconv.Atoi(key); err != nil {
|
// Ensure that we attempt to parse the key using 64 bits, this is because the state
|
||||||
|
// could've been generated on a 64-bit system, and we need to be able to
|
||||||
|
// convert this on both a 32-bit and 64-bit arch.
|
||||||
|
if _, err := strconv.ParseInt(key, 10, 64); err != nil {
|
||||||
hasNonNumericKeys = true
|
hasNonNumericKeys = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user