-
Notifications
You must be signed in to change notification settings - Fork 777
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
feat: external data mutation #1506
Conversation
Signed-off-by: Sertac Ozercan <sozercan@gmail.com>
Signed-off-by: Sertac Ozercan <sozercan@gmail.com>
Signed-off-by: Sertac Ozercan <sozercan@gmail.com>
Codecov Report
@@ Coverage Diff @@
## master #1506 +/- ##
==========================================
- Coverage 52.25% 50.98% -1.28%
==========================================
Files 82 84 +2
Lines 7377 7675 +298
==========================================
+ Hits 3855 3913 +58
- Misses 3163 3397 +234
- Partials 359 365 +6
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
Signed-off-by: Sertac Ozercan <sozercan@gmail.com>
Signed-off-by: Sertac Ozercan <sozercan@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had a bunch of pending comments b/c this review was deferred pending a review of the CF PR.
Releasing them to add some more context to the external data discussion.
@@ -48,6 +48,8 @@ type Parameters struct { | |||
// Assign.value holds the value to be assigned | |||
// +kubebuilder:validation:XPreserveUnknownFields | |||
Assign runtime.RawExtension `json:"assign,omitempty"` | |||
|
|||
ExternalData ExternalData `json:"externalData,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add docstrings here so it gets documented in the generated CRD (and thus by kubectl explain
), also should ExternalData
be a member of Assign
? Assign
No longer needs to be a RawExtension
, now that we have the Schemaless
marker for controller-gen.
@@ -36,6 +36,8 @@ type MetadataParameters struct { | |||
// Assign.value holds the value to be assigned | |||
// +kubebuilder:validation:XPreserveUnknownFields | |||
Assign runtime.RawExtension `json:"assign,omitempty"` | |||
|
|||
ExternalData ExternalData `json:"externalData,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comments about ExternalData
as in Assign
go.mod
Outdated
sigs.k8s.io/controller-runtime v0.8.3 | ||
sigs.k8s.io/yaml v1.2.0 | ||
) | ||
|
||
replace github.com/open-policy-agent/frameworks/constraint => github.com/sozercan/frameworks/constraint v0.0.0-20210818181827-bf04f25ec1e9 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be removed before we merge
} | ||
|
||
// Watch for changes to Provider | ||
return c.Watch( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eventually we'll want to report status on a provider
Kind: "Assign", | ||
NewMutationObj: func() client.Object { return &mutationsv1alpha1.Assign{} }, | ||
MutatorFor: func(obj client.Object) (types.Mutator, error) { | ||
// The type is provided by the `NewObj` function above. If we | ||
// are fed the wrong type, this is a non-recoverable error and we | ||
// may as well crash for visibility | ||
assign := obj.(*mutationsv1alpha1.Assign) // nolint:forcetypeassert | ||
return mutators.MutatorForAssign(assign) | ||
return mutators.MutatorForAssign(assign, a.ProviderCache) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Injecting the provider cache into the mutators seems brittle... could we inject them into the mutation system and system can provide the context at mutation time? Unless there would be a reason for different mutators to have different provider caches?
@@ -114,8 +120,24 @@ func (m *AssignMetadataMutator) String() string { | |||
return fmt.Sprintf("%s/%s/%s:%d", m.id.Kind, m.id.Namespace, m.id.Name, m.assignMetadata.GetGeneration()) | |||
} | |||
|
|||
func (m *AssignMetadataMutator) GetExternalDataProvider() string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because this is an implementation detail of how mutators work, maybe we can hide this?
Maybe we can leverage the Setter interface I propose in the ModifySet PR?
} | ||
|
||
func (m *AssignMetadataMutator) GetExternalDataCache(name string) (*externaldatav1alpha1.Provider, error) { | ||
data, err := m.providerCache.Get(name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if the data provider hasn't yet been cached due to eventual consistency?
@@ -173,10 +202,14 @@ func isValidMetadataPath(path parser.Path) bool { | |||
return false | |||
} | |||
|
|||
func isValidExternalDataSource(source types.DataSource) bool { | |||
return source == types.Username |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also enforce this at the JSONSchema validation level?
@@ -14,18 +18,83 @@ import ( | |||
|
|||
var log = logf.Log.WithName("mutation").WithValues(logging.Process, "mutation") | |||
|
|||
func Mutate(mutator types.Mutator, tester *path.Tester, valueTest func(interface{}, bool) bool, obj *unstructured.Unstructured) (bool, error) { | |||
func Mutate(mutator types.Mutator, tester *path.Tester, valueTest func(interface{}, bool) bool, obj *unstructured.Unstructured, providerResponseCache map[types.ProviderCacheKey]string) (bool, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can also avoid the need to pass providerResponseCache
explicitly with the setter interface
if providerName != "" { | ||
providerStore, err := mutator.GetExternalDataCache(providerName) | ||
if err != nil { | ||
return nil, false, fmt.Errorf("failed to get external data provider cache: %v", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will cause requests to fail due to eventual consistency whenever a new provider is added, which might nullify all mutators. Is this the behavior that we want?
closing in favor of #1891 |
Signed-off-by: Sertac Ozercan sozercan@gmail.com
What this PR does / why we need it:
Design doc: https://docs.google.com/document/d/1hPi86jdsCKg8puYT5_s_73mPGExUJeZfyKmvG-XWtPc/edit
Which issue(s) this PR fixes (optional, using
fixes #<issue number>(, fixes #<issue_number>, ...)
format, will close the issue(s) when the PR gets merged):Fixes #15 #1293
Special notes for your reviewer:
corresponding frameworks pr: open-policy-agent/frameworks#134
Sample providers:
validation:
https://github.com/sozercan/cosign-provider
https://github.com/sozercan/trivy-provider
mutation:
https://github.com/sozercan/tagToDigest-provider (
valueAtLocation
)https://github.com/sozercan/aad-provider (
username
)