Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add crds.yaml-based defaulting functions to pkg/apis/templates/... #129

Merged

Conversation

julianKatz
Copy link
Contributor

Each ConstrainTemplate version (v1alpha1, v1beta1, v1) has a default
value for the LegacySchema field. true for v1alpha1, v1beta1, and
false for v1. These defaults are defined in the CRD yaml.

For the ConstraintTemplate golang types to have the same functionality
to have the same defaulting functionality. We are required to write
custom defaulting functions for each defaulted field.

While we could do this, we could easily see how this practice could
become unsustainable. A forgotten defaulting function would yield
unexpected bugs.

To remedy this, this PR adds defaulting functions that default based on
the content of deploy/crds.yaml, i.e. the ConstraintTemplate CRD
generated by controller-gen.

This provides us with a single defaulting source of truth: the
constrainttemplate_types.go files, which contain annotations that
define a field's default values.

Fixes #128

Signed-off-by: juliankatz juliankatz@google.com

Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
functions

Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
Each ConstrainTemplate version (v1alpha1, v1beta1, v1) has a default
value for the LegacySchema field.  `true` for v1alpha1, v1beta1, and
`false` for v1.  These defaults are defined in the CRD yaml.

For the ConstraintTemplate golang types to have the same functionality
to have the same defaulting functionality.  We are required to write
custom defaulting functions for each defaulted field.

While we could do this, we could easily see how this practice could
become unsustainable.  A forgotten defaulting function would yield
unexpected bugs.

To remedy this, this PR adds defaulting functions that default based on
the content of deploy/crds.yaml, i.e. the ConstraintTemplate CRD
generated by controller-gen.

This provides us with a single defaulting source of truth: the
constrainttemplate_types.go files, which contain annotations that
define a field's default values.

Fixes open-policy-agent#128

Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
@codecov-commenter
Copy link

codecov-commenter commented Jul 29, 2021

Codecov Report

Merging #129 (889ec45) into master (d4a673c) will decrease coverage by 0.20%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #129      +/-   ##
==========================================
- Coverage   42.59%   42.39%   -0.21%     
==========================================
  Files          35       49      +14     
  Lines        2775     2951     +176     
==========================================
+ Hits         1182     1251      +69     
- Misses       1228     1321      +93     
- Partials      365      379      +14     
Flag Coverage Δ
unittests 42.39% <ø> (-0.21%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
...eworks/constraint/pkg/apis/templates/v1/helpers.go 0.00% <0.00%> (ø)
.../constraint/pkg/apis/templates/v1alpha1/helpers.go 0.00% <0.00%> (ø)
...s/constraint/pkg/apis/templates/v1beta1/helpers.go 0.00% <0.00%> (ø)
...traint/pkg/apis/templates/zz_generated.defaults.go 0.00% <0.00%> (ø)
...kg/apis/templates/v1beta1/zz_generated.defaults.go 50.00% <0.00%> (ø)
...eworks/constraint/pkg/apis/templates/crd_schema.go 50.00% <0.00%> (ø)
...t/frameworks/constraint/pkg/apis/templates/init.go 100.00% <0.00%> (ø)
...works/constraint/pkg/apis/templates/v1/defaults.go 55.55% <0.00%> (ø)
...int/pkg/apis/templates/v1/zz_generated.defaults.go 50.00% <0.00%> (ø)
...constraint/pkg/apis/templates/v1alpha1/defaults.go 55.55% <0.00%> (ø)
... and 13 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d4a673c...889ec45. Read the comment docs.

Copy link
Contributor

@maxsmythe maxsmythe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with a couple nits

}

unCRD := unstructured.Unstructured{}
unCRD.UnmarshalJSON(crdJSON)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't unmarshal directly to constraintTemplateCRD and save the middle step of converting to unstructured?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look like CustomResourceDefinition has an Unmarshal function.

apiextensions-apiserver/pkg/apis/apiextensions/v1/marshal.go does have unmarshalling logic, but it only supports doing so into a JSONSchemaPropsOrArray.

One idea:

