Skip to content
This repository has been archived by the owner on Feb 8, 2021. It is now read-only.

Commit

Permalink
hyperstart: Support converting embedded field
Browse files Browse the repository at this point in the history
The gRPC generated Go structures will never have embedded
fields, while the OCI ones have some.

This forces us to support copying between structs with different
number of fields when one field is embedded on one side while
it's not on the other.

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
  • Loading branch information
Samuel Ortiz committed Nov 10, 2017
1 parent e433e14 commit 359f5d3
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 40 deletions.
16 changes: 14 additions & 2 deletions hyperstart/api/grpc/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,19 @@
"allow": false,
"access": "rwm"
}
]
],
"blockIO": {
"weight": 32,
"leafWeight": 33,
"weightDevice": [
{
"major": 10,
"minor": 11,
"weight": 64,
"leafWeight": 128
}
]
}
},
"namespaces": [
{
Expand Down Expand Up @@ -571,4 +583,4 @@
]
}
}
}
}
83 changes: 45 additions & 38 deletions hyperstart/api/grpc/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,28 @@ func structFieldName(v reflect.Value, index int) (string, error) {
return v.Type().Field(index).Name, nil
}

func isEmbeddedStruct(v reflect.Value, index int) bool {
if v.Kind() != reflect.Struct || index > v.Type().NumField()-1 {
return false
}

return v.Type().Field(index).Anonymous
}

func findStructField(v reflect.Value, name string) (reflect.Value, error) {
if v.Kind() != reflect.Struct {
return reflect.Value{}, fmt.Errorf("Can only infer field name from structs")
}

for i := 0; i < v.NumField(); i++ {
if v.Type().Field(i).Name == name {
return v.Field(i), nil
}
}

return reflect.Value{}, fmt.Errorf("Could not find field %s", name)
}

func copyStructValue(to, from reflect.Value) error {
if to.Kind() != reflect.Struct && from.Kind() != reflect.Struct {
return fmt.Errorf("Can only copy structs into structs")
Expand All @@ -132,54 +154,39 @@ func copyStructValue(to, from reflect.Value) error {
return nil
}

if to.NumField() != from.NumField() {
return fmt.Errorf("Structures must have the same number of fields")
}

for i := 0; i < to.NumField(); i++ {
var fromFieldIndex int
// If one of the field is embedded, we copy between the embedded field
// and the structure itself. The fields in the embedded field should
// be found in the parent structure.
if isEmbeddedStruct(to, i) {
if err := copyStructValue(to.Field(i), from); err != nil {
return err
}
continue
}

// We want to verify that both fields have the same name
toFieldName, err := structFieldName(to, i)
if err != nil {
return err
if isEmbeddedStruct(from, i) {
if err := copyStructValue(to, from.Field(i)); err != nil {
return err
}
continue
}

fromFieldName, err := structFieldName(from, i)
// Find the destination structure field name.
fieldName, err := structFieldName(to, i)
if err != nil {
return err
}

// The two fields at index i do not have the same name.
// Maybe they're not ordered the same way, let's look through
// the from struct fields and check if we find one that matches
// the to struct field we're trying to copy into.
if fromFieldName != toFieldName {
fieldFound := false
j := 0

for j = 0; j < from.NumField(); j++ {
fieldName, err := structFieldName(from, j)
if err != nil {
continue
}

if fieldName == toFieldName {
fieldFound = true
break
}
}

if !fieldFound {
return fmt.Errorf("Wrong field names %s vs %s", toFieldName, fromFieldName)
} else {
fromFieldIndex = j
}
} else {
fromFieldIndex = i
// Try to find the same field name in the origin structure.
// This can fail as we support copying between structures
// that optionally have embedded fields.
v, err := findStructField(from, fieldName)
if err != nil {
continue
}

if err := copyValue(to.Field(i), from.Field(fromFieldIndex)); err != nil {
if err := copyValue(to.Field(i), v); err != nil {
return err
}
}
Expand Down
14 changes: 14 additions & 0 deletions hyperstart/api/grpc/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ func assertIsEqual(t *testing.T, ociSpec *specs.Spec, grpcSpec *Spec) {
assert.Equal(len(grpcSpec.Linux.Resources.Devices), 1)
assert.Equal(grpcSpec.Linux.Resources.Devices[0].Access, "rwm")

// Linux checks: Block IO, for checking embedded structures copy
assert.NotNil(ociSpec.Linux.Resources.BlockIO.LeafWeight)
assert.NotNil(ociSpec.Linux.Resources.BlockIO.Weight)
assert.EqualValues(grpcSpec.Linux.Resources.BlockIO.Weight, *ociSpec.Linux.Resources.BlockIO.Weight)
assert.EqualValues(grpcSpec.Linux.Resources.BlockIO.LeafWeight, *ociSpec.Linux.Resources.BlockIO.LeafWeight)
assert.NotEqual(len(grpcSpec.Linux.Resources.BlockIO.WeightDevice), 0)
assert.Equal(len(grpcSpec.Linux.Resources.BlockIO.WeightDevice), len(grpcSpec.Linux.Resources.BlockIO.WeightDevice))
assert.EqualValues(grpcSpec.Linux.Resources.BlockIO.WeightDevice[0].Major, ociSpec.Linux.Resources.BlockIO.WeightDevice[0].Major)
assert.EqualValues(grpcSpec.Linux.Resources.BlockIO.WeightDevice[0].Minor, ociSpec.Linux.Resources.BlockIO.WeightDevice[0].Minor)
assert.NotNil(ociSpec.Linux.Resources.BlockIO.WeightDevice[0].LeafWeight)
assert.NotNil(ociSpec.Linux.Resources.BlockIO.WeightDevice[0].Weight)
assert.EqualValues(grpcSpec.Linux.Resources.BlockIO.WeightDevice[0].Weight, *ociSpec.Linux.Resources.BlockIO.WeightDevice[0].Weight)
assert.EqualValues(grpcSpec.Linux.Resources.BlockIO.WeightDevice[0].LeafWeight, *ociSpec.Linux.Resources.BlockIO.WeightDevice[0].LeafWeight)

// Linux checks: Namespaces
assert.Equal(len(grpcSpec.Linux.Namespaces), len(ociSpec.Linux.Namespaces))
assert.Equal(len(grpcSpec.Linux.Namespaces), 5)
Expand Down

0 comments on commit 359f5d3

Please sign in to comment.