Skip to content

Commit

Permalink
test
Browse files Browse the repository at this point in the history
  • Loading branch information
oliverbaehler committed Aug 26, 2024
2 parents 1fae6ec + 3f5bc4a commit 67d523d
Show file tree
Hide file tree
Showing 16 changed files with 436 additions and 89 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/check-commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ jobs:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
fetch-depth: 0
- uses: wagoid/commitlint-github-action@baa1b236f990293a1b2d94c19e41c2313a85e749 #v6.0.2
- uses: wagoid/commitlint-github-action@a2bc521d745b1ba127ee2f8b02d6afaa4eed035c #v6.1.1
with:
firstParent: true
2 changes: 1 addition & 1 deletion .github/workflows/releaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
timeout-minutes: 5
continue-on-error: true
- uses: creekorful/goreportcard-action@1f35ced8cdac2cba28c9a2f2288a16aacfd507f9 # v1.0
- uses: anchore/sbom-action/download-syft@ab9d16d4b419c9d1a02df5213fa0ebe965ca5a57
- uses: anchore/sbom-action/download-syft@61119d458adab75f756bc0b9e4bde25725f86a7a
- name: Install Cosign
uses: sigstore/cosign-installer@4959ce089c160fddf62f7b42464195ba1a56d382 # v3.6.0
- name: Run GoReleaser
Expand Down
7 changes: 3 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -194,14 +194,13 @@ ko-publish-all: ko-publish-capsule
####################

CONTROLLER_GEN := $(shell pwd)/bin/controller-gen
CONTROLLER_GEN_VERSION := v0.15.0
CONTROLLER_GEN_VERSION := v0.16.1
controller-gen: ## Download controller-gen locally if necessary.
$(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_GEN_VERSION))

GINKGO := $(shell pwd)/bin/ginkgo
GINGKO_VERSION := v2.17.2
ginkgo: ## Download ginkgo locally if necessary.
$(call go-install-tool,$(GINKGO),github.com/onsi/ginkgo/v2/ginkgo@$(GINGKO_VERSION))
$(call go-install-tool,$(GINKGO),github.com/onsi/ginkgo/v2/ginkgo)

CT := $(shell pwd)/bin/ct
CT_VERSION := v3.10.1
Expand Down Expand Up @@ -277,7 +276,7 @@ e2e/%: ginkgo

e2e-build/%:
kind create cluster --wait=60s --name capsule --image=kindest/node:$*
make e2e-install
$(MAKE) e2e-install

.PHONY: e2e-install
e2e-install: e2e-load-image
Expand Down
2 changes: 1 addition & 1 deletion api/v1beta2/tenant_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type TenantSpec struct {
// Specifies the allowed RuntimeClasses assigned to the Tenant.
// Capsule assures that all Pods resources created in the Tenant can use only one of the allowed RuntimeClasses.
// Optional.
RuntimeClasses *api.SelectorAllowedListSpec `json:"runtimeClasses,omitempty"`
RuntimeClasses *api.DefaultAllowedListSpec `json:"runtimeClasses,omitempty"`
// Specifies the allowed priorityClasses assigned to the Tenant.
// Capsule assures that all Pods resources created in the Tenant can use only one of the allowed PriorityClasses.
// A default value can be specified, and all the Pod resources created will inherit the declared class.
Expand Down
2 changes: 1 addition & 1 deletion api/v1beta2/zz_generated.deepcopy.go

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

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.15.0
controller-gen.kubebuilder.io/version: v0.16.1
name: capsuleconfigurations.capsule.clastix.io
spec:
group: capsule.clastix.io
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.15.0
controller-gen.kubebuilder.io/version: v0.16.1
name: globaltenantresources.capsule.clastix.io
spec:
group: capsule.clastix.io
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.15.0
controller-gen.kubebuilder.io/version: v0.16.1
name: tenantresources.capsule.clastix.io
spec:
group: capsule.clastix.io
Expand Down
312 changes: 287 additions & 25 deletions charts/capsule/crds/capsule.clastix.io_tenants.yaml

Large diffs are not rendered by default.

64 changes: 56 additions & 8 deletions e2e/pod_runtime_class_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,17 @@ var _ = Describe("enforcing a Runtime Class", func() {
Kind: "User",
},
},
RuntimeClasses: &api.SelectorAllowedListSpec{
AllowedListSpec: api.AllowedListSpec{
Exact: []string{"legacy"},
Regex: "^hardened-.*$",
},
LabelSelector: metav1.LabelSelector{
MatchLabels: map[string]string{
"env": "customers",
RuntimeClasses: &api.DefaultAllowedListSpec{
Default: "default-runtime",
SelectorAllowedListSpec: api.SelectorAllowedListSpec{
AllowedListSpec: api.AllowedListSpec{
Exact: []string{"legacy"},
Regex: "^hardened-.*$",
},
LabelSelector: metav1.LabelSelector{
MatchLabels: map[string]string{
"env": "customers",
},
},
},
},
Expand Down Expand Up @@ -221,4 +224,49 @@ var _ = Describe("enforcing a Runtime Class", func() {
}
})

It("should auto assign the default", func() {
ns := NewNamespace("rc-default")

NamespaceCreation(ns, tnt.Spec.Owners[0], defaultTimeoutInterval).Should(Succeed())

runtime := &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{
Name: "default-runtime",
},
Handler: "custom-handler",
}
Expect(k8sClient.Create(context.TODO(), runtime)).Should(Succeed())
defer func() {
Expect(k8sClient.Delete(context.TODO(), runtime)).Should(Succeed())
}()

pod := corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "rc-default",
Namespace: ns.Name,
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "container",
Image: "quay.io/google-containers/pause-amd64:3.0",
},
},
},
}

