Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Annotate CSVs with the properties used during dependency resolution.
This ensures that property information is not lost after an operator is installed, and that the properties of an operator are the same before and after installation. Preserving properties also allows installed operators to satisfy dependencies on properties that cannot be inferred from a ClusterServiceVersion spec, and is a step toward unifying installed and available operators from the perspective of resolution.
- Loading branch information
Showing
14 changed files
with
347 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package projection | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
|
||
"github.com/operator-framework/operator-registry/pkg/api" | ||
) | ||
|
||
const ( | ||
PropertiesAnnotationKey = "operatorframework.io/properties" | ||
) | ||
|
||
type property struct { | ||
Type string `json:"type"` | ||
Value json.RawMessage `json:"value"` | ||
} | ||
|
||
type propertiesAnnotation struct { | ||
Properties []property `json:"properties,omitempty"` | ||
} | ||
|
||
func PropertiesAnnotationFromPropertyList(props []*api.Property) (string, error) { | ||
var anno propertiesAnnotation | ||
for _, prop := range props { | ||
anno.Properties = append(anno.Properties, property{ | ||
Type: prop.Type, | ||
Value: json.RawMessage(prop.Value), | ||
}) | ||
} | ||
v, err := json.Marshal(&anno) | ||
if err != nil { | ||
return "", fmt.Errorf("failed to marshal properties annotation: %w", err) | ||
} | ||
return string(v), nil | ||
} | ||
|
||
func PropertyListFromPropertiesAnnotation(raw string) ([]*api.Property, error) { | ||
var anno propertiesAnnotation | ||
if err := json.Unmarshal([]byte(raw), &anno); err != nil { | ||
return nil, fmt.Errorf("failed to unmarshal properties annotation: %w", err) | ||
} | ||
var result []*api.Property | ||
for _, each := range anno.Properties { | ||
result = append(result, &api.Property{ | ||
Type: each.Type, | ||
Value: string(each.Value), | ||
}) | ||
} | ||
return result, nil | ||
} |
141 changes: 141 additions & 0 deletions
141
pkg/controller/registry/resolver/projection/properties_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
package projection_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/projection" | ||
"github.com/operator-framework/operator-registry/pkg/api" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestPropertiesAnnotationFromPropertyList(t *testing.T) { | ||
for _, tc := range []struct { | ||
name string | ||
properties []*api.Property | ||
expected string | ||
error bool | ||
}{ | ||
{ | ||
name: "nil property slice", | ||
properties: nil, | ||
expected: "{}", | ||
}, | ||
{ | ||
name: "empty property slice", | ||
properties: []*api.Property{}, | ||
expected: "{}", | ||
}, | ||
{ | ||
name: "invalid property value", | ||
properties: []*api.Property{{ | ||
Type: "bad", | ||
Value: `]`, | ||
}}, | ||
error: true, | ||
}, | ||
{ | ||
name: "nonempty property slice", | ||
properties: []*api.Property{ | ||
{ | ||
Type: "string", | ||
Value: `"hello"`, | ||
}, | ||
{ | ||
Type: "number", | ||
Value: `5`, | ||
}, | ||
{ | ||
Type: "array", | ||
Value: `[1,"two",3,"four"]`, | ||
}, { | ||
Type: "object", | ||
Value: `{"hello":{"worl":"d"}}`, | ||
}, | ||
}, | ||
expected: `{"properties":[{"type":"string","value":"hello"},{"type":"number","value":5},{"type":"array","value":[1,"two",3,"four"]},{"type":"object","value":{"hello":{"worl":"d"}}}]}`, | ||
}, | ||
} { | ||
t.Run(tc.name, func(t *testing.T) { | ||
actual, err := projection.PropertiesAnnotationFromPropertyList(tc.properties) | ||
assert := assert.New(t) | ||
assert.Equal(tc.expected, actual) | ||
if tc.error { | ||
assert.Error(err) | ||
} else { | ||
assert.NoError(err) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestPropertyListFromPropertiesAnnotation(t *testing.T) { | ||
for _, tc := range []struct { | ||
name string | ||
annotation string | ||
expected []*api.Property | ||
error bool | ||
}{ | ||
{ | ||
name: "empty", | ||
annotation: "", | ||
error: true, | ||
}, | ||
{ | ||
name: "invalid json", | ||
annotation: "]", | ||
error: true, | ||
}, | ||
{ | ||
name: "no properties key", | ||
annotation: "{}", | ||
expected: nil, | ||
}, | ||
{ | ||
name: "properties value not an array or null", | ||
annotation: `{"properties":5}`, | ||
error: true, | ||
}, | ||
{ | ||
name: "property element not an object", | ||
annotation: `{"properties":[42]}`, | ||
error: true, | ||
}, | ||
{ | ||
name: "no properties", | ||
annotation: `{"properties":[]}`, | ||
expected: nil, | ||
}, | ||
{ | ||
name: "several properties", | ||
annotation: `{"properties":[{"type":"string","value":"hello"},{"type":"number","value":5},{"type":"array","value":[1,"two",3,"four"]},{"type":"object","value":{"hello":{"worl":"d"}}}]}`, | ||
expected: []*api.Property{ | ||
{ | ||
Type: "string", | ||
Value: `"hello"`, | ||
}, | ||
{ | ||
Type: "number", | ||
Value: `5`, | ||
}, | ||
{ | ||
Type: "array", | ||
Value: `[1,"two",3,"four"]`, | ||
}, { | ||
Type: "object", | ||
Value: `{"hello":{"worl":"d"}}`, | ||
}, | ||
}, | ||
}, | ||
} { | ||
t.Run(tc.name, func(t *testing.T) { | ||
actual, err := projection.PropertyListFromPropertiesAnnotation(tc.annotation) | ||
assert := assert.New(t) | ||
assert.Equal(tc.expected, actual) | ||
if tc.error { | ||
assert.Error(err) | ||
} else { | ||
assert.NoError(err) | ||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.