I did the unmarshalling + FromUnstructured() because it made it easier to dive into the versions: and populate my ConstraintTemplateSchemas map. I could probably simplify this logic by diving straight to versions in the unstructured and unmarshalling those JSON blobs straight into apiextensionsv1.JSONSchemaProps. I'd then convert to apiextensions.JSONSchemaProps (apiextensions has no unmarshalling methods, only the versioned sub-packages) and create the Structural type for the map.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried this^ and it's more trouble than it's worth. B/c I use multiple properties of a version in my loop, it pays to convert to a CustomResourceDefinition{}.

constraint/pkg/apis/templates/crd_schema.go Outdated Show resolved Hide resolved
constraint/pkg/apis/templates/v1/defaults.go Outdated Show resolved Hide resolved
Copy link
Contributor

@maxsmythe maxsmythe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, digging a bit deeper, it looks like we have these defaulting functions (which is good), but they're not being applied anywhere.

This means issues like open-policy-agent/gatekeeper#1458 will still occur.

Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
Copy link
Contributor

@maxsmythe maxsmythe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good!

I think the last piece would be a "conversion" helper function that knows to apply defaults before converting. This could be leveraged by gator test

@julianKatz
Copy link
Contributor Author

Looking good!

I think the last piece would be a "conversion" helper function that knows to apply defaults before converting. This could be leveraged by gator test

Is there an existing place where we'll use this function? That would help me know I'm making the right thing.

Signed-off-by: juliankatz <juliankatz@google.com>
… crd-yaml-based-defaulting

Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
Copy link
Contributor

@maxsmythe maxsmythe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for figuring this out!

@maxsmythe
Copy link
Contributor

Though it looks like there are linting errors, and we need to re-bake the CRD yaml into the golang constant

Copy link
Contributor

@maxsmythe maxsmythe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, missed some things

constraint/pkg/apis/templates/v1/helpers.go Outdated Show resolved Hide resolved
Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
constraint/pkg/apis/templates/v1/helpers.go Outdated Show resolved Hide resolved
constraint/pkg/apis/templates/v1beta1/helpers.go Outdated Show resolved Hide resolved
constraint/pkg/apis/templates/v1alpha1/helpers.go Outdated Show resolved Hide resolved
Signed-off-by: juliankatz <juliankatz@google.com>
Copy link
Contributor

@maxsmythe maxsmythe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Signed-off-by: juliankatz <juliankatz@google.com>
@julianKatz
Copy link
Contributor Author

ping :) @shomron @ritazh @sozercan

constraint/pkg/apis/templates/crd_schema.go Outdated Show resolved Hide resolved
constraint/pkg/apis/templates/crd_schema.go Outdated Show resolved Hide resolved
@@ -0,0 +1,6 @@
package templates

func init() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is valid to have multiple init() functions in the same Go package. You can rename both initializeScheme and initializeCTSchemaMap to init and it will work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem wasn't the inability to have multiple init() calls, but rather that initializeCTSchemaMap() uses the Scheme that's created in initializeScheme(). As init functions are run according to the order of their containing file's name (crd_schema.go before scheme.go), this caused a null-pointer exception.

Rather than fix this through naming, I figured the best way to was to call them in an intentional order like I did in this init.go file. I'll add a comment to init.go explaining that choice.

Or, perhaps there's a pattern that would better suit this use-case? @willbeason

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason the contents of those two methods can't be in the same function? initializeScheme is rather short.

constraint/pkg/apis/templates/test_fakes.go Outdated Show resolved Hide resolved
constraint/pkg/apis/templates/v1/conversion.go Outdated Show resolved Hide resolved
constraint/pkg/apis/templates/v1/defaults_test.go Outdated Show resolved Hide resolved
Signed-off-by: juliankatz <juliankatz@google.com>
@julianKatz julianKatz requested a review from ritazh August 10, 2021 21:29
Signed-off-by: juliankatz <juliankatz@google.com>
Signed-off-by: juliankatz <juliankatz@google.com>
… crd-yaml-based-defaulting

Signed-off-by: juliankatz <juliankatz@google.com>
@julianKatz julianKatz merged commit 2924b2c into open-policy-agent:master Aug 16, 2021
@julianKatz julianKatz deleted the crd-yaml-based-defaulting branch August 16, 2021 18:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Build a defaulting system that derives code from the ConstraintTemplate CRD yaml
5 participants