cs := ownerClient(tnt.Spec.Owners[0])

var createdPod *corev1.Pod

EventuallyCreation(func() (err error) {
createdPod, err = cs.CoreV1().Pods(ns.GetName()).Create(context.Background(), &pod, metav1.CreateOptions{})

return err
}).Should(Succeed())

Expect(createdPod.Spec.RuntimeClassName).NotTo(BeNil())
_, err := Equal(createdPod.Spec.RuntimeClassName).Match(tnt.Spec.RuntimeClasses.Default)
Expect(err).NotTo(HaveOccurred())
})
})
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/onsi/ginkgo/v2 v2.20.0
github.com/onsi/gomega v1.34.1
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.20.1
github.com/prometheus/client_golang v1.20.2
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.9.0
github.com/valyala/fasttemplate v1.2.2
Expand Down Expand Up @@ -61,7 +61,7 @@ require (
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/oauth2 v0.22.0 // indirect
golang.org/x/sys v0.24.0 // indirect
Expand All @@ -75,7 +75,7 @@ require (
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20240816214639-573285566f34 // indirect
k8s.io/kube-openapi v0.0.0-20240822171749-76de80e0abd9 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
Expand Down
9 changes: 7 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
Expand Down Expand Up @@ -125,10 +126,10 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus/client_golang v1.20.0 h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI=
github.com/prometheus/client_golang v1.20.0/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_golang v1.20.1 h1:IMJXHOD6eARkQpxo8KkhgEVFlBNm+nkrFUyGlIu7Na8=
github.com/prometheus/client_golang v1.20.1/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
Expand Down Expand Up @@ -195,6 +196,8 @@ golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
Expand Down Expand Up @@ -275,6 +278,8 @@ k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20240816214639-573285566f34 h1:/amS69DLm09mtbFtN3+LyygSFohnYGMseF8iv+2zulg=
k8s.io/kube-openapi v0.0.0-20240816214639-573285566f34/go.mod h1:G0W3eI9gG219NHRq3h5uQaRBl4pj4ZpwzRP5ti8y770=
k8s.io/kube-openapi v0.0.0-20240822171749-76de80e0abd9 h1:y+4z/s0h3R97P/o/098DSjlpyNpHzGirNPlTL+GHdqY=
k8s.io/kube-openapi v0.0.0-20240822171749-76de80e0abd9/go.mod h1:s4yb9FXajAVNRnxSB5Ckpr/oq2LP4mKSMWeZDVppd30=
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20240821151609-f90d01438635 h1:2wThSvJoW/Ncn9TmQEYXRnevZXi2duqHWf5OX9S3zjI=
Expand Down
99 changes: 68 additions & 31 deletions pkg/webhook/defaults/pods.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,79 +11,116 @@ import (
corev1 "k8s.io/api/core/v1"
schedulev1 "k8s.io/api/scheduling/v1"
"k8s.io/client-go/tools/record"
"k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
"github.com/projectcapsule/capsule/pkg/api"
"github.com/projectcapsule/capsule/pkg/webhook/utils"
)

func mutatePodDefaults(ctx context.Context, req admission.Request, c client.Client, decoder admission.Decoder, recorder record.EventRecorder, namespace string) *admission.Response {
var err error

pod := &corev1.Pod{}
if err = decoder.Decode(req, pod); err != nil {
var pod corev1.Pod
if err := decoder.Decode(req, &pod); err != nil {
return utils.ErroredResponse(err)
}

pod.SetNamespace(namespace)

var tnt *capsulev1beta2.Tenant
tnt, tErr := utils.TenantByStatusNamespace(ctx, c, pod.Namespace)
if tErr != nil {
return utils.ErroredResponse(tErr)
} else if tnt == nil {
return nil
}

var err error

tnt, err = utils.TenantByStatusNamespace(ctx, c, pod.Namespace)
if err != nil {
return utils.ErroredResponse(err)
pcMutated, pcErr := handlePriorityClassDefault(ctx, c, tnt.Spec.PriorityClasses, &pod)
if pcErr != nil {
return utils.ErroredResponse(pcErr)
} else if pcMutated {
defer func() {
if err == nil {
recorder.Eventf(tnt, corev1.EventTypeNormal, "TenantDefault", "Assigned Tenant default Priority Class %s to %s/%s", tnt.Spec.PriorityClasses.Default, pod.Namespace, pod.Name)
}
}()
}

if tnt == nil {
rcMutated := handleRuntimeClassDefault(tnt.Spec.RuntimeClasses, &pod)
if rcMutated {
defer func() {
if err == nil {
recorder.Eventf(tnt, corev1.EventTypeNormal, "TenantDefault", "Assigned Tenant default Runtime Class %s to %s/%s", tnt.Spec.RuntimeClasses.Default, pod.Namespace, pod.Name)
}
}()
}

if !rcMutated && !pcMutated {
return nil
}

allowed := tnt.Spec.PriorityClasses
var marshaled []byte

if marshaled, err = json.Marshal(pod); err != nil {
return utils.ErroredResponse(err)
}

return ptr.To(admission.PatchResponseFromRaw(req.Object.Raw, marshaled))
}

func handleRuntimeClassDefault(allowed *api.DefaultAllowedListSpec, pod *corev1.Pod) (mutated bool) {
if allowed == nil || allowed.Default == "" {
return nil
return false
}

priorityClassPod := pod.Spec.PriorityClassName
runtimeClass := pod.Spec.RuntimeClassName

switch {
case allowed.Default == "":
return false
case runtimeClass != nil && *runtimeClass != "":
return false
case runtimeClass != nil && *runtimeClass != allowed.Default:
return false
default:
pod.Spec.RuntimeClassName = &allowed.Default

return true
}
}

func handlePriorityClassDefault(ctx context.Context, c client.Client, allowed *api.DefaultAllowedListSpec, pod *corev1.Pod) (mutated bool, err error) {
if allowed == nil || allowed.Default == "" {
return false, nil
}

var mutate bool
priorityClassPod := pod.Spec.PriorityClassName

var cpc *schedulev1.PriorityClass
// PriorityClass name is empty, if no GlobalDefault is set and no PriorityClass was given on pod
if len(priorityClassPod) > 0 && priorityClassPod != allowed.Default {
cpc, err = utils.GetPriorityClassByName(ctx, c, priorityClassPod)
// Should not happen, since API already checks if PC present
if err != nil {
response := admission.Denied(NewPriorityClassError(priorityClassPod, err).Error())

return &response
return false, NewPriorityClassError(priorityClassPod, err)
}
} else {
mutate = true
mutated = true
}

if mutate = mutate || (utils.IsDefaultPriorityClass(cpc) && cpc.GetName() != allowed.Default); !mutate {
return nil
if mutated = mutated || (utils.IsDefaultPriorityClass(cpc) && cpc.GetName() != allowed.Default); !mutated {
return false, nil
}

pc, err := utils.GetPriorityClassByName(ctx, c, allowed.Default)
if err != nil {
return utils.ErroredResponse(fmt.Errorf("failed to assign tenant default Priority Class: %w", err))
return false, fmt.Errorf("failed to assign tenant default Priority Class: %w", err)
}

pod.Spec.PreemptionPolicy = pc.PreemptionPolicy
pod.Spec.Priority = &pc.Value
pod.Spec.PriorityClassName = pc.Name
// Marshal Pod
marshaled, err := json.Marshal(pod)
if err != nil {
return utils.ErroredResponse(err)
}

recorder.Eventf(tnt, corev1.EventTypeNormal, "TenantDefault", "Assigned Tenant default Priority Class %s to %s/%s", allowed.Default, pod.Namespace, pod.Name)

response := admission.PatchResponseFromRaw(req.Object.Raw, marshaled)

return &response
return true, nil
}
4 changes: 2 additions & 2 deletions pkg/webhook/pod/runtimeclass.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ func (h *runtimeClass) validate(ctx context.Context, c client.Client, decoder ad
case allowed == nil:
// Enforcement is not in place, skipping it at all
return nil
case len(runtimeClassName) == 0:
// We don't have to force Pod to specify a RuntimeClass
case len(runtimeClassName) == 0 || runtimeClassName == allowed.Default:
// Delegating mutating webhook to specify a default RuntimeClass
return nil
case !allowed.MatchSelectByName(class):
recorder.Eventf(tnt, corev1.EventTypeWarning, "ForbiddenRuntimeClass", "Pod %s/%s is using Runtime Class %s is forbidden for the current Tenant", pod.Namespace, pod.Name, runtimeClassName)
Expand Down
Loading

0 comments on commit 67d523d

Please sign in to comment.