Skip to content

Commit

Permalink
Add ModifySet mutator (#1508)
Browse files Browse the repository at this point in the history
* Add ModifySet mutator.

Fixes #1358

This PR is still a WIP... tests need to be written.

Signed-off-by: Max Smythe <smythe@google.com>

* address PR comments

Signed-off-by: Max Smythe <smythe@google.com>

Co-authored-by: Rita Zhang <rita.z.zhang@gmail.com>
  • Loading branch information
maxsmythe and ritazh authored Sep 8, 2021
1 parent 63b51d3 commit 9918cbe
Show file tree
Hide file tree
Showing 48 changed files with 1,642 additions and 302 deletions.
8 changes: 0 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,6 @@ deploy-mutation: patch-image
k8s.gcr.io/kustomize/kustomize:v${KUSTOMIZE_VERSION} build \
--load_restrictor LoadRestrictionsNone \
/config/overlays/dev_mutation | kubectl apply -f -
docker run -v $(shell pwd)/config:/config -v $(shell pwd)/vendor:/vendor \
k8s.gcr.io/kustomize/kustomize:v${KUSTOMIZE_VERSION} build \
--load_restrictor LoadRestrictionsNone \
/config/overlays/mutation | kubectl apply -f -

# Deploy controller in the configured Kubernetes cluster in ~/.kube/config
deploy: patch-image manifests
Expand All @@ -208,10 +204,6 @@ manifests: __controller-gen
paths="./apis/..." \
paths="./pkg/..." \
output:crd:artifacts:config=config/crd/bases
# As mutation CRDs are not ready to be included in our final gatekeeper.yaml, we leave them out of config/crd/kustomization.yaml.
# This makes these files unavailable to the helmify step below. The solve for this was to copy the mutation CRDs into
# config/overlays/mutation_webhook/. To maintain the generation pipeline, we do that copy step here.
cp config/crd/bases/*mutat* config/overlays/mutation_webhook/
rm -rf manifest_staging
mkdir -p manifest_staging/deploy
mkdir -p manifest_staging/charts/gatekeeper
Expand Down
20 changes: 16 additions & 4 deletions apis/mutations/v1alpha1/assign_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,22 @@ import (
type AssignSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
ApplyTo []match.ApplyTo `json:"applyTo,omitempty"`
Match match.Match `json:"match,omitempty"`
Location string `json:"location,omitempty"`
Parameters Parameters `json:"parameters,omitempty"`

// ApplyTo lists the specific groups, versions and kinds a mutation will be applied to.
// This is necessary because every mutation implies part of an object schema and object
// schemas are associated with specific GVKs.
ApplyTo []match.ApplyTo `json:"applyTo,omitempty"`

// Match allows the user to limit which resources get mutated.
// Individual match criteria are AND-ed together. An undefined
// match criteria matches everything.
Match match.Match `json:"match,omitempty"`

// Location describes the path to be mutated, for example: `spec.containers[name: main]`.
Location string `json:"location,omitempty"`

// Parameters define the behavior of the mutator.
Parameters Parameters `json:"parameters,omitempty"`
}

type Parameters struct {
Expand Down
147 changes: 147 additions & 0 deletions apis/mutations/v1alpha1/modifyset_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha1

import (
"github.com/open-policy-agent/gatekeeper/apis/status/v1beta1"
"github.com/open-policy-agent/gatekeeper/pkg/mutation/match"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)

// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.

// ModifySetSpec defines the desired state of ModifySet.
type ModifySetSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file

// ApplyTo lists the specific groups, versions and kinds a mutation will be applied to.
// This is necessary because every mutation implies part of an object schema and object
// schemas are associated with specific GVKs.
ApplyTo []match.ApplyTo `json:"applyTo,omitempty"`

// Match allows the user to limit which resources get mutated.
// Individual match criteria are AND-ed together. An undefined
// match criteria matches everything.
Match match.Match `json:"match,omitempty"`

// Location describes the path to be mutated, for example: `spec.containers[name: main].args`.
Location string `json:"location,omitempty"`

// Parameters define the behavior of the mutator.
Parameters ModifySetParameters `json:"parameters,omitempty"`
}

type ModifySetParameters struct {
// PathTests are a series of existence tests that can be checked
// before a mutation is applied
PathTests []PathTest `json:"pathTests,omitempty"`

// Operation describes whether values should be merged in ("merge"), or pruned ("prune"). Default value is "merge"
// +kubebuilder:validation:Enum=merge;prune
// +kubebuilder:default=merge
Operation Operation `json:"operation,omitempty"`

// Values describes the values provided to the operation as `values.fromList`.
// +kubebuilder:validation:Schemaless
// +kubebuilder:validation:Type=object
// +kubebuilder:validation:XPreserveUnknownFields
Values Values `json:"values,omitempty"`
}

type Operation string

const (
// MergeOp means that the provided values should be merged with the existing values.
MergeOp Operation = "merge"

// PruneOp means that the provided values should be removed from the existing values.
PruneOp Operation = "prune"
)

// Values describes the values provided to the operation.
// +kubebuilder:object:generate=false
type Values struct {
FromList []interface{} `json:"fromList,omitempty"`
}

func (in *Values) DeepCopy() *Values {
if in == nil {
return nil
}

var fromList []interface{}
if in.FromList != nil {
fromList = make([]interface{}, len(in.FromList))
for i := range fromList {
fromList[i] = runtime.DeepCopyJSONValue(in.FromList[i])
}
}

return &Values{
FromList: fromList,
}
}

func (in *Values) DeepCopyInto(out *Values) {
*in = *out

if in.FromList != nil {
fromList := make([]interface{}, len(in.FromList))
for i := range fromList {
fromList[i] = runtime.DeepCopyJSONValue(in.FromList[i])
}
out.FromList = fromList
}
}

// ModifySetStatus defines the observed state of ModifySet.
type ModifySetStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file

ByPod []v1beta1.MutatorPodStatusStatus `json:"byPod,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:resource:path="modifyset"
// +kubebuilder:resource:scope="Cluster"
// +kubebuilder:subresource:status

// ModifySet allows the user to modify non-keyed lists, such as
// the list of arguments to a container.
type ModifySet struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec ModifySetSpec `json:"spec,omitempty"`
Status ModifySetStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// ModifySetList contains a list of ModifySet.
type ModifySetList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []ModifySet `json:"items"`
}

func init() {
SchemeBuilder.Register(&ModifySet{}, &ModifySetList{})
}
126 changes: 126 additions & 0 deletions apis/mutations/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion cmd/build/helmify/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ commonLabels:
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
bases:
- "../../../config/overlays/mutation_webhook" # calls ../../default
- "../../../config/overlays/mutation" # calls ../../default
patchesStrategicMerge:
- kustomize-for-helm.yaml
- delete-ports.yaml
Expand Down Expand Up @@ -52,6 +52,12 @@ patchesJson6902:
kind: CustomResourceDefinition
name: assign.mutations.gatekeeper.sh
path: labels_patch.yaml
- target:
group: apiextensions.k8s.io
version: v1
kind: CustomResourceDefinition
name: modifyset.mutations.gatekeeper.sh
path: labels_patch.yaml
# these are defined in the chart values rather than hard-coded
- target:
kind: Deployment
Expand Down
6 changes: 4 additions & 2 deletions config/crd/bases/mutations.gatekeeper.sh_assign.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ spec:
description: AssignSpec defines the desired state of Assign.
properties:
applyTo:
description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster Important: Run "make" to regenerate code after modifying this file'
description: ApplyTo lists the specific groups, versions and kinds a mutation will be applied to. This is necessary because every mutation implies part of an object schema and object schemas are associated with specific GVKs.
items:
description: ApplyTo determines what GVKs items the mutation should apply to. Globs are not allowed.
properties:
Expand All @@ -52,9 +52,10 @@ spec:
type: object
type: array
location:
description: 'Location describes the path to be mutated, for example: `spec.containers[name: main]`.'
type: string
match:
description: Match selects objects to apply mutations to.
description: Match allows the user to limit which resources get mutated. Individual match criteria are AND-ed together. An undefined match criteria matches everything.
properties:
excludedNamespaces:
items:
Expand Down Expand Up @@ -144,6 +145,7 @@ spec:
type: string
type: object
parameters:
description: Parameters define the behavior of the mutator.
properties:
assign:
description: Assign.value holds the value to be assigned
Expand Down
Loading

0 comments on commit 9918cbe

Please sign in to comment.