mirror of
https://github.com/projectcapsule/capsule.git
synced 2026-02-14 18:09:58 +00:00
Adding linters and aligning code (#169)
* Adding linters and aligning code * Aligning ingressHostnames to AllowedListSpec
This commit is contained in:
committed by
GitHub
parent
89c66de7c6
commit
d2700556dd
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -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
59
.golangci.yml
Normal 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$"
|
||||
2
Makefile
2
Makefile
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
80
api/v1alpha1/allowed_list_test.go
Normal file
80
api/v1alpha1/allowed_list_test.go
Normal 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))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,9 +142,6 @@ spec:
|
||||
type: array
|
||||
allowedRegex:
|
||||
type: string
|
||||
required:
|
||||
- allowed
|
||||
- allowedRegex
|
||||
type: object
|
||||
limitRanges:
|
||||
items:
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
|
||||
@@ -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+`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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{})
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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
28
main.go
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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("")
|
||||
|
||||
}
|
||||
|
||||
@@ -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{}
|
||||
|
||||
@@ -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"
|
||||
@@ -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)
|
||||
@@ -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
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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 ®istryClassForbidden{
|
||||
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
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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, ", "))
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
10
version.go
10
version.go
@@ -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 = ""
|
||||
|
||||
Reference in New Issue
Block a user