Adding linters and aligning code (#169)

* Adding linters and aligning code

* Aligning ingressHostnames to AllowedListSpec
This commit is contained in:
Dario Tranchitella
2021-01-13 23:49:11 +01:00
committed by GitHub
parent 89c66de7c6
commit d2700556dd
56 changed files with 430 additions and 564 deletions

View File

@@ -17,7 +17,7 @@ jobs:
with:
version: latest
only-new-issues: false
args: --timeout 2m
args: --timeout 2m --config .golangci.yml
diff:
name: diff
runs-on: ubuntu-18.04

59
.golangci.yml Normal file
View File

@@ -0,0 +1,59 @@
linters-settings:
govet:
check-shadowing: true
golint:
min-confidence: 0
maligned:
suggest-new: true
goimports:
local-prefixes: github.com/clastix/capsule
dupl:
threshold: 100
goconst:
min-len: 2
min-occurrences: 2
linters:
disable-all: true
enable:
- bodyclose
- deadcode
- depguard
- dogsled
- dupl
- errcheck
- goconst
- gocritic
- gofmt
- goimports
- golint
- goprintffuncname
- gosec
- gosimple
- govet
- ineffassign
- interfacer
- misspell
- nolintlint
- rowserrcheck
- scopelint
- staticcheck
- structcheck
- stylecheck
- typecheck
- unconvert
- unparam
- unused
- varcheck
- whitespace
- maligned
issues:
exclude:
- Using the variable on range scope .* in function literal
service:
golangci-lint-version: 1.33.x
run:
skip-files:
- "zz_.*\\.go$"

View File

@@ -131,7 +131,7 @@ goimports:
# Linting code as PR is expecting
.PHONY: golint
golint:
golangci-lint run
golangci-lint run -c .golangci.yml
# Running e2e tests in a KinD instance
.PHONY: e2e

View File

@@ -17,27 +17,30 @@ limitations under the License.
package v1alpha1
import (
"regexp"
"sort"
"strings"
)
type StorageClassList []string
func (n StorageClassList) Len() int {
return len(n)
type AllowedListSpec struct {
Exact []string `json:"allowed,omitempty"`
Regex string `json:"allowedRegex,omitempty"`
}
func (n StorageClassList) Swap(i, j int) {
n[i], n[j] = n[j], n[i]
}
func (n StorageClassList) Less(i, j int) bool {
return strings.ToLower(n[i]) < strings.ToLower(n[j])
}
func (n StorageClassList) IsStringInList(value string) (ok bool) {
sort.Sort(n)
i := sort.SearchStrings(n, value)
ok = i < n.Len() && n[i] == value
func (in *AllowedListSpec) ExactMatch(value string) (ok bool) {
if len(in.Exact) > 0 {
sort.SliceStable(in.Exact, func(i, j int) bool {
return strings.ToLower(in.Exact[i]) < strings.ToLower(in.Exact[j])
})
i := sort.SearchStrings(in.Exact, value)
ok = i < len(in.Exact) && in.Exact[i] == value
}
return
}
func (in AllowedListSpec) RegexMatch(value string) (ok bool) {
if len(in.Regex) > 0 {
ok = regexp.MustCompile(in.Regex).MatchString(value)
}
return
}

View File

@@ -0,0 +1,80 @@
/*
Copyright 2020 Clastix Labs.
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 (
"testing"
"github.com/stretchr/testify/assert"
)
func TestAllowedListSpec_ExactMatch(t *testing.T) {
type tc struct {
In []string
True []string
False []string
}
for _, tc := range []tc{
{
[]string{"foo", "bar", "bizz", "buzz"},
[]string{"foo", "bar", "bizz", "buzz"},
[]string{"bing", "bong"},
},
{
[]string{"one", "two", "three"},
[]string{"one", "two", "three"},
[]string{"a", "b", "c"},
},
{
nil,
nil,
[]string{"any", "value"},
},
} {
a := AllowedListSpec{
Exact: tc.In,
}
for _, ok := range tc.True {
assert.True(t, a.ExactMatch(ok))
}
for _, ko := range tc.False {
assert.False(t, a.ExactMatch(ko))
}
}
}
func TestAllowedListSpec_RegexMatch(t *testing.T) {
type tc struct {
Regex string
True []string
False []string
}
for _, tc := range []tc{
{`first-\w+-pattern`, []string{"first-date-pattern", "first-year-pattern"}, []string{"broken", "first-year", "second-date-pattern"}},
{``, nil, []string{"any", "value"}},
} {
a := AllowedListSpec{
Regex: tc.Regex,
}
for _, ok := range tc.True {
assert.True(t, a.RegexMatch(ok))
}
for _, ko := range tc.False {
assert.False(t, a.RegexMatch(ko))
}
}
}

View File

@@ -16,6 +16,7 @@ limitations under the License.
package domain
type SearchIn interface {
IsStringInList(value string) bool
type AllowedList interface {
ExactMatch(value string) bool
RegexMatch(value string) bool
}

View File

@@ -20,6 +20,8 @@ import (
"regexp"
)
const defaultRegistryName = "docker.io"
type registry map[string]string
func (r registry) Registry() string {
@@ -28,7 +30,7 @@ func (r registry) Registry() string {
return ""
}
if len(res) == 0 {
return "docker.io"
return defaultRegistryName
}
return res
}
@@ -38,7 +40,7 @@ func (r registry) Repository() string {
if !ok {
return ""
}
if res == "docker.io" {
if res == defaultRegistryName {
return ""
}
return res
@@ -64,15 +66,15 @@ func (r registry) Tag() string {
}
func NewRegistry(value string) Registry {
registry := make(registry)
reg := make(registry)
r := regexp.MustCompile(`(((?P<registry>[a-zA-Z0-9-.]+)\/)?((?P<repository>[a-zA-Z0-9-.]+)\/))?(?P<image>[a-zA-Z0-9-.]+)(:(?P<tag>[a-zA-Z0-9-.]+))?`)
match := r.FindStringSubmatch(value)
for i, name := range r.SubexpNames() {
if i > 0 && i <= len(match) {
registry[name] = match[i]
reg[name] = match[i]
}
}
return registry
return reg
}
type Registry interface {

View File

@@ -1,43 +0,0 @@
/*
Copyright 2020 Clastix Labs.
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 (
"sort"
"strings"
)
type IngressClassList []string
func (n IngressClassList) Len() int {
return len(n)
}
func (n IngressClassList) Swap(i, j int) {
n[i], n[j] = n[j], n[i]
}
func (n IngressClassList) Less(i, j int) bool {
return strings.ToLower(n[i]) < strings.ToLower(n[j])
}
func (n IngressClassList) IsStringInList(value string) (ok bool) {
sort.Sort(n)
i := sort.SearchStrings(n, value)
ok = i < n.Len() && n[i] == value
return
}

View File

@@ -1,43 +0,0 @@
/*
Copyright 2020 Clastix Labs.
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 (
"sort"
"strings"
)
type NamespaceList []string
func (n NamespaceList) Len() int {
return len(n)
}
func (n NamespaceList) Swap(i, j int) {
n[i], n[j] = n[j], n[i]
}
func (n NamespaceList) Less(i, j int) bool {
return strings.ToLower(n[i]) < strings.ToLower(n[j])
}
func (n NamespaceList) IsStringInList(value string) (ok bool) {
sort.Sort(n)
i := sort.SearchStrings(n, value)
ok = i < n.Len() && n[i] == value
return
}

View File

@@ -1,43 +0,0 @@
/*
Copyright 2020 Clastix Labs.
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 (
"sort"
"strings"
)
type RegistryList []string
func (in RegistryList) Len() int {
return len(in)
}
func (in RegistryList) Swap(i, j int) {
in[i], in[j] = in[j], in[i]
}
func (in RegistryList) Less(i, j int) bool {
return strings.ToLower(in[i]) < strings.ToLower(in[j])
}
func (in RegistryList) IsStringInList(value string) (ok bool) {
sort.Sort(in)
i := sort.SearchStrings(in, value)
ok = i < in.Len() && in[i] == value
return
}

View File

@@ -17,7 +17,7 @@ limitations under the License.
package v1alpha1
import (
corev1 "k8s.io/api/core/v1"
"fmt"
)
const (
@@ -29,10 +29,10 @@ const (
AllowedRegistriesRegexpAnnotation = "capsule.clastix.io/allowed-registries-regexp"
)
func UsedQuotaFor(resource corev1.ResourceName) string {
func UsedQuotaFor(resource fmt.Stringer) string {
return "quota.capsule.clastix.io/used-" + resource.String()
}
func HardQuotaFor(resource corev1.ResourceName) string {
func HardQuotaFor(resource fmt.Stringer) string {
return "quota.capsule.clastix.io/hard-" + resource.String()
}

View File

@@ -27,7 +27,7 @@ func (t *Tenant) IsFull() bool {
if t.Spec.NamespaceQuota == nil {
return false
}
return t.Status.Namespaces.Len() >= int(*t.Spec.NamespaceQuota)
return len(t.Status.Namespaces) >= int(*t.Spec.NamespaceQuota)
}
func (t *Tenant) AssignNamespaces(namespaces []corev1.Namespace) {

View File

@@ -28,31 +28,16 @@ type AdditionalMetadata struct {
AdditionalAnnotations map[string]string `json:"additionalAnnotations,omitempty"`
}
type StorageClassesSpec struct {
Allowed StorageClassList `json:"allowed,omitempty"`
AllowedRegex string `json:"allowedRegex,omitempty"`
}
type IngressClassesSpec struct {
Allowed IngressClassList `json:"allowed,omitempty"`
AllowedRegex string `json:"allowedRegex,omitempty"`
}
type IngressHostnamesSpec struct {
Allowed IngressHostnamesList `json:"allowed"`
AllowedRegex string `json:"allowedRegex"`
}
type ContainerRegistriesSpec struct {
Allowed RegistryList `json:"allowed,omitempty"`
AllowedRegex string `json:"allowedRegex,omitempty"`
}
// +kubebuilder:validation:Pattern="^([0-9]{1,3}.){3}[0-9]{1,3}(/([0-9]|[1-2][0-9]|3[0-2]))?$"
type AllowedIp string
type AllowedIP string
type ExternalServiceIPs struct {
Allowed []AllowedIp `json:"allowed"`
Allowed []AllowedIP `json:"allowed"`
}
// TenantSpec defines the desired state of Tenant
@@ -63,10 +48,10 @@ type TenantSpec struct {
NamespaceQuota *int32 `json:"namespaceQuota,omitempty"`
NamespacesMetadata AdditionalMetadata `json:"namespacesMetadata,omitempty"`
ServicesMetadata AdditionalMetadata `json:"servicesMetadata,omitempty"`
StorageClasses *StorageClassesSpec `json:"storageClasses,omitempty"`
IngressClasses *IngressClassesSpec `json:"ingressClasses,omitempty"`
IngressHostnames *IngressHostnamesSpec `json:"ingressHostnames,omitempty"`
ContainerRegistries *ContainerRegistriesSpec `json:"containerRegistries,omitempty"`
StorageClasses *AllowedListSpec `json:"storageClasses,omitempty"`
IngressClasses *AllowedListSpec `json:"ingressClasses,omitempty"`
IngressHostnames *AllowedListSpec `json:"ingressHostnames,omitempty"`
ContainerRegistries *AllowedListSpec `json:"containerRegistries,omitempty"`
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
NetworkPolicies []networkingv1.NetworkPolicySpec `json:"networkPolicies,omitempty"`
LimitRanges []corev1.LimitRangeSpec `json:"limitRanges,omitempty"`
@@ -96,8 +81,8 @@ func (k Kind) String() string {
// TenantStatus defines the observed state of Tenant
type TenantStatus struct {
Size uint `json:"size"`
Namespaces NamespaceList `json:"namespaces,omitempty"`
Size uint `json:"size"`
Namespaces []string `json:"namespaces,omitempty"`
}
// +kubebuilder:object:root=true

View File

@@ -77,21 +77,21 @@ func (in *AdditionalRoleBindings) DeepCopy() *AdditionalRoleBindings {
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ContainerRegistriesSpec) DeepCopyInto(out *ContainerRegistriesSpec) {
func (in *AllowedListSpec) DeepCopyInto(out *AllowedListSpec) {
*out = *in
if in.Allowed != nil {
in, out := &in.Allowed, &out.Allowed
*out = make(RegistryList, len(*in))
if in.Exact != nil {
in, out := &in.Exact, &out.Exact
*out = make([]string, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerRegistriesSpec.
func (in *ContainerRegistriesSpec) DeepCopy() *ContainerRegistriesSpec {
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AllowedListSpec.
func (in *AllowedListSpec) DeepCopy() *AllowedListSpec {
if in == nil {
return nil
}
out := new(ContainerRegistriesSpec)
out := new(AllowedListSpec)
in.DeepCopyInto(out)
return out
}
@@ -101,7 +101,7 @@ func (in *ExternalServiceIPs) DeepCopyInto(out *ExternalServiceIPs) {
*out = *in
if in.Allowed != nil {
in, out := &in.Allowed, &out.Allowed
*out = make([]AllowedIp, len(*in))
*out = make([]AllowedIP, len(*in))
copy(*out, *in)
}
}
@@ -116,45 +116,6 @@ func (in *ExternalServiceIPs) DeepCopy() *ExternalServiceIPs {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in IngressClassList) DeepCopyInto(out *IngressClassList) {
{
in := &in
*out = make(IngressClassList, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressClassList.
func (in IngressClassList) DeepCopy() IngressClassList {
if in == nil {
return nil
}
out := new(IngressClassList)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *IngressClassesSpec) DeepCopyInto(out *IngressClassesSpec) {
*out = *in
if in.Allowed != nil {
in, out := &in.Allowed, &out.Allowed
*out = make(IngressClassList, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressClassesSpec.
func (in *IngressClassesSpec) DeepCopy() *IngressClassesSpec {
if in == nil {
return nil
}
out := new(IngressClassesSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in IngressHostnamesList) DeepCopyInto(out *IngressHostnamesList) {
{
@@ -194,25 +155,6 @@ func (in *IngressHostnamesSpec) DeepCopy() *IngressHostnamesSpec {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in NamespaceList) DeepCopyInto(out *NamespaceList) {
{
in := &in
*out = make(NamespaceList, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamespaceList.
func (in NamespaceList) DeepCopy() NamespaceList {
if in == nil {
return nil
}
out := new(NamespaceList)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OwnerSpec) DeepCopyInto(out *OwnerSpec) {
*out = *in
@@ -228,64 +170,6 @@ func (in *OwnerSpec) DeepCopy() *OwnerSpec {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in RegistryList) DeepCopyInto(out *RegistryList) {
{
in := &in
*out = make(RegistryList, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RegistryList.
func (in RegistryList) DeepCopy() RegistryList {
if in == nil {
return nil
}
out := new(RegistryList)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in StorageClassList) DeepCopyInto(out *StorageClassList) {
{
in := &in
*out = make(StorageClassList, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StorageClassList.
func (in StorageClassList) DeepCopy() StorageClassList {
if in == nil {
return nil
}
out := new(StorageClassList)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *StorageClassesSpec) DeepCopyInto(out *StorageClassesSpec) {
*out = *in
if in.Allowed != nil {
in, out := &in.Allowed, &out.Allowed
*out = make(StorageClassList, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StorageClassesSpec.
func (in *StorageClassesSpec) DeepCopy() *StorageClassesSpec {
if in == nil {
return nil
}
out := new(StorageClassesSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Tenant) DeepCopyInto(out *Tenant) {
*out = *in
@@ -358,22 +242,22 @@ func (in *TenantSpec) DeepCopyInto(out *TenantSpec) {
in.ServicesMetadata.DeepCopyInto(&out.ServicesMetadata)
if in.StorageClasses != nil {
in, out := &in.StorageClasses, &out.StorageClasses
*out = new(StorageClassesSpec)
*out = new(AllowedListSpec)
(*in).DeepCopyInto(*out)
}
if in.IngressClasses != nil {
in, out := &in.IngressClasses, &out.IngressClasses
*out = new(IngressClassesSpec)
*out = new(AllowedListSpec)
(*in).DeepCopyInto(*out)
}
if in.IngressHostnames != nil {
in, out := &in.IngressHostnames, &out.IngressHostnames
*out = new(IngressHostnamesSpec)
*out = new(AllowedListSpec)
(*in).DeepCopyInto(*out)
}
if in.ContainerRegistries != nil {
in, out := &in.ContainerRegistries, &out.ContainerRegistries
*out = new(ContainerRegistriesSpec)
*out = new(AllowedListSpec)
(*in).DeepCopyInto(*out)
}
if in.NodeSelector != nil {
@@ -433,7 +317,7 @@ func (in *TenantStatus) DeepCopyInto(out *TenantStatus) {
*out = *in
if in.Namespaces != nil {
in, out := &in.Namespaces, &out.Namespaces
*out = make(NamespaceList, len(*in))
*out = make([]string, len(*in))
copy(*out, *in)
}
}

View File

@@ -142,9 +142,6 @@ spec:
type: array
allowedRegex:
type: string
required:
- allowed
- allowedRegex
type: object
limitRanges:
items:

View File

@@ -54,7 +54,6 @@ func (r *Manager) SetupWithManager(mgr ctrl.Manager) (err error) {
crErr := ctrl.NewControllerManagedBy(mgr).
For(&rbacv1.ClusterRole{}, builder.WithPredicates(predicate.Funcs{
CreateFunc: func(event event.CreateEvent) bool {
return r.filterByClusterRolesNames(event.Object.GetName())
},
DeleteFunc: func(deleteEvent event.DeleteEvent) bool {
@@ -153,7 +152,7 @@ func (r *Manager) EnsureClusterRoleBinding() (err error) {
func (r *Manager) EnsureClusterRole(roleName string) (err error) {
role, ok := clusterRoles[roleName]
if !ok {
return fmt.Errorf("ClusterRole %s is not mapped", roleName)
return fmt.Errorf("clusterRole %s is not mapped", roleName)
}
clusterRole := &rbacv1.ClusterRole{
ObjectMeta: v1.ObjectMeta{

View File

@@ -37,20 +37,21 @@ import (
"github.com/clastix/capsule/pkg/cert"
)
type CaReconciler struct {
type CAReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
Namespace string
}
func (r *CaReconciler) SetupWithManager(mgr ctrl.Manager) error {
func (r *CAReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&corev1.Secret{}, forOptionPerInstanceName(caSecretName)).
Complete(r)
}
func (r CaReconciler) UpdateValidatingWebhookConfiguration(caBundle []byte) error {
//nolint:dupl
func (r CAReconciler) UpdateValidatingWebhookConfiguration(caBundle []byte) error {
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
vw := &v1.ValidatingWebhookConfiguration{}
err = r.Get(context.TODO(), types.NamespacedName{Name: "capsule-validating-webhook-configuration"}, vw)
@@ -68,7 +69,8 @@ func (r CaReconciler) UpdateValidatingWebhookConfiguration(caBundle []byte) erro
})
}
func (r CaReconciler) UpdateMutatingWebhookConfiguration(caBundle []byte) error {
//nolint:dupl
func (r CAReconciler) UpdateMutatingWebhookConfiguration(caBundle []byte) error {
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
mw := &v1.MutatingWebhookConfiguration{}
err = r.Get(context.TODO(), types.NamespacedName{Name: "capsule-mutating-webhook-configuration"}, mw)
@@ -86,7 +88,7 @@ func (r CaReconciler) UpdateMutatingWebhookConfiguration(caBundle []byte) error
})
}
func (r CaReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) {
func (r CAReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) {
var err error
r.Log = r.Log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
@@ -100,7 +102,7 @@ func (r CaReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl
return reconcile.Result{}, err
}
var ca cert.Ca
var ca cert.CA
var rq time.Duration
ca, err = getCertificateAuthority(r.Client, r.Namespace)
if err != nil && errors.Is(err, MissingCaError{}) {
@@ -123,8 +125,8 @@ func (r CaReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl
var crt *bytes.Buffer
var key *bytes.Buffer
crt, _ = ca.CaCertificatePem()
key, _ = ca.CaPrivateKeyPem()
crt, _ = ca.CACertificatePem()
key, _ = ca.CAPrivateKeyPem()
instance.Data = map[string][]byte{
certSecretKey: crt.Bytes(),
@@ -139,7 +141,7 @@ func (r CaReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl
return r.UpdateValidatingWebhookConfiguration(crt.Bytes())
})
if err := group.Wait(); err != nil {
if err = group.Wait(); err != nil {
return reconcile.Result{}, err
}
}

View File

@@ -30,7 +30,7 @@ import (
"github.com/clastix/capsule/pkg/cert"
)
func getCertificateAuthority(client client.Client, namespace string) (ca cert.Ca, err error) {
func getCertificateAuthority(client client.Client, namespace string) (ca cert.CA, err error) {
instance := &corev1.Secret{}
err = client.Get(context.TODO(), types.NamespacedName{

View File

@@ -17,6 +17,7 @@ limitations under the License.
package secret
import (
"bytes"
"context"
"crypto/x509"
"encoding/pem"
@@ -34,20 +35,20 @@ import (
"github.com/clastix/capsule/pkg/cert"
)
type TlsReconciler struct {
type TLSReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
Namespace string
}
func (r *TlsReconciler) SetupWithManager(mgr ctrl.Manager) error {
func (r *TLSReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&corev1.Secret{}, forOptionPerInstanceName(tlsSecretName)).
Complete(r)
}
func (r TlsReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) {
func (r TLSReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) {
var err error
r.Log = r.Log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
@@ -61,7 +62,7 @@ func (r TlsReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctr
return reconcile.Result{}, err
}
var ca cert.Ca
var ca cert.CA
var rq time.Duration
ca, err = getCertificateAuthority(r.Client, r.Namespace)
@@ -82,7 +83,8 @@ func (r TlsReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctr
rq = 6 * 30 * 24 * time.Hour
opts := cert.NewCertOpts(time.Now().Add(rq), "capsule-webhook-service.capsule-system.svc")
crt, key, err := ca.GenerateCertificate(opts)
var crt, key *bytes.Buffer
crt, key, err = ca.GenerateCertificate(opts)
if err != nil {
r.Log.Error(err, "Cannot generate new TLS certificate")
return reconcile.Result{}, err

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package service_labels
package servicelabels
import (
"context"

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package service_labels
package servicelabels
import (
"github.com/go-logr/logr"

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package service_labels
package servicelabels
import (
"github.com/go-logr/logr"

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package service_labels
package servicelabels
import "fmt"

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package service_labels
package servicelabels
import (
"github.com/go-logr/logr"

View File

@@ -76,62 +76,62 @@ func (r TenantReconciler) Reconcile(ctx context.Context, request ctrl.Request) (
return reconcile.Result{}, nil
}
r.Log.Error(err, "Error reading the object")
return reconcile.Result{}, err
return
}
// Ensuring all namespaces are collected
r.Log.Info("Ensuring all Namespaces are collected")
if err := r.collectNamespaces(instance); err != nil {
if err = r.collectNamespaces(instance); err != nil {
r.Log.Error(err, "Cannot collect Namespace resources")
return reconcile.Result{}, err
return
}
r.Log.Info("Starting processing of Namespaces", "items", instance.Status.Namespaces.Len())
if err := r.syncNamespaces(instance); err != nil {
r.Log.Info("Starting processing of Namespaces", "items", len(instance.Status.Namespaces))
if err = r.syncNamespaces(instance); err != nil {
r.Log.Error(err, "Cannot sync Namespace items")
return reconcile.Result{}, err
return
}
r.Log.Info("Starting processing of Network Policies", "items", len(instance.Spec.NetworkPolicies))
if err := r.syncNetworkPolicies(instance); err != nil {
if err = r.syncNetworkPolicies(instance); err != nil {
r.Log.Error(err, "Cannot sync NetworkPolicy items")
return reconcile.Result{}, err
return
}
r.Log.Info("Starting processing of Node Selector")
if err := r.ensureNodeSelector(instance); err != nil {
if err = r.ensureNodeSelector(instance); err != nil {
r.Log.Error(err, "Cannot sync Namespaces Node Selector items")
return reconcile.Result{}, err
return
}
r.Log.Info("Starting processing of Limit Ranges", "items", len(instance.Spec.LimitRanges))
if err := r.syncLimitRanges(instance); err != nil {
if err = r.syncLimitRanges(instance); err != nil {
r.Log.Error(err, "Cannot sync LimitRange items")
return reconcile.Result{}, err
return
}
r.Log.Info("Starting processing of Resource Quotas", "items", len(instance.Spec.ResourceQuota))
if err := r.syncResourceQuotas(instance); err != nil {
if err = r.syncResourceQuotas(instance); err != nil {
r.Log.Error(err, "Cannot sync ResourceQuota items")
return reconcile.Result{}, err
return
}
r.Log.Info("Ensuring PSP for owner")
if err := r.syncAdditionalRoleBindings(instance); err != nil {
if err = r.syncAdditionalRoleBindings(instance); err != nil {
r.Log.Error(err, "Cannot sync additional Role Bindings items")
return reconcile.Result{}, err
return
}
r.Log.Info("Ensuring RoleBinding for owner")
if err := r.ownerRoleBinding(instance); err != nil {
if err = r.ownerRoleBinding(instance); err != nil {
r.Log.Error(err, "Cannot sync owner RoleBinding")
return reconcile.Result{}, err
return
}
r.Log.Info("Ensuring Namespace count")
if err := r.ensureNamespaceCount(instance); err != nil {
if err = r.ensureNamespaceCount(instance); err != nil {
r.Log.Error(err, "Cannot sync Namespace count")
return reconcile.Result{}, err
return
}
r.Log.Info("Tenant reconciling completed")
@@ -155,7 +155,8 @@ func (r *TenantReconciler) pruningResources(ns string, keys []string, obj client
s = s.Add(*exists)
if len(keys) > 0 {
notIn, err := labels.NewRequirement(capsuleLabel, selection.NotIn, keys)
var notIn *labels.Requirement
notIn, err = labels.NewRequirement(capsuleLabel, selection.NotIn, keys)
if err != nil {
return err
}
@@ -177,7 +178,7 @@ func (r *TenantReconciler) pruningResources(ns string, keys []string, obj client
// Serial ResourceQuota processing is expensive: using Go routines we can speed it up.
// In case of multiple errors these are logged properly, returning a generic error since we have to repush back the
// reconciliation loop.
func (r *TenantReconciler) resourceQuotasUpdate(resourceName corev1.ResourceName, actual, limit resource.Quantity, list ...corev1.ResourceQuota) (err error) {
func (r *TenantReconciler) resourceQuotasUpdate(resourceName corev1.ResourceName, actual, limit resource.Quantity, list ...corev1.ResourceQuota) error {
g := errgroup.Group{}
for _, item := range list {
@@ -207,6 +208,7 @@ func (r *TenantReconciler) resourceQuotasUpdate(resourceName corev1.ResourceName
})
}
var err error
if err = g.Wait(); err != nil {
// We had an error and we mark the whole transaction as failed
// to process it another time according to the Tenant controller back-off factor.
@@ -475,27 +477,27 @@ func (r *TenantReconciler) syncNamespace(namespace string, tnt *capsulev1alpha1.
delete(a, capsulev1alpha1.AllowedRegistriesRegexpAnnotation)
if tnt.Spec.IngressClasses != nil {
if len(tnt.Spec.IngressClasses.Allowed) > 0 {
a[capsulev1alpha1.AvailableIngressClassesAnnotation] = strings.Join(tnt.Spec.IngressClasses.Allowed, ",")
if len(tnt.Spec.IngressClasses.Exact) > 0 {
a[capsulev1alpha1.AvailableIngressClassesAnnotation] = strings.Join(tnt.Spec.IngressClasses.Exact, ",")
}
if len(tnt.Spec.IngressClasses.AllowedRegex) > 0 {
a[capsulev1alpha1.AvailableIngressClassesRegexpAnnotation] = tnt.Spec.IngressClasses.AllowedRegex
if len(tnt.Spec.IngressClasses.Regex) > 0 {
a[capsulev1alpha1.AvailableIngressClassesRegexpAnnotation] = tnt.Spec.IngressClasses.Regex
}
}
if tnt.Spec.StorageClasses != nil {
if len(tnt.Spec.StorageClasses.Allowed) > 0 {
a[capsulev1alpha1.AvailableStorageClassesAnnotation] = strings.Join(tnt.Spec.StorageClasses.Allowed, ",")
if len(tnt.Spec.StorageClasses.Exact) > 0 {
a[capsulev1alpha1.AvailableStorageClassesAnnotation] = strings.Join(tnt.Spec.StorageClasses.Exact, ",")
}
if len(tnt.Spec.StorageClasses.AllowedRegex) > 0 {
a[capsulev1alpha1.AvailableStorageClassesRegexpAnnotation] = tnt.Spec.StorageClasses.AllowedRegex
if len(tnt.Spec.StorageClasses.Regex) > 0 {
a[capsulev1alpha1.AvailableStorageClassesRegexpAnnotation] = tnt.Spec.StorageClasses.Regex
}
}
if tnt.Spec.ContainerRegistries != nil {
if len(tnt.Spec.ContainerRegistries.Allowed) > 0 {
a[capsulev1alpha1.AllowedRegistriesAnnotation] = strings.Join(tnt.Spec.ContainerRegistries.Allowed, ",")
if len(tnt.Spec.ContainerRegistries.Exact) > 0 {
a[capsulev1alpha1.AllowedRegistriesAnnotation] = strings.Join(tnt.Spec.ContainerRegistries.Exact, ",")
}
if len(tnt.Spec.ContainerRegistries.AllowedRegex) > 0 {
a[capsulev1alpha1.AllowedRegistriesRegexpAnnotation] = tnt.Spec.ContainerRegistries.AllowedRegex
if len(tnt.Spec.ContainerRegistries.Regex) > 0 {
a[capsulev1alpha1.AllowedRegistriesRegexpAnnotation] = tnt.Spec.ContainerRegistries.Regex
}
}
@@ -509,10 +511,7 @@ func (r *TenantReconciler) syncNamespace(namespace string, tnt *capsulev1alpha1.
if l == nil {
l = make(map[string]string)
}
capsuleLabel, err := capsulev1alpha1.GetTypeLabel(&capsulev1alpha1.Tenant{})
if err != nil {
return err
}
capsuleLabel, _ := capsulev1alpha1.GetTypeLabel(&capsulev1alpha1.Tenant{})
l[capsuleLabel] = tnt.GetName()
if al := tnt.Spec.NamespacesMetadata.AdditionalLabels; al != nil {
for k, v := range al {
@@ -679,7 +678,7 @@ func (r *TenantReconciler) ensureNodeSelector(tenant *capsulev1alpha1.Tenant) (e
func (r *TenantReconciler) ensureNamespaceCount(tenant *capsulev1alpha1.Tenant) error {
return retry.RetryOnConflict(retry.DefaultBackoff, func() error {
tenant.Status.Size = uint(tenant.Status.Namespaces.Len())
tenant.Status.Size = uint(len(tenant.Status.Namespaces))
found := &capsulev1alpha1.Tenant{}
if err := r.Client.Get(context.TODO(), types.NamespacedName{Name: tenant.GetName()}, found); err != nil {
return err

View File

@@ -209,9 +209,11 @@ You can easily check them issuing the _Make_ recipe `golint`.
```
# make golint
golangci-lint run
golangci-lint run -c .golangci.yml
```
> Enabled linters and related options are defined in the [.golanci.yml file](../../.golangci.yml)
### goimports
Also, the Go import statements must be sorted following the best practice:

View File

@@ -41,7 +41,7 @@ var _ = Describe("enforcing an allowed set of Service external IPs", func() {
Kind: "User",
},
ExternalServiceIPs: &v1alpha1.ExternalServiceIPs{
Allowed: []v1alpha1.AllowedIp{
Allowed: []v1alpha1.AllowedIP{
"10.20.0.0/16",
"192.168.1.2/32",
},

View File

@@ -40,9 +40,9 @@ var _ = Describe("enforcing a Container Registry", func() {
Name: "matt",
Kind: "User",
},
ContainerRegistries: &v1alpha1.ContainerRegistriesSpec{
Allowed: []string{"docker.io", "docker.tld"},
AllowedRegex: `quay\.\w+`,
ContainerRegistries: &v1alpha1.AllowedListSpec{
Exact: []string{"docker.io", "docker.tld"},
Regex: `quay\.\w+`,
},
},
}

View File

@@ -41,12 +41,12 @@ var _ = Describe("when Tenant handles Ingress classes", func() {
Name: "ingress",
Kind: "User",
},
IngressClasses: &v1alpha1.IngressClassesSpec{
Allowed: []string{
IngressClasses: &v1alpha1.AllowedListSpec{
Exact: []string{
"nginx",
"haproxy",
},
AllowedRegex: "^oil-.*$",
Regex: "^oil-.*$",
},
},
}
@@ -132,7 +132,7 @@ var _ = Describe("when Tenant handles Ingress classes", func() {
NamespaceCreation(ns, tnt, defaultTimeoutInterval).Should(Succeed())
TenantNamespaceList(tnt, podRecreationTimeoutInterval).Should(ContainElement(ns.GetName()))
for _, c := range tnt.Spec.IngressClasses.Allowed {
for _, c := range tnt.Spec.IngressClasses.Exact {
Eventually(func() (err error) {
i := &extensionsv1beta1.Ingress{
ObjectMeta: metav1.ObjectMeta{
@@ -166,7 +166,7 @@ var _ = Describe("when Tenant handles Ingress classes", func() {
NamespaceCreation(ns, tnt, defaultTimeoutInterval).Should(Succeed())
TenantNamespaceList(tnt, podRecreationTimeoutInterval).Should(ContainElement(ns.GetName()))
for _, c := range tnt.Spec.IngressClasses.Allowed {
for _, c := range tnt.Spec.IngressClasses.Exact {
Eventually(func() (err error) {
i := &extensionsv1beta1.Ingress{
ObjectMeta: metav1.ObjectMeta{

View File

@@ -42,9 +42,9 @@ var _ = Describe("when Tenant handles Ingress hostnames", func() {
Name: "hostname",
Kind: "User",
},
IngressHostnames: &v1alpha1.IngressHostnamesSpec{
Allowed: []string{"sigs.k8s.io", "operator.sdk", "domain.tld"},
AllowedRegex: `.*\.clastix\.io`,
IngressHostnames: &v1alpha1.AllowedListSpec{
Exact: []string{"sigs.k8s.io", "operator.sdk", "domain.tld"},
Regex: `.*\.clastix\.io`,
},
},
}
@@ -165,7 +165,7 @@ var _ = Describe("when Tenant handles Ingress hostnames", func() {
if maj == 1 && min > 18 {
By("testing networking.k8s.io", func() {
for i, h := range tnt.Spec.IngressHostnames.Allowed {
for i, h := range tnt.Spec.IngressHostnames.Exact {
Eventually(func() (err error) {
obj := networkingIngress(fmt.Sprintf("allowed-networking-%d", i), h)
_, err = cs.NetworkingV1().Ingresses(ns.GetName()).Create(context.TODO(), obj, metav1.CreateOptions{})
@@ -177,7 +177,7 @@ var _ = Describe("when Tenant handles Ingress hostnames", func() {
if maj == 1 && min < 22 {
By("testing extensions", func() {
for i, h := range tnt.Spec.IngressHostnames.Allowed {
for i, h := range tnt.Spec.IngressHostnames.Exact {
Eventually(func() (err error) {
obj := extensionsIngress(fmt.Sprintf("allowed-extensions-%d", i), h)
_, err = cs.ExtensionsV1beta1().Ingresses(ns.GetName()).Create(context.TODO(), obj, metav1.CreateOptions{})

View File

@@ -43,8 +43,8 @@ var _ = Describe("when Tenant owner interacts with the webhooks", func() {
Name: "ruby",
Kind: "User",
},
StorageClasses: &v1alpha1.StorageClassesSpec{
Allowed: []string{
StorageClasses: &v1alpha1.AllowedListSpec{
Exact: []string{
"cephfs",
"glusterfs",
},

View File

@@ -41,12 +41,12 @@ var _ = Describe("when Tenant handles Storage classes", func() {
Name: "storage",
Kind: "User",
},
StorageClasses: &v1alpha1.StorageClassesSpec{
Allowed: []string{
StorageClasses: &v1alpha1.AllowedListSpec{
Exact: []string{
"cephfs",
"glusterfs",
},
AllowedRegex: "^oil-.*$",
Regex: "^oil-.*$",
},
},
}
@@ -115,7 +115,7 @@ var _ = Describe("when Tenant handles Storage classes", func() {
NamespaceCreation(ns, tnt, defaultTimeoutInterval).Should(Succeed())
TenantNamespaceList(tnt, podRecreationTimeoutInterval).Should(ContainElement(ns.GetName()))
By("using exact matches", func() {
for _, c := range tnt.Spec.StorageClasses.Allowed {
for _, c := range tnt.Spec.StorageClasses.Exact {
Eventually(func() (err error) {
p := &corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{

View File

@@ -38,8 +38,8 @@ var _ = Describe("when a second Tenant contains an already declared allowed Ingr
Name: "first-user",
Kind: "User",
},
IngressHostnames: &v1alpha1.IngressHostnamesSpec{
Allowed: []string{"capsule.clastix.io", "docs.capsule.k8s", "42.clatix.io"},
IngressHostnames: &v1alpha1.AllowedListSpec{
Exact: []string{"capsule.clastix.io", "docs.capsule.k8s", "42.clatix.io"},
},
},
}
@@ -55,7 +55,7 @@ var _ = Describe("when a second Tenant contains an already declared allowed Ingr
})
It("should block creation if contains collided Ingress hostnames", func() {
for _, h := range tnt.Spec.IngressHostnames.Allowed {
for _, h := range tnt.Spec.IngressHostnames.Exact {
tnt2 := &v1alpha1.Tenant{
ObjectMeta: metav1.ObjectMeta{
Name: "second-ingress-hostnames",
@@ -65,8 +65,8 @@ var _ = Describe("when a second Tenant contains an already declared allowed Ingr
Name: "second-user",
Kind: "User",
},
IngressHostnames: &v1alpha1.IngressHostnamesSpec{
Allowed: []string{h},
IngressHostnames: &v1alpha1.AllowedListSpec{
Exact: []string{h},
},
},
}

View File

@@ -60,7 +60,7 @@ func NamespaceCreation(ns *corev1.Namespace, t *v1alpha1.Tenant, timeout time.Du
}
func TenantNamespaceList(t *v1alpha1.Tenant, timeout time.Duration) AsyncAssertion {
return Eventually(func() v1alpha1.NamespaceList {
return Eventually(func() []string {
Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: t.GetName()}, t)).Should(Succeed())
return t.Status.Namespaces
}, timeout, defaultPollInterval)

28
main.go
View File

@@ -36,18 +36,18 @@ import (
"github.com/clastix/capsule/controllers"
"github.com/clastix/capsule/controllers/rbac"
"github.com/clastix/capsule/controllers/secret"
"github.com/clastix/capsule/controllers/service_labels"
"github.com/clastix/capsule/controllers/servicelabels"
"github.com/clastix/capsule/pkg/indexer"
"github.com/clastix/capsule/pkg/webhook"
"github.com/clastix/capsule/pkg/webhook/ingress"
"github.com/clastix/capsule/pkg/webhook/namespace_quota"
"github.com/clastix/capsule/pkg/webhook/network_policies"
"github.com/clastix/capsule/pkg/webhook/owner_reference"
"github.com/clastix/capsule/pkg/webhook/namespacequota"
"github.com/clastix/capsule/pkg/webhook/networkpolicies"
"github.com/clastix/capsule/pkg/webhook/ownerreference"
"github.com/clastix/capsule/pkg/webhook/pvc"
"github.com/clastix/capsule/pkg/webhook/registry"
"github.com/clastix/capsule/pkg/webhook/services"
"github.com/clastix/capsule/pkg/webhook/tenant"
"github.com/clastix/capsule/pkg/webhook/tenant_prefix"
"github.com/clastix/capsule/pkg/webhook/tenantprefix"
"github.com/clastix/capsule/pkg/webhook/utils"
// +kubebuilder:scaffold:imports
)
@@ -161,10 +161,10 @@ func main() {
pvc.Webhook(pvc.Handler()),
registry.Webhook(registry.Handler()),
services.Webhook(services.Handler()),
owner_reference.Webhook(utils.InCapsuleGroup(capsuleGroup, owner_reference.Handler(forceTenantPrefix))),
namespace_quota.Webhook(utils.InCapsuleGroup(capsuleGroup, namespace_quota.Handler())),
network_policies.Webhook(utils.InCapsuleGroup(capsuleGroup, network_policies.Handler())),
tenant_prefix.Webhook(utils.InCapsuleGroup(capsuleGroup, tenant_prefix.Handler(forceTenantPrefix, protectedNamespaceRegexp))),
ownerreference.Webhook(utils.InCapsuleGroup(capsuleGroup, ownerreference.Handler(forceTenantPrefix))),
namespacequota.Webhook(utils.InCapsuleGroup(capsuleGroup, namespacequota.Handler())),
networkpolicies.Webhook(utils.InCapsuleGroup(capsuleGroup, networkpolicies.Handler())),
tenantprefix.Webhook(utils.InCapsuleGroup(capsuleGroup, tenantprefix.Handler(forceTenantPrefix, protectedNamespaceRegexp))),
tenant.Webhook(tenant.Handler()),
)
if err = webhook.Register(mgr, wl...); err != nil {
@@ -185,7 +185,7 @@ func main() {
os.Exit(1)
}
if err = (&secret.CaReconciler{
if err = (&secret.CAReconciler{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("CA"),
Scheme: mgr.GetScheme(),
@@ -194,7 +194,7 @@ func main() {
setupLog.Error(err, "unable to create controller", "controller", "Namespace")
os.Exit(1)
}
if err = (&secret.TlsReconciler{
if err = (&secret.TLSReconciler{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("Tls"),
Scheme: mgr.GetScheme(),
@@ -204,19 +204,19 @@ func main() {
os.Exit(1)
}
if err = (&service_labels.ServicesLabelsReconciler{
if err = (&servicelabels.ServicesLabelsReconciler{
Log: ctrl.Log.WithName("controllers").WithName("ServiceLabels"),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "ServiceLabels")
os.Exit(1)
}
if err = (&service_labels.EndpointsLabelsReconciler{
if err = (&servicelabels.EndpointsLabelsReconciler{
Log: ctrl.Log.WithName("controllers").WithName("EndpointLabels"),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "EndpointLabels")
os.Exit(1)
}
if err = (&service_labels.EndpointSlicesLabelsReconciler{
if err = (&servicelabels.EndpointSlicesLabelsReconciler{
Log: ctrl.Log.WithName("controllers").WithName("EndpointSliceLabels"),
VersionMinor: minorVer,
VersionMajor: majorVer,

View File

@@ -27,22 +27,22 @@ import (
"time"
)
type Ca interface {
type CA interface {
GenerateCertificate(opts CertificateOptions) (certificatePem *bytes.Buffer, certificateKey *bytes.Buffer, err error)
CaCertificatePem() (b *bytes.Buffer, err error)
CaPrivateKeyPem() (b *bytes.Buffer, err error)
CACertificatePem() (b *bytes.Buffer, err error)
CAPrivateKeyPem() (b *bytes.Buffer, err error)
ExpiresIn(now time.Time) (time.Duration, error)
ValidateCert(certificate *x509.Certificate) error
}
type CapsuleCa struct {
ca *x509.Certificate
privateKey *rsa.PrivateKey
type CapsuleCA struct {
certificate *x509.Certificate
key *rsa.PrivateKey
}
func (c CapsuleCa) ValidateCert(certificate *x509.Certificate) (err error) {
func (c CapsuleCA) ValidateCert(certificate *x509.Certificate) (err error) {
pool := x509.NewCertPool()
pool.AddCert(c.ca)
pool.AddCert(c.certificate)
_, err = certificate.Verify(x509.VerifyOptions{
Roots: pool,
@@ -51,27 +51,27 @@ func (c CapsuleCa) ValidateCert(certificate *x509.Certificate) (err error) {
return
}
func (c CapsuleCa) isAlreadyValid(now time.Time) bool {
return now.After(c.ca.NotBefore)
func (c CapsuleCA) isAlreadyValid(now time.Time) bool {
return now.After(c.certificate.NotBefore)
}
func (c CapsuleCa) isExpired(now time.Time) bool {
return now.Before(c.ca.NotAfter)
func (c CapsuleCA) isExpired(now time.Time) bool {
return now.Before(c.certificate.NotAfter)
}
func (c CapsuleCa) ExpiresIn(now time.Time) (time.Duration, error) {
func (c CapsuleCA) ExpiresIn(now time.Time) (time.Duration, error) {
if !c.isExpired(now) {
return time.Nanosecond, CaExpiredError{}
}
if !c.isAlreadyValid(now) {
return time.Nanosecond, CaNotYetValidError{}
}
return time.Duration(c.ca.NotAfter.Unix()-now.Unix()) * time.Second, nil
return time.Duration(c.certificate.NotAfter.Unix()-now.Unix()) * time.Second, nil
}
func (c CapsuleCa) CaCertificatePem() (b *bytes.Buffer, err error) {
func (c CapsuleCA) CACertificatePem() (b *bytes.Buffer, err error) {
var crtBytes []byte
crtBytes, err = x509.CreateCertificate(rand.Reader, c.ca, c.ca, &c.privateKey.PublicKey, c.privateKey)
crtBytes, err = x509.CreateCertificate(rand.Reader, c.certificate, c.certificate, &c.key.PublicKey, c.key)
if err != nil {
return
}
@@ -83,17 +83,17 @@ func (c CapsuleCa) CaCertificatePem() (b *bytes.Buffer, err error) {
return b, err
}
func (c CapsuleCa) CaPrivateKeyPem() (b *bytes.Buffer, err error) {
func (c CapsuleCA) CAPrivateKeyPem() (b *bytes.Buffer, err error) {
b = new(bytes.Buffer)
return b, pem.Encode(b, &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(c.privateKey),
Bytes: x509.MarshalPKCS1PrivateKey(c.key),
})
}
func GenerateCertificateAuthority() (s *CapsuleCa, err error) {
s = &CapsuleCa{
ca: &x509.Certificate{
func GenerateCertificateAuthority() (s *CapsuleCA, err error) {
s = &CapsuleCA{
certificate: &x509.Certificate{
SerialNumber: big.NewInt(2019),
Subject: pkix.Name{
Organization: []string{"Clastix"},
@@ -112,7 +112,7 @@ func GenerateCertificateAuthority() (s *CapsuleCa, err error) {
},
}
s.privateKey, err = rsa.GenerateKey(rand.Reader, 4096)
s.key, err = rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return nil, err
}
@@ -120,7 +120,7 @@ func GenerateCertificateAuthority() (s *CapsuleCa, err error) {
return
}
func NewCertificateAuthorityFromBytes(certBytes, keyBytes []byte) (s *CapsuleCa, err error) {
func NewCertificateAuthorityFromBytes(certBytes, keyBytes []byte) (s *CapsuleCA, err error) {
var b *pem.Block
b, _ = pem.Decode(certBytes)
@@ -135,16 +135,17 @@ func NewCertificateAuthorityFromBytes(certBytes, keyBytes []byte) (s *CapsuleCa,
return
}
s = &CapsuleCa{
ca: cert,
privateKey: key,
s = &CapsuleCA{
certificate: cert,
key: key,
}
return
}
func (c *CapsuleCa) GenerateCertificate(opts CertificateOptions) (certificatePem *bytes.Buffer, certificateKey *bytes.Buffer, err error) {
certPrivKey, err := rsa.GenerateKey(rand.Reader, 4096)
func (c *CapsuleCA) GenerateCertificate(opts CertificateOptions) (certificatePem *bytes.Buffer, certificateKey *bytes.Buffer, err error) {
var certPrivKey *rsa.PrivateKey
certPrivKey, err = rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return nil, nil, err
}
@@ -159,7 +160,7 @@ func (c *CapsuleCa) GenerateCertificate(opts CertificateOptions) (certificatePem
StreetAddress: []string{"27, Old Gloucester Street"},
PostalCode: []string{"WC1N 3AX"},
},
DNSNames: opts.DnsNames(),
DNSNames: opts.DNSNames(),
NotBefore: time.Now().AddDate(0, 0, -1),
NotAfter: opts.ExpirationDate(),
SubjectKeyId: []byte{1, 2, 3, 4, 6},
@@ -167,7 +168,8 @@ func (c *CapsuleCa) GenerateCertificate(opts CertificateOptions) (certificatePem
KeyUsage: x509.KeyUsageDigitalSignature,
}
certBytes, err := x509.CreateCertificate(rand.Reader, cert, c.ca, &certPrivKey.PublicKey, c.privateKey)
var certBytes []byte
certBytes, err = x509.CreateCertificate(rand.Reader, cert, c.certificate, &certPrivKey.PublicKey, c.key)
if err != nil {
return nil, nil, err
}

View File

@@ -12,18 +12,18 @@ import (
)
func TestNewCertificateAuthorityFromBytes(t *testing.T) {
var ca *CapsuleCa
var ca *CapsuleCA
var err error
ca, err = GenerateCertificateAuthority()
assert.Nil(t, err)
var crt *bytes.Buffer
crt, err = ca.CaCertificatePem()
crt, err = ca.CACertificatePem()
assert.Nil(t, err)
var key *bytes.Buffer
key, err = ca.CaPrivateKeyPem()
key, err = ca.CAPrivateKeyPem()
assert.Nil(t, err)
_, err = NewCertificateAuthorityFromBytes(crt.Bytes(), key.Bytes())
@@ -39,7 +39,7 @@ func TestCapsuleCa_GenerateCertificate(t *testing.T) {
"SAN": {[]string{"capsule-webhook-service.capsule-system.svc", "capsule-webhook-service.capsule-system.default.cluster"}},
} {
t.Run(name, func(t *testing.T) {
var ca *CapsuleCa
var ca *CapsuleCA
var err error
e := time.Now().AddDate(1, 0, 0)
@@ -83,14 +83,14 @@ func TestCapsuleCa_IsValid(t *testing.T) {
}
for name, c := range tc {
t.Run(name, func(t *testing.T) {
var ca *CapsuleCa
var ca *CapsuleCA
var err error
ca, err = GenerateCertificateAuthority()
assert.Nil(t, err)
ca.ca.NotAfter = c.notAfter
ca.ca.NotBefore = c.notBefore
ca.certificate.NotAfter = c.notAfter
ca.certificate.NotBefore = c.notBefore
var w time.Duration
w, err = ca.ExpiresIn(time.Now())
@@ -99,7 +99,7 @@ func TestCapsuleCa_IsValid(t *testing.T) {
return
}
assert.Nil(t, err)
assert.WithinDuration(t, ca.ca.NotAfter, time.Now().Add(w), time.Minute)
assert.WithinDuration(t, ca.certificate.NotAfter, time.Now().Add(w), time.Minute)
})
}
}

View File

@@ -19,7 +19,7 @@ package cert
import "time"
type CertificateOptions interface {
DnsNames() []string
DNSNames() []string
ExpirationDate() time.Time
}
@@ -28,7 +28,7 @@ type certOpts struct {
expirationDate time.Time
}
func (c certOpts) DnsNames() []string {
func (c certOpts) DNSNames() []string {
return c.dnsNames
}
@@ -36,6 +36,6 @@ func (c certOpts) ExpirationDate() time.Time {
return c.expirationDate
}
func NewCertOpts(expirationDate time.Time, dnsNames ...string) *certOpts {
func NewCertOpts(expirationDate time.Time, dnsNames ...string) CertificateOptions {
return &certOpts{dnsNames: dnsNames, expirationDate: expirationDate}
}

View File

@@ -34,11 +34,11 @@ func (IngressHostnames) Field() string {
}
func (IngressHostnames) Func() client.IndexerFunc {
return func(object client.Object) []string {
return func(object client.Object) (out []string) {
tenant := object.(*v1alpha1.Tenant)
if tenant.Spec.IngressHostnames != nil {
return tenant.Spec.IngressHostnames.Allowed.DeepCopy()
out = append(out, tenant.Spec.IngressHostnames.Exact...)
}
return nil
return
}
}

View File

@@ -35,7 +35,6 @@ func (o NamespacesReference) Field() string {
func (o NamespacesReference) Func() client.IndexerFunc {
return func(object client.Object) []string {
tenant := object.(*v1alpha1.Tenant)
return tenant.Status.Namespaces.DeepCopy()
return object.(*v1alpha1.Tenant).DeepCopy().Status.Namespaces
}
}

View File

@@ -25,10 +25,10 @@ import (
type ingressClassForbidden struct {
className string
spec v1alpha1.IngressClassesSpec
spec v1alpha1.AllowedListSpec
}
func NewIngressClassForbidden(className string, spec v1alpha1.IngressClassesSpec) error {
func NewIngressClassForbidden(className string, spec v1alpha1.AllowedListSpec) error {
return &ingressClassForbidden{
className: className,
spec: spec,
@@ -42,11 +42,10 @@ func (i ingressClassForbidden) Error() string {
type ingressHostnameNotValid struct {
invalidHostnames []string
notMatchingHostnames []string
spec v1alpha1.IngressHostnamesSpec
spec v1alpha1.AllowedListSpec
}
func NewIngressHostnamesNotValid(invalidHostnames []string, notMatchingHostnames []string, spec v1alpha1.IngressHostnamesSpec) error {
func NewIngressHostnamesNotValid(invalidHostnames []string, notMatchingHostnames []string, spec v1alpha1.AllowedListSpec) error {
return &ingressHostnameNotValid{invalidHostnames: invalidHostnames, notMatchingHostnames: notMatchingHostnames, spec: spec}
}
@@ -56,10 +55,10 @@ func (i ingressHostnameNotValid) Error() string {
}
type ingressClassNotValid struct {
spec v1alpha1.IngressClassesSpec
spec v1alpha1.AllowedListSpec
}
func NewIngressClassNotValid(spec v1alpha1.IngressClassesSpec) error {
func NewIngressClassNotValid(spec v1alpha1.AllowedListSpec) error {
return &ingressClassNotValid{
spec: spec,
}
@@ -69,22 +68,22 @@ func (i ingressClassNotValid) Error() string {
return "A valid Ingress Class must be used" + appendClassError(i.spec)
}
func appendClassError(spec v1alpha1.IngressClassesSpec) (append string) {
if len(spec.Allowed) > 0 {
append += fmt.Sprintf(", one of the following (%s)", strings.Join(spec.Allowed, ", "))
func appendClassError(spec v1alpha1.AllowedListSpec) (append string) {
if len(spec.Exact) > 0 {
append += fmt.Sprintf(", one of the following (%s)", strings.Join(spec.Exact, ", "))
}
if len(spec.AllowedRegex) > 0 {
append += fmt.Sprintf(", or matching the regex %s", spec.AllowedRegex)
if len(spec.Regex) > 0 {
append += fmt.Sprintf(", or matching the regex %s", spec.Regex)
}
return
}
func appendHostnameError(spec v1alpha1.IngressHostnamesSpec) (append string) {
if len(spec.Allowed) > 0 {
append += fmt.Sprintf(", specify one of the following (%s)", strings.Join(spec.Allowed, ", "))
func appendHostnameError(spec v1alpha1.AllowedListSpec) (append string) {
if len(spec.Exact) > 0 {
append += fmt.Sprintf(", specify one of the following (%s)", strings.Join(spec.Exact, ", "))
}
if len(spec.AllowedRegex) > 0 {
append += fmt.Sprintf(", or matching the regex %s", spec.AllowedRegex)
if len(spec.Regex) > 0 {
append += fmt.Sprintf(", or matching the regex %s", spec.Regex)
}
return
}

View File

@@ -37,7 +37,6 @@ type NetworkingV1 struct {
}
func (n NetworkingV1) IngressClass() (res *string) {
res = n.Spec.IngressClassName
if res == nil {
if a := n.GetAnnotations(); a != nil {
@@ -67,7 +66,6 @@ type NetworkingV1Beta1 struct {
}
func (n NetworkingV1Beta1) IngressClass() (res *string) {
res = n.Spec.IngressClassName
if res == nil {
if a := n.GetAnnotations(); a != nil {

View File

@@ -98,21 +98,21 @@ func (r *handler) ingressFromRequest(req admission.Request, decoder *admission.D
case "networking.k8s.io":
if req.Kind.Version == "v1" {
n := &networkingv1.Ingress{}
if err := decoder.Decode(req, n); err != nil {
return nil, err
if err = decoder.Decode(req, n); err != nil {
return
}
ingress = NetworkingV1{Ingress: n}
break
}
n := &networkingv1beta1.Ingress{}
if err := decoder.Decode(req, n); err != nil {
return nil, err
if err = decoder.Decode(req, n); err != nil {
return
}
ingress = NetworkingV1Beta1{Ingress: n}
case "extensions":
e := &extensionsv1beta1.Ingress{}
if err := decoder.Decode(req, e); err != nil {
return nil, err
if err = decoder.Decode(req, e); err != nil {
return
}
ingress = Extension{Ingress: e}
default:
@@ -146,13 +146,10 @@ func (r *handler) validateIngress(ctx context.Context, c client.Client, ingress
return admission.Errored(http.StatusBadRequest, NewIngressClassNotValid(*tnt.Spec.IngressClasses))
}
if len(tnt.Spec.IngressClasses.Allowed) > 0 {
valid = tnt.Spec.IngressClasses.Allowed.IsStringInList(*ingressClass)
}
if len(tnt.Spec.IngressClasses.AllowedRegex) > 0 {
matched, _ = regexp.MatchString(tnt.Spec.IngressClasses.AllowedRegex, *ingressClass)
if len(tnt.Spec.IngressClasses.Exact) > 0 {
valid = tnt.Spec.IngressClasses.ExactMatch(*ingressClass)
}
matched = tnt.Spec.IngressClasses.RegexMatch(*ingressClass)
if !valid && !matched {
return admission.Errored(http.StatusBadRequest, NewIngressClassForbidden(*ingressClass, *tnt.Spec.IngressClasses))
@@ -166,7 +163,7 @@ func (r *handler) validateIngress(ctx context.Context, c client.Client, ingress
hostnames := ingress.Hostnames()
if len(hostnames) > 0 {
for _, currentHostname := range hostnames {
isPresent := tnt.Spec.IngressHostnames.Allowed.IsStringInList(currentHostname)
isPresent := v1alpha1.IngressHostnamesList(tnt.Spec.IngressHostnames.Exact).IsStringInList(currentHostname)
if !isPresent {
invalidHostnames = append(invalidHostnames, currentHostname)
}
@@ -177,10 +174,10 @@ func (r *handler) validateIngress(ctx context.Context, c client.Client, ingress
}
var notMatchingHostnames []string
allowedRegex := tnt.Spec.IngressHostnames.AllowedRegex
allowedRegex := tnt.Spec.IngressHostnames.Regex
if len(allowedRegex) > 0 {
for _, currentHostname := range hostnames {
matched, _ := regexp.MatchString(tnt.Spec.IngressHostnames.AllowedRegex, currentHostname)
matched, _ = regexp.MatchString(tnt.Spec.IngressHostnames.Regex, currentHostname)
if !matched {
notMatchingHostnames = append(notMatchingHostnames, currentHostname)
}
@@ -195,5 +192,4 @@ func (r *handler) validateIngress(ctx context.Context, c client.Client, ingress
}
return admission.Allowed("")
}

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package namespace_quota
package namespacequota
type namespaceQuotaExceededError struct{}

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package namespace_quota
package namespacequota
import (
"context"

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package network_policies
package networkpolicies
import (
"context"
@@ -64,7 +64,7 @@ func (r *handler) OnCreate(client client.Client, decoder *admission.Decoder) cap
}
}
func (r *handler) generic(ctx context.Context, req admission.Request, client client.Client, decoder *admission.Decoder) (bool, error) {
func (r *handler) generic(ctx context.Context, req admission.Request, client client.Client, _ *admission.Decoder) (bool, error) {
var err error
np := &networkingv1.NetworkPolicy{}
err = client.Get(ctx, types.NamespacedName{Namespace: req.AdmissionRequest.Namespace, Name: req.AdmissionRequest.Name}, np)

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package owner_reference
package ownerreference
import (
"context"
@@ -32,7 +32,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
"github.com/clastix/capsule/api/v1alpha1"
capsulev1alpha1 "github.com/clastix/capsule/api/v1alpha1"
capsulewebhook "github.com/clastix/capsule/pkg/webhook"
)
@@ -133,7 +132,7 @@ func (h *handler) OnCreate(clt client.Client, decoder *admission.Decoder) capsul
if h.forceTenantPrefix {
for _, tnt := range tenants {
if strings.HasPrefix(ns.GetName(), fmt.Sprintf("%s-", tnt.GetName())) {
return h.patchResponseForOwnerRef(&tnt, ns)
return h.patchResponseForOwnerRef(tnt.DeepCopy(), ns)
}
}
admission.Denied("The Namespace prefix used doesn't match any available Tenant")
@@ -167,8 +166,8 @@ func (h *handler) patchResponseForOwnerRef(tenant *capsulev1alpha1.Tenant, ns *c
return admission.PatchResponseFromRaw(o, c)
}
func (h *handler) listTenantsForOwnerKind(ctx context.Context, ownerKind string, ownerName string, clt client.Client) (*v1alpha1.TenantList, error) {
tl := &v1alpha1.TenantList{}
func (h *handler) listTenantsForOwnerKind(ctx context.Context, ownerKind string, ownerName string, clt client.Client) (*capsulev1alpha1.TenantList, error) {
tl := &capsulev1alpha1.TenantList{}
f := client.MatchingFields{
".spec.owner.ownerkind": fmt.Sprintf("%s:%s", ownerKind, ownerName),
}
@@ -176,7 +175,7 @@ func (h *handler) listTenantsForOwnerKind(ctx context.Context, ownerKind string,
return tl, err
}
func (h *handler) isTenantOwner(os v1alpha1.OwnerSpec, userInfo authenticationv1.UserInfo) bool {
func (h *handler) isTenantOwner(os capsulev1alpha1.OwnerSpec, userInfo authenticationv1.UserInfo) bool {
if os.Kind == "User" && userInfo.Username == os.Name {
return true
}

View File

@@ -24,21 +24,21 @@ import (
)
type storageClassNotValid struct {
spec v1alpha1.StorageClassesSpec
spec v1alpha1.AllowedListSpec
}
func NewStorageClassNotValid(storageClasses v1alpha1.StorageClassesSpec) error {
func NewStorageClassNotValid(storageClasses v1alpha1.AllowedListSpec) error {
return &storageClassNotValid{
spec: storageClasses,
}
}
func appendError(spec v1alpha1.StorageClassesSpec) (append string) {
if len(spec.Allowed) > 0 {
append += fmt.Sprintf(", one of the following (%s)", strings.Join(spec.Allowed, ", "))
func appendError(spec v1alpha1.AllowedListSpec) (append string) {
if len(spec.Exact) > 0 {
append += fmt.Sprintf(", one of the following (%s)", strings.Join(spec.Exact, ", "))
}
if len(spec.AllowedRegex) > 0 {
append += fmt.Sprintf(", or matching the regex %s", spec.AllowedRegex)
if len(spec.Regex) > 0 {
append += fmt.Sprintf(", or matching the regex %s", spec.Regex)
}
return
}
@@ -49,10 +49,10 @@ func (s storageClassNotValid) Error() (err string) {
type storageClassForbidden struct {
className string
spec v1alpha1.StorageClassesSpec
spec v1alpha1.AllowedListSpec
}
func NewStorageClassForbidden(className string, storageClasses v1alpha1.StorageClassesSpec) error {
func NewStorageClassForbidden(className string, storageClasses v1alpha1.AllowedListSpec) error {
return &storageClassForbidden{
className: className,
spec: storageClasses,

View File

@@ -19,7 +19,6 @@ package pvc
import (
"context"
"net/http"
"regexp"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/fields"
@@ -90,15 +89,8 @@ func (h *handler) OnCreate(c client.Client, decoder *admission.Decoder) capsulew
}
sc := *pvc.Spec.StorageClassName
if len(tnt.Spec.StorageClasses.Allowed) > 0 {
valid = tnt.Spec.StorageClasses.Allowed.IsStringInList(sc)
}
if len(tnt.Spec.StorageClasses.AllowedRegex) > 0 {
matched, _ = regexp.MatchString(tnt.Spec.StorageClasses.AllowedRegex, sc)
}
valid = tnt.Spec.StorageClasses.ExactMatch(sc)
matched = tnt.Spec.StorageClasses.RegexMatch(sc)
if !valid && !matched {
return admission.Errored(http.StatusBadRequest, NewStorageClassForbidden(*pvc.Spec.StorageClassName, *tnt.Spec.StorageClasses))
}

View File

@@ -25,10 +25,10 @@ import (
type registryClassForbidden struct {
fqdi string
spec v1alpha1.ContainerRegistriesSpec
spec v1alpha1.AllowedListSpec
}
func NewContainerRegistryForbidden(image string, spec v1alpha1.ContainerRegistriesSpec) error {
func NewContainerRegistryForbidden(image string, spec v1alpha1.AllowedListSpec) error {
return &registryClassForbidden{
fqdi: image,
spec: spec,
@@ -38,11 +38,11 @@ func NewContainerRegistryForbidden(image string, spec v1alpha1.ContainerRegistri
func (f registryClassForbidden) Error() (err string) {
err = fmt.Sprintf("Container image %s registry is forbidden for the current Tenant: ", f.fqdi)
var extra []string
if len(f.spec.Allowed) > 0 {
extra = append(extra, fmt.Sprintf("use one from the following list (%s)", strings.Join(f.spec.Allowed, ", ")))
if len(f.spec.Exact) > 0 {
extra = append(extra, fmt.Sprintf("use one from the following list (%s)", strings.Join(f.spec.Exact, ", ")))
}
if len(f.spec.AllowedRegex) > 0 {
extra = append(extra, fmt.Sprintf(" use one matching the following regex (%s)", f.spec.AllowedRegex))
if len(f.spec.Regex) > 0 {
extra = append(extra, fmt.Sprintf(" use one matching the following regex (%s)", f.spec.Regex))
}
err += strings.Join(extra, " or ")
return

View File

@@ -19,7 +19,6 @@ package registry
import (
"context"
"net/http"
"regexp"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/fields"
@@ -81,13 +80,10 @@ func (h *handler) OnCreate(c client.Client, decoder *admission.Decoder) capsulew
if tnt.Spec.ContainerRegistries != nil {
var valid, matched bool
regex := regexp.MustCompile(tnt.Spec.ContainerRegistries.AllowedRegex)
for _, container := range pod.Spec.Containers {
r := domain.NewRegistry(container.Image)
valid = tnt.Spec.ContainerRegistries.Allowed.IsStringInList(r.Registry())
if len(tnt.Spec.ContainerRegistries.AllowedRegex) > 0 {
matched = regex.MatchString(r.Registry())
}
valid = tnt.Spec.ContainerRegistries.ExactMatch(r.Registry())
matched = tnt.Spec.ContainerRegistries.RegexMatch(r.Registry())
if !valid && !matched {
return admission.Errored(http.StatusBadRequest, NewContainerRegistryForbidden(container.Image, *tnt.Spec.ContainerRegistries))
}

View File

@@ -27,7 +27,7 @@ type externalServiceIPForbidden struct {
cidr []string
}
func NewExternalServiceIPForbidden(allowedIps []v1alpha1.AllowedIp) error {
func NewExternalServiceIPForbidden(allowedIps []v1alpha1.AllowedIP) error {
var cidr []string
for _, i := range allowedIps {
cidr = append(cidr, string(i))
@@ -38,6 +38,5 @@ func NewExternalServiceIPForbidden(allowedIps []v1alpha1.AllowedIp) error {
}
func (e externalServiceIPForbidden) Error() string {
return fmt.Sprintf("The selected external IPs for the current Service are violating the following enforced CIDRs: %s", strings.Join(e.cidr, ", "))
}

View File

@@ -58,7 +58,7 @@ func Handler() capsulewebhook.Handler {
return &handler{}
}
func (r *handler) handleService(clt client.Client, decoder *admission.Decoder, ctx context.Context, req admission.Request) admission.Response {
func (r *handler) handleService(ctx context.Context, clt client.Client, decoder *admission.Decoder, req admission.Request) admission.Response {
s := &corev1.Service{}
if err := decoder.Decode(req, s); err != nil {
return admission.Errored(http.StatusBadRequest, err)
@@ -84,10 +84,10 @@ func (r *handler) handleService(clt client.Client, decoder *admission.Decoder, c
}
for _, allowed := range tnt.Spec.ExternalServiceIPs.Allowed {
_, allowedIp, _ := net.ParseCIDR(string(allowed))
for _, externalIp := range s.Spec.ExternalIPs {
IP := net.ParseIP(externalIp)
if allowedIp.Contains(IP) {
_, allowedIP, _ := net.ParseCIDR(string(allowed))
for _, externalIP := range s.Spec.ExternalIPs {
IP := net.ParseIP(externalIP)
if allowedIP.Contains(IP) {
return admission.Allowed("")
}
}
@@ -98,13 +98,13 @@ func (r *handler) handleService(clt client.Client, decoder *admission.Decoder, c
func (r *handler) OnCreate(client client.Client, decoder *admission.Decoder) capsulewebhook.Func {
return func(ctx context.Context, req admission.Request) admission.Response {
return r.handleService(client, decoder, ctx, req)
return r.handleService(ctx, client, decoder, req)
}
}
func (r *handler) OnUpdate(client client.Client, decoder *admission.Decoder) capsulewebhook.Func {
return func(ctx context.Context, req admission.Request) admission.Response {
return r.handleService(client, decoder, ctx, req)
return r.handleService(ctx, client, decoder, req)
}
}

View File

@@ -72,35 +72,35 @@ func (h *handler) OnCreate(clt client.Client, decoder *admission.Decoder) capsul
}
// Validate ingressClasses regexp
if tnt.Spec.IngressClasses != nil && len(tnt.Spec.IngressClasses.AllowedRegex) > 0 {
if _, err := regexp.Compile(tnt.Spec.IngressClasses.AllowedRegex); err != nil {
if tnt.Spec.IngressClasses != nil && len(tnt.Spec.IngressClasses.Regex) > 0 {
if _, err := regexp.Compile(tnt.Spec.IngressClasses.Regex); err != nil {
return admission.Denied("Unable to compile ingressClasses allowedRegex")
}
}
// Validate storageClasses regexp
if tnt.Spec.StorageClasses != nil && len(tnt.Spec.StorageClasses.AllowedRegex) > 0 {
if _, err := regexp.Compile(tnt.Spec.StorageClasses.AllowedRegex); err != nil {
if tnt.Spec.StorageClasses != nil && len(tnt.Spec.StorageClasses.Regex) > 0 {
if _, err := regexp.Compile(tnt.Spec.StorageClasses.Regex); err != nil {
return admission.Denied("Unable to compile storageClasses allowedRegex")
}
}
// Validate containerRegistries regexp
if tnt.Spec.ContainerRegistries != nil && len(tnt.Spec.ContainerRegistries.AllowedRegex) > 0 {
if _, err := regexp.Compile(tnt.Spec.ContainerRegistries.AllowedRegex); err != nil {
if tnt.Spec.ContainerRegistries != nil && len(tnt.Spec.ContainerRegistries.Regex) > 0 {
if _, err := regexp.Compile(tnt.Spec.ContainerRegistries.Regex); err != nil {
return admission.Denied("Unable to compile containerRegistries allowedRegex")
}
}
// Validate ingressHostnames regexp
if tnt.Spec.IngressHostnames != nil && len(tnt.Spec.IngressHostnames.AllowedRegex) > 0 {
if _, err := regexp.Compile(tnt.Spec.IngressHostnames.AllowedRegex); err != nil {
if tnt.Spec.IngressHostnames != nil && len(tnt.Spec.IngressHostnames.Regex) > 0 {
if _, err := regexp.Compile(tnt.Spec.IngressHostnames.Regex); err != nil {
return admission.Denied("Unable to compile ingressHostnames allowedRegex")
}
}
if tnt.Spec.IngressHostnames != nil && len(tnt.Spec.IngressHostnames.Allowed) > 0 {
for _, h := range tnt.Spec.IngressHostnames.Allowed {
if tnt.Spec.IngressHostnames != nil && len(tnt.Spec.IngressHostnames.Exact) > 0 {
for _, h := range tnt.Spec.IngressHostnames.Exact {
tl := &v1alpha1.TenantList{}
err := clt.List(ctx, tl, client.MatchingFieldsSelector{
Selector: fields.OneTermEqualSelector(".spec.ingressHostnames", h),
@@ -113,7 +113,7 @@ func (h *handler) OnCreate(clt client.Client, decoder *admission.Decoder) capsul
}
}
if _, err := regexp.Compile(tnt.Spec.IngressHostnames.AllowedRegex); err != nil {
if _, err := regexp.Compile(tnt.Spec.IngressHostnames.Regex); err != nil {
return admission.Denied("Unable to compile ingressHostnames allowedRegex")
}
}

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package tenant_prefix
package tenantprefix
import (
"context"
@@ -38,7 +38,7 @@ type webhook struct {
handler capsulewebhook.Handler
}
func Webhook(handler capsulewebhook.Handler) *webhook {
func Webhook(handler capsulewebhook.Handler) capsulewebhook.Webhook {
return &webhook{
handler: handler,
}

View File

@@ -16,17 +16,17 @@ limitations under the License.
package main
//GitRepo ...
// GitRepo ...
var GitRepo = ""
//GitTag ...
// GitTag ...
var GitTag = "dev"
//GitCommit ...
// GitCommit ...
var GitCommit = ""
//GitDirty ...
// GitDirty ...
var GitDirty = "dirty"
//BuildTime ...
// BuildTime ...
var BuildTime = ""