mirror of
https://github.com/arangodb/kube-arangodb.git
synced 2024-12-14 11:57:37 +00:00
[Feature] [ML] SA Management (#1525)
This commit is contained in:
parent
a7bd9cb54e
commit
f1038721b7
17 changed files with 1240 additions and 18 deletions
|
@ -34,10 +34,23 @@ rules:
|
||||||
- "get"
|
- "get"
|
||||||
- "list"
|
- "list"
|
||||||
- "watch"
|
- "watch"
|
||||||
|
- apiGroups:
|
||||||
|
- "rbac.authorization.k8s.io"
|
||||||
|
resources:
|
||||||
|
- "roles"
|
||||||
|
- "rolebindings"
|
||||||
|
verbs: ["*"]
|
||||||
|
- apiGroups:
|
||||||
|
- "batch"
|
||||||
|
resources:
|
||||||
|
- "cronjobs"
|
||||||
|
- "jobs"
|
||||||
|
verbs: ["*"]
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
resources:
|
resources:
|
||||||
- "secrets"
|
|
||||||
- "pods"
|
- "pods"
|
||||||
|
- "secrets"
|
||||||
|
- "serviceaccounts"
|
||||||
verbs: ["*"]
|
verbs: ["*"]
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
|
@ -76,7 +76,7 @@ PullSecrets define Secrets used to pull Image from registry
|
||||||
|
|
||||||
### .spec.storage.name
|
### .spec.storage.name
|
||||||
|
|
||||||
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L32)</sup>
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L46)</sup>
|
||||||
|
|
||||||
Name of the object
|
Name of the object
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ Name of the object
|
||||||
|
|
||||||
### .spec.storage.namespace
|
### .spec.storage.namespace
|
||||||
|
|
||||||
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L35)</sup>
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L49)</sup>
|
||||||
|
|
||||||
Namespace of the object. Should default to the namespace of the parent object
|
Namespace of the object. Should default to the namespace of the parent object
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ Namespace of the object. Should default to the namespace of the parent object
|
||||||
|
|
||||||
### .spec.storage.uid
|
### .spec.storage.uid
|
||||||
|
|
||||||
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L38)</sup>
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L52)</sup>
|
||||||
|
|
||||||
UID keeps the information about object UID
|
UID keeps the information about object UID
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ UID keeps the information about object UID
|
||||||
|
|
||||||
### .status.conditions
|
### .status.conditions
|
||||||
|
|
||||||
Type: `api.Conditions` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/ml/v1alpha1/extension_status.go#L28)</sup>
|
Type: `api.Conditions` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/ml/v1alpha1/extension_status.go#L31)</sup>
|
||||||
|
|
||||||
Conditions specific to the entire extension
|
Conditions specific to the entire extension
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ ArangoPipeDatabase define Database name to be used as MetadataService Backend
|
||||||
|
|
||||||
### .status.metadataService.secret.name
|
### .status.metadataService.secret.name
|
||||||
|
|
||||||
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L32)</sup>
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L46)</sup>
|
||||||
|
|
||||||
Name of the object
|
Name of the object
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ Name of the object
|
||||||
|
|
||||||
### .status.metadataService.secret.namespace
|
### .status.metadataService.secret.namespace
|
||||||
|
|
||||||
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L35)</sup>
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L49)</sup>
|
||||||
|
|
||||||
Namespace of the object. Should default to the namespace of the parent object
|
Namespace of the object. Should default to the namespace of the parent object
|
||||||
|
|
||||||
|
@ -140,7 +140,127 @@ Namespace of the object. Should default to the namespace of the parent object
|
||||||
|
|
||||||
### .status.metadataService.secret.uid
|
### .status.metadataService.secret.uid
|
||||||
|
|
||||||
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L38)</sup>
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L52)</sup>
|
||||||
|
|
||||||
|
UID keeps the information about object UID
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .status.serviceAccount.cluster.binding.name
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L46)</sup>
|
||||||
|
|
||||||
|
Name of the object
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .status.serviceAccount.cluster.binding.namespace
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L49)</sup>
|
||||||
|
|
||||||
|
Namespace of the object. Should default to the namespace of the parent object
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .status.serviceAccount.cluster.binding.uid
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L52)</sup>
|
||||||
|
|
||||||
|
UID keeps the information about object UID
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .status.serviceAccount.cluster.role.name
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L46)</sup>
|
||||||
|
|
||||||
|
Name of the object
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .status.serviceAccount.cluster.role.namespace
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L49)</sup>
|
||||||
|
|
||||||
|
Namespace of the object. Should default to the namespace of the parent object
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .status.serviceAccount.cluster.role.uid
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L52)</sup>
|
||||||
|
|
||||||
|
UID keeps the information about object UID
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .status.serviceAccount.name
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L46)</sup>
|
||||||
|
|
||||||
|
Name of the object
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .status.serviceAccount.namespace
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L49)</sup>
|
||||||
|
|
||||||
|
Namespace of the object. Should default to the namespace of the parent object
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .status.serviceAccount.namespaced.binding.name
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L46)</sup>
|
||||||
|
|
||||||
|
Name of the object
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .status.serviceAccount.namespaced.binding.namespace
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L49)</sup>
|
||||||
|
|
||||||
|
Namespace of the object. Should default to the namespace of the parent object
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .status.serviceAccount.namespaced.binding.uid
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L52)</sup>
|
||||||
|
|
||||||
|
UID keeps the information about object UID
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .status.serviceAccount.namespaced.role.name
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L46)</sup>
|
||||||
|
|
||||||
|
Name of the object
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .status.serviceAccount.namespaced.role.namespace
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L49)</sup>
|
||||||
|
|
||||||
|
Namespace of the object. Should default to the namespace of the parent object
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .status.serviceAccount.namespaced.role.uid
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L52)</sup>
|
||||||
|
|
||||||
|
UID keeps the information about object UID
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### .status.serviceAccount.uid
|
||||||
|
|
||||||
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L52)</sup>
|
||||||
|
|
||||||
UID keeps the information about object UID
|
UID keeps the information about object UID
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ Default Value: `false`
|
||||||
|
|
||||||
### .spec.backend.s3.caSecret.name
|
### .spec.backend.s3.caSecret.name
|
||||||
|
|
||||||
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L32)</sup>
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L46)</sup>
|
||||||
|
|
||||||
Name of the object
|
Name of the object
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ Name of the object
|
||||||
|
|
||||||
### .spec.backend.s3.caSecret.namespace
|
### .spec.backend.s3.caSecret.namespace
|
||||||
|
|
||||||
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L35)</sup>
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L49)</sup>
|
||||||
|
|
||||||
Namespace of the object. Should default to the namespace of the parent object
|
Namespace of the object. Should default to the namespace of the parent object
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ Namespace of the object. Should default to the namespace of the parent object
|
||||||
|
|
||||||
### .spec.backend.s3.caSecret.uid
|
### .spec.backend.s3.caSecret.uid
|
||||||
|
|
||||||
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L38)</sup>
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L52)</sup>
|
||||||
|
|
||||||
UID keeps the information about object UID
|
UID keeps the information about object UID
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ UID keeps the information about object UID
|
||||||
|
|
||||||
### .spec.backend.s3.credentialsSecret.name
|
### .spec.backend.s3.credentialsSecret.name
|
||||||
|
|
||||||
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L32)</sup>
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L46)</sup>
|
||||||
|
|
||||||
Name of the object
|
Name of the object
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ Name of the object
|
||||||
|
|
||||||
### .spec.backend.s3.credentialsSecret.namespace
|
### .spec.backend.s3.credentialsSecret.namespace
|
||||||
|
|
||||||
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L35)</sup>
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L49)</sup>
|
||||||
|
|
||||||
Namespace of the object. Should default to the namespace of the parent object
|
Namespace of the object. Should default to the namespace of the parent object
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ Namespace of the object. Should default to the namespace of the parent object
|
||||||
|
|
||||||
### .spec.backend.s3.credentialsSecret.uid
|
### .spec.backend.s3.credentialsSecret.uid
|
||||||
|
|
||||||
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L38)</sup>
|
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.35/pkg/apis/shared/v1/object.go#L52)</sup>
|
||||||
|
|
||||||
UID keeps the information about object UID
|
UID keeps the information about object UID
|
||||||
|
|
||||||
|
|
|
@ -27,5 +27,6 @@ const (
|
||||||
ExtensionDeploymentFoundCondition api.ConditionType = "DeploymentFound"
|
ExtensionDeploymentFoundCondition api.ConditionType = "DeploymentFound"
|
||||||
ExtensionBootstrapCompletedCondition api.ConditionType = "BootstrapCompleted"
|
ExtensionBootstrapCompletedCondition api.ConditionType = "BootstrapCompleted"
|
||||||
ExtensionMetadataServiceValidCondition api.ConditionType = "MetadataServiceValid"
|
ExtensionMetadataServiceValidCondition api.ConditionType = "MetadataServiceValid"
|
||||||
|
ExtensionServiceAccountReadyCondition api.ConditionType = "ServiceAccountReady"
|
||||||
LicenseValidCondition api.ConditionType = "LicenseValid"
|
LicenseValidCondition api.ConditionType = "LicenseValid"
|
||||||
)
|
)
|
||||||
|
|
|
@ -20,7 +20,10 @@
|
||||||
|
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
import (
|
||||||
|
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
|
||||||
|
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1"
|
||||||
|
)
|
||||||
|
|
||||||
type ArangoMLExtensionStatus struct {
|
type ArangoMLExtensionStatus struct {
|
||||||
// Conditions specific to the entire extension
|
// Conditions specific to the entire extension
|
||||||
|
@ -29,4 +32,7 @@ type ArangoMLExtensionStatus struct {
|
||||||
|
|
||||||
// MetadataService keeps the MetadataService configuration
|
// MetadataService keeps the MetadataService configuration
|
||||||
MetadataService *ArangoMLExtensionStatusMetadataService `json:"metadataService,omitempty"`
|
MetadataService *ArangoMLExtensionStatusMetadataService `json:"metadataService,omitempty"`
|
||||||
|
|
||||||
|
// ServiceAccount keeps the information about ServiceAccount
|
||||||
|
ServiceAccount *shared.ServiceAccount `json:"serviceAccount,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
5
pkg/apis/ml/v1alpha1/zz_generated.deepcopy.go
generated
5
pkg/apis/ml/v1alpha1/zz_generated.deepcopy.go
generated
|
@ -418,6 +418,11 @@ func (in *ArangoMLExtensionStatus) DeepCopyInto(out *ArangoMLExtensionStatus) {
|
||||||
*out = new(ArangoMLExtensionStatusMetadataService)
|
*out = new(ArangoMLExtensionStatusMetadataService)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
|
if in.ServiceAccount != nil {
|
||||||
|
in, out := &in.ServiceAccount, &out.ServiceAccount
|
||||||
|
*out = new(sharedv1.ServiceAccount)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,22 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
"github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
"github.com/arangodb/kube-arangodb/pkg/apis/shared"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func NewObject(object meta.Object) Object {
|
||||||
|
var n Object
|
||||||
|
|
||||||
|
n.Name = object.GetName()
|
||||||
|
n.UID = util.NewType(object.GetUID())
|
||||||
|
|
||||||
|
if ns := object.GetNamespace(); ns != "" {
|
||||||
|
n.Namespace = util.NewType(ns)
|
||||||
|
}
|
||||||
|
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
type Object struct {
|
type Object struct {
|
||||||
// Name of the object
|
// Name of the object
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
@ -71,6 +85,30 @@ func (o *Object) GetUID() types.UID {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Object) Equals(obj meta.Object) bool {
|
||||||
|
if o == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.Name != obj.GetName() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if n := o.Namespace; n != nil {
|
||||||
|
if *n != obj.GetNamespace() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if n := o.UID; n != nil {
|
||||||
|
if *n != obj.GetUID() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (o *Object) Validate() error {
|
func (o *Object) Validate() error {
|
||||||
if o == nil {
|
if o == nil {
|
||||||
o = &Object{}
|
o = &Object{}
|
||||||
|
|
40
pkg/apis/shared/v1/service_account.go
Normal file
40
pkg/apis/shared/v1/service_account.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
//
|
||||||
|
// DISCLAIMER
|
||||||
|
//
|
||||||
|
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||||
|
//
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
type ServiceAccount struct {
|
||||||
|
// Object keeps the reference to the ServiceAccount
|
||||||
|
*Object `json:",inline"`
|
||||||
|
|
||||||
|
// Namespaced keeps the reference to core.Role objects
|
||||||
|
Namespaced *ServiceAccountRole `json:"namespaced,omitempty"`
|
||||||
|
|
||||||
|
// Cluster keeps the reference to core.ClusterRole objects
|
||||||
|
Cluster *ServiceAccountRole `json:"cluster,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceAccountRole struct {
|
||||||
|
// Role keeps the reference to the Kubernetes Role
|
||||||
|
Role *Object `json:"role,omitempty"`
|
||||||
|
|
||||||
|
// Binding keeps the reference to the Kubernetes Binding
|
||||||
|
Binding *Object `json:"binding,omitempty"`
|
||||||
|
}
|
57
pkg/apis/shared/v1/zz_generated.deepcopy.go
generated
57
pkg/apis/shared/v1/zz_generated.deepcopy.go
generated
|
@ -127,3 +127,60 @@ func (in *Resources) DeepCopy() *Resources {
|
||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ServiceAccount) DeepCopyInto(out *ServiceAccount) {
|
||||||
|
*out = *in
|
||||||
|
if in.Object != nil {
|
||||||
|
in, out := &in.Object, &out.Object
|
||||||
|
*out = new(Object)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
if in.Namespaced != nil {
|
||||||
|
in, out := &in.Namespaced, &out.Namespaced
|
||||||
|
*out = new(ServiceAccountRole)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
if in.Cluster != nil {
|
||||||
|
in, out := &in.Cluster, &out.Cluster
|
||||||
|
*out = new(ServiceAccountRole)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceAccount.
|
||||||
|
func (in *ServiceAccount) DeepCopy() *ServiceAccount {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ServiceAccount)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ServiceAccountRole) DeepCopyInto(out *ServiceAccountRole) {
|
||||||
|
*out = *in
|
||||||
|
if in.Role != nil {
|
||||||
|
in, out := &in.Role, &out.Role
|
||||||
|
*out = new(Object)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
if in.Binding != nil {
|
||||||
|
in, out := &in.Binding, &out.Binding
|
||||||
|
*out = new(Object)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceAccountRole.
|
||||||
|
func (in *ServiceAccountRole) DeepCopy() *ServiceAccountRole {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ServiceAccountRole)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,10 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/deployment/patch"
|
||||||
"github.com/arangodb/kube-arangodb/pkg/util/globals"
|
"github.com/arangodb/kube-arangodb/pkg/util/globals"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,3 +52,25 @@ func WithContextTimeoutP2A2[P1, P2, A1, A2 interface{}](ctx context.Context, tim
|
||||||
|
|
||||||
return f(nCtx, a1, a2)
|
return f(nCtx, a1, a2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PatchInterface[P1 meta.Object] interface {
|
||||||
|
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts meta.PatchOptions, subresources ...string) (P1, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithKubernetesPatch[P1 meta.Object](ctx context.Context, obj string, client PatchInterface[P1], p ...patch.Item) (P1, error) {
|
||||||
|
if len(p) == 0 {
|
||||||
|
return Default[P1](), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
parser := patch.Patch(p)
|
||||||
|
|
||||||
|
data, err := parser.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return Default[P1](), err
|
||||||
|
}
|
||||||
|
|
||||||
|
nCtx, c := context.WithTimeout(ctx, globals.GetGlobals().Timeouts().Kubernetes().Get())
|
||||||
|
defer c()
|
||||||
|
|
||||||
|
return client.Patch(nCtx, obj, types.JSONPatchType, data, meta.PatchOptions{})
|
||||||
|
}
|
||||||
|
|
394
pkg/util/k8sutil/helpers/service_account.go
Normal file
394
pkg/util/k8sutil/helpers/service_account.go
Normal file
|
@ -0,0 +1,394 @@
|
||||||
|
//
|
||||||
|
// DISCLAIMER
|
||||||
|
//
|
||||||
|
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||||
|
//
|
||||||
|
|
||||||
|
package helpers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/dchest/uniuri"
|
||||||
|
core "k8s.io/api/core/v1"
|
||||||
|
rbac "k8s.io/api/rbac/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/equality"
|
||||||
|
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/client-go/kubernetes"
|
||||||
|
|
||||||
|
sharedApi "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/deployment/patch"
|
||||||
|
operator "github.com/arangodb/kube-arangodb/pkg/operatorV2"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/kerrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func EnsureServiceAccount(ctx context.Context, client kubernetes.Interface, owner meta.OwnerReference, obj *sharedApi.ServiceAccount, name, namespace string, role, clusterRole []rbac.PolicyRule) (bool, error) {
|
||||||
|
if obj == nil {
|
||||||
|
return false, errors.Newf("Object reference cannot be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if secret exists
|
||||||
|
if obj.Object != nil {
|
||||||
|
if sa, err := util.WithKubernetesContextTimeoutP2A2(ctx, client.CoreV1().ServiceAccounts(namespace).Get, obj.Object.GetName(), meta.GetOptions{}); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Object = nil
|
||||||
|
|
||||||
|
return true, operator.Reconcile("SA is missing")
|
||||||
|
} else {
|
||||||
|
if !obj.Object.Equals(sa) {
|
||||||
|
// Invalid object
|
||||||
|
if err := util.WithKubernetesContextTimeoutP1A2(ctx, client.CoreV1().ServiceAccounts(namespace).Delete, name, meta.DeleteOptions{
|
||||||
|
Preconditions: meta.NewUIDPreconditions(string(obj.Object.GetUID())),
|
||||||
|
}); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) && !kerrors.IsConflict(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Object = nil
|
||||||
|
|
||||||
|
return true, operator.Reconcile("Removing SA")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if obj.Object == nil {
|
||||||
|
if sa, err := util.WithKubernetesContextTimeoutP2A2(ctx, client.CoreV1().ServiceAccounts(namespace).Create, &core.ServiceAccount{
|
||||||
|
ObjectMeta: meta.ObjectMeta{
|
||||||
|
OwnerReferences: []meta.OwnerReference{owner},
|
||||||
|
|
||||||
|
Name: fmt.Sprintf("%s-%s", name, strings.ToLower(uniuri.NewLen(6))),
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
}, meta.CreateOptions{}); err != nil {
|
||||||
|
return false, err
|
||||||
|
} else {
|
||||||
|
obj.Object = util.NewType(sharedApi.NewObject(sa))
|
||||||
|
return true, operator.Reconcile("Created SA")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ROLE
|
||||||
|
|
||||||
|
if len(role) == 0 {
|
||||||
|
// Ensure role and binding is missing
|
||||||
|
if obj.Namespaced != nil {
|
||||||
|
if obj.Namespaced.Binding != nil {
|
||||||
|
// Remove binding
|
||||||
|
if err := util.WithKubernetesContextTimeoutP1A2(ctx, client.RbacV1().RoleBindings(namespace).Delete, obj.Namespaced.Binding.GetName(), meta.DeleteOptions{
|
||||||
|
Preconditions: meta.NewUIDPreconditions(string(obj.Namespaced.Binding.GetUID())),
|
||||||
|
}); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) && !kerrors.IsConflict(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Namespaced.Binding = nil
|
||||||
|
return true, operator.Reconcile("Removing RoleBinding")
|
||||||
|
}
|
||||||
|
|
||||||
|
if obj.Namespaced.Role != nil {
|
||||||
|
// Remove binding
|
||||||
|
if err := util.WithKubernetesContextTimeoutP1A2(ctx, client.RbacV1().Roles(namespace).Delete, obj.Namespaced.Role.GetName(), meta.DeleteOptions{
|
||||||
|
Preconditions: meta.NewUIDPreconditions(string(obj.Namespaced.Role.GetUID())),
|
||||||
|
}); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) && !kerrors.IsConflict(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Namespaced.Role = nil
|
||||||
|
return true, operator.Reconcile("Removing Role")
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Namespaced = nil
|
||||||
|
return true, operator.Reconcile("Removing Namespaced Handler")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Create if required
|
||||||
|
if obj.Namespaced == nil || obj.Namespaced.Role == nil {
|
||||||
|
if r, err := util.WithKubernetesContextTimeoutP2A2(ctx, client.RbacV1().Roles(namespace).Create, &rbac.Role{
|
||||||
|
ObjectMeta: meta.ObjectMeta{
|
||||||
|
OwnerReferences: []meta.OwnerReference{owner},
|
||||||
|
|
||||||
|
Name: fmt.Sprintf("%s-%s", name, strings.ToLower(uniuri.NewLen(6))),
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
Rules: role,
|
||||||
|
}, meta.CreateOptions{}); err != nil {
|
||||||
|
return false, err
|
||||||
|
} else {
|
||||||
|
if obj.Namespaced == nil {
|
||||||
|
obj.Namespaced = &sharedApi.ServiceAccountRole{}
|
||||||
|
}
|
||||||
|
obj.Namespaced.Role = util.NewType(sharedApi.NewObject(r))
|
||||||
|
return true, operator.Reconcile("Created Role")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if obj.Namespaced == nil || obj.Namespaced.Binding == nil {
|
||||||
|
if r, err := util.WithKubernetesContextTimeoutP2A2(ctx, client.RbacV1().RoleBindings(namespace).Create, &rbac.RoleBinding{
|
||||||
|
ObjectMeta: meta.ObjectMeta{
|
||||||
|
OwnerReferences: []meta.OwnerReference{owner},
|
||||||
|
|
||||||
|
Name: fmt.Sprintf("%s-%s", name, strings.ToLower(uniuri.NewLen(6))),
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
RoleRef: rbac.RoleRef{
|
||||||
|
APIGroup: "rbac.authorization.k8s.io",
|
||||||
|
Kind: "Role",
|
||||||
|
Name: obj.Namespaced.Role.GetName(),
|
||||||
|
},
|
||||||
|
Subjects: []rbac.Subject{
|
||||||
|
{
|
||||||
|
Kind: "ServiceAccount",
|
||||||
|
APIGroup: "",
|
||||||
|
Name: obj.Object.GetName(),
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, meta.CreateOptions{}); err != nil {
|
||||||
|
return false, err
|
||||||
|
} else {
|
||||||
|
if obj.Namespaced == nil {
|
||||||
|
obj.Namespaced = &sharedApi.ServiceAccountRole{}
|
||||||
|
}
|
||||||
|
obj.Namespaced.Binding = util.NewType(sharedApi.NewObject(r))
|
||||||
|
return true, operator.Reconcile("Created RoleBinding")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Both object are nil, lets validate aspects
|
||||||
|
if r, err := util.WithKubernetesContextTimeoutP2A2(ctx, client.RbacV1().Roles(namespace).Get, obj.Namespaced.Role.GetName(), meta.GetOptions{}); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Namespaced.Role = nil
|
||||||
|
return true, operator.Reconcile("Missing Role")
|
||||||
|
} else {
|
||||||
|
if !obj.Namespaced.Role.Equals(r) {
|
||||||
|
if err := util.WithKubernetesContextTimeoutP1A2(ctx, client.RbacV1().Roles(namespace).Delete, obj.Namespaced.Role.GetName(), meta.DeleteOptions{
|
||||||
|
Preconditions: meta.NewUIDPreconditions(string(obj.Namespaced.Role.GetUID())),
|
||||||
|
}); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) && !kerrors.IsConflict(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Namespaced.Role = nil
|
||||||
|
return true, operator.Reconcile("Recreate Role")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !equality.Semantic.DeepEqual(r.Rules, role) {
|
||||||
|
// There is change in the roles
|
||||||
|
if _, err := util.WithKubernetesPatch[*rbac.Role](ctx, obj.Namespaced.Role.GetName(), client.RbacV1().Roles(namespace), patch.ItemReplace(patch.NewPath("rules"), role)); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, operator.Reconcile("Refresh Role")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r, err := util.WithKubernetesContextTimeoutP2A2(ctx, client.RbacV1().RoleBindings(namespace).Get, obj.Namespaced.Binding.GetName(), meta.GetOptions{}); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Namespaced.Role = nil
|
||||||
|
return true, operator.Reconcile("Missing RoleBinding")
|
||||||
|
} else {
|
||||||
|
if !obj.Namespaced.Binding.Equals(r) {
|
||||||
|
if err := util.WithKubernetesContextTimeoutP1A2(ctx, client.RbacV1().RoleBindings(namespace).Delete, obj.Namespaced.Binding.GetName(), meta.DeleteOptions{
|
||||||
|
Preconditions: meta.NewUIDPreconditions(string(obj.Namespaced.Role.GetUID())),
|
||||||
|
}); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) && !kerrors.IsConflict(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Namespaced.Role = nil
|
||||||
|
return true, operator.Reconcile("Recreate RoleBinding")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CLUSTER ROLE
|
||||||
|
|
||||||
|
if len(clusterRole) == 0 {
|
||||||
|
// Ensure role and binding is missing
|
||||||
|
if obj.Cluster != nil {
|
||||||
|
if obj.Cluster.Binding != nil {
|
||||||
|
// Remove binding
|
||||||
|
if err := util.WithKubernetesContextTimeoutP1A2(ctx, client.RbacV1().ClusterRoleBindings().Delete, obj.Cluster.Binding.GetName(), meta.DeleteOptions{
|
||||||
|
Preconditions: meta.NewUIDPreconditions(string(obj.Cluster.Binding.GetUID())),
|
||||||
|
}); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) && !kerrors.IsConflict(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Cluster.Binding = nil
|
||||||
|
return true, operator.Reconcile("Removing ClusterRoleBinding")
|
||||||
|
}
|
||||||
|
|
||||||
|
if obj.Cluster.Role != nil {
|
||||||
|
// Remove binding
|
||||||
|
if err := util.WithKubernetesContextTimeoutP1A2(ctx, client.RbacV1().ClusterRoles().Delete, obj.Cluster.Role.GetName(), meta.DeleteOptions{
|
||||||
|
Preconditions: meta.NewUIDPreconditions(string(obj.Cluster.Role.GetUID())),
|
||||||
|
}); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) && !kerrors.IsConflict(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Cluster.Role = nil
|
||||||
|
return true, operator.Reconcile("Removing ClusterRole")
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Cluster = nil
|
||||||
|
return true, operator.Reconcile("Removing Cluster Handler")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Create if required
|
||||||
|
if obj.Cluster == nil || obj.Cluster.Role == nil {
|
||||||
|
if r, err := util.WithKubernetesContextTimeoutP2A2(ctx, client.RbacV1().ClusterRoles().Create, &rbac.ClusterRole{
|
||||||
|
ObjectMeta: meta.ObjectMeta{
|
||||||
|
OwnerReferences: []meta.OwnerReference{owner},
|
||||||
|
|
||||||
|
Name: fmt.Sprintf("%s-%s", name, strings.ToLower(uniuri.NewLen(6))),
|
||||||
|
},
|
||||||
|
Rules: clusterRole,
|
||||||
|
}, meta.CreateOptions{}); err != nil {
|
||||||
|
return false, err
|
||||||
|
} else {
|
||||||
|
if obj.Cluster == nil {
|
||||||
|
obj.Cluster = &sharedApi.ServiceAccountRole{}
|
||||||
|
}
|
||||||
|
obj.Cluster.Role = util.NewType(sharedApi.NewObject(r))
|
||||||
|
return true, operator.Reconcile("Created ClusterRole")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if obj.Cluster == nil || obj.Cluster.Binding == nil {
|
||||||
|
if r, err := util.WithKubernetesContextTimeoutP2A2(ctx, client.RbacV1().ClusterRoleBindings().Create, &rbac.ClusterRoleBinding{
|
||||||
|
ObjectMeta: meta.ObjectMeta{
|
||||||
|
OwnerReferences: []meta.OwnerReference{owner},
|
||||||
|
|
||||||
|
Name: fmt.Sprintf("%s-%s", name, strings.ToLower(uniuri.NewLen(6))),
|
||||||
|
},
|
||||||
|
RoleRef: rbac.RoleRef{
|
||||||
|
APIGroup: "rbac.authorization.k8s.io",
|
||||||
|
Kind: "ClusterRole",
|
||||||
|
Name: obj.Cluster.Role.GetName(),
|
||||||
|
},
|
||||||
|
Subjects: []rbac.Subject{
|
||||||
|
{
|
||||||
|
Kind: "ServiceAccount",
|
||||||
|
APIGroup: "",
|
||||||
|
Name: obj.Object.GetName(),
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, meta.CreateOptions{}); err != nil {
|
||||||
|
return false, err
|
||||||
|
} else {
|
||||||
|
if obj.Cluster == nil {
|
||||||
|
obj.Cluster = &sharedApi.ServiceAccountRole{}
|
||||||
|
}
|
||||||
|
obj.Cluster.Binding = util.NewType(sharedApi.NewObject(r))
|
||||||
|
return true, operator.Reconcile("Created ClusterRoleBinding")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Both object are nil, lets validate aspects
|
||||||
|
if r, err := util.WithKubernetesContextTimeoutP2A2(ctx, client.RbacV1().ClusterRoles().Get, obj.Cluster.Role.GetName(), meta.GetOptions{}); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Cluster.Role = nil
|
||||||
|
return true, operator.Reconcile("Missing ClusterRole")
|
||||||
|
} else {
|
||||||
|
if !obj.Cluster.Role.Equals(r) {
|
||||||
|
if err := util.WithKubernetesContextTimeoutP1A2(ctx, client.RbacV1().ClusterRoles().Delete, obj.Cluster.Role.GetName(), meta.DeleteOptions{
|
||||||
|
Preconditions: meta.NewUIDPreconditions(string(obj.Cluster.Role.GetUID())),
|
||||||
|
}); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) && !kerrors.IsConflict(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Cluster.Role = nil
|
||||||
|
return true, operator.Reconcile("Recreate ClusterRole")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !equality.Semantic.DeepEqual(r.Rules, clusterRole) {
|
||||||
|
// There is change in the roles
|
||||||
|
if _, err := util.WithKubernetesPatch[*rbac.ClusterRole](ctx, obj.Cluster.Role.GetName(), client.RbacV1().ClusterRoles(), patch.ItemReplace(patch.NewPath("rules"), clusterRole)); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, operator.Reconcile("Refresh ClusterRole")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r, err := util.WithKubernetesContextTimeoutP2A2(ctx, client.RbacV1().ClusterRoleBindings().Get, obj.Cluster.Binding.GetName(), meta.GetOptions{}); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Cluster.Role = nil
|
||||||
|
return true, operator.Reconcile("Missing ClusterRoleBinding")
|
||||||
|
} else {
|
||||||
|
if !obj.Cluster.Binding.Equals(r) {
|
||||||
|
if err := util.WithKubernetesContextTimeoutP1A2(ctx, client.RbacV1().ClusterRoleBindings().Delete, obj.Cluster.Binding.GetName(), meta.DeleteOptions{
|
||||||
|
Preconditions: meta.NewUIDPreconditions(string(obj.Cluster.Role.GetUID())),
|
||||||
|
}); err != nil {
|
||||||
|
if !kerrors.IsNotFound(err) && !kerrors.IsConflict(err) {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.Cluster.Role = nil
|
||||||
|
return true, operator.Reconcile("Recreate ClusterRoleBinding")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func AppendServiceAccount(obj *sharedApi.ServiceAccount, spec *core.PodTemplateSpec) {
|
||||||
|
if obj == nil || obj.Object == nil || spec == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
spec.Spec.ServiceAccountName = obj.Object.GetName()
|
||||||
|
spec.Spec.AutomountServiceAccountToken = util.NewType(true)
|
||||||
|
}
|
298
pkg/util/k8sutil/helpers/service_account_test.go
Normal file
298
pkg/util/k8sutil/helpers/service_account_test.go
Normal file
|
@ -0,0 +1,298 @@
|
||||||
|
//
|
||||||
|
// DISCLAIMER
|
||||||
|
//
|
||||||
|
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||||
|
//
|
||||||
|
|
||||||
|
package helpers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
rbac "k8s.io/api/rbac/v1"
|
||||||
|
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
|
|
||||||
|
sharedApi "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1"
|
||||||
|
"github.com/arangodb/kube-arangodb/pkg/util/tests"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_ServiceAccount_Roles(t *testing.T) {
|
||||||
|
k := fake.NewSimpleClientset()
|
||||||
|
|
||||||
|
var obj sharedApi.ServiceAccount
|
||||||
|
|
||||||
|
t.Run("PreCheck", func(t *testing.T) {
|
||||||
|
require.Nil(t, obj.Object)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Create SA without any roles", func(t *testing.T) {
|
||||||
|
require.NoError(t, tests.HandleFunc(func(ctx context.Context) (bool, error) {
|
||||||
|
return EnsureServiceAccount(ctx, k, meta.OwnerReference{}, &obj, "test", tests.FakeNamespace, nil, nil)
|
||||||
|
}))
|
||||||
|
|
||||||
|
require.NotNil(t, obj.Object)
|
||||||
|
require.Nil(t, obj.Namespaced)
|
||||||
|
require.Nil(t, obj.Cluster)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Create SA with roles", func(t *testing.T) {
|
||||||
|
require.NoError(t, tests.HandleFunc(func(ctx context.Context) (bool, error) {
|
||||||
|
return EnsureServiceAccount(ctx, k, meta.OwnerReference{}, &obj, "test", tests.FakeNamespace, []rbac.PolicyRule{
|
||||||
|
{
|
||||||
|
Resources: []string{"*"},
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
}))
|
||||||
|
|
||||||
|
require.NotNil(t, obj.Object)
|
||||||
|
require.NotNil(t, obj.Namespaced)
|
||||||
|
require.NotNil(t, obj.Namespaced.Binding)
|
||||||
|
require.NotNil(t, obj.Namespaced.Role)
|
||||||
|
require.Nil(t, obj.Cluster)
|
||||||
|
|
||||||
|
sa := tests.NewMetaObject[*rbac.Role](t, tests.FakeNamespace, obj.Namespaced.Role.GetName())
|
||||||
|
|
||||||
|
tests.RefreshObjects(t, k, nil, &sa)
|
||||||
|
|
||||||
|
require.Len(t, sa.Rules, 1)
|
||||||
|
require.Len(t, sa.Rules[0].Resources, 1)
|
||||||
|
require.Equal(t, sa.Rules[0].Resources[0], "*")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Create SA with updated roles", func(t *testing.T) {
|
||||||
|
require.NoError(t, tests.HandleFunc(func(ctx context.Context) (bool, error) {
|
||||||
|
return EnsureServiceAccount(ctx, k, meta.OwnerReference{}, &obj, "test", tests.FakeNamespace, []rbac.PolicyRule{
|
||||||
|
{
|
||||||
|
Resources: []string{"DATA"},
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
}))
|
||||||
|
|
||||||
|
require.NotNil(t, obj.Object)
|
||||||
|
require.NotNil(t, obj.Namespaced)
|
||||||
|
require.NotNil(t, obj.Namespaced.Binding)
|
||||||
|
require.NotNil(t, obj.Namespaced.Role)
|
||||||
|
require.Nil(t, obj.Cluster)
|
||||||
|
|
||||||
|
sa := tests.NewMetaObject[*rbac.Role](t, tests.FakeNamespace, obj.Namespaced.Role.GetName())
|
||||||
|
|
||||||
|
tests.RefreshObjects(t, k, nil, &sa)
|
||||||
|
|
||||||
|
require.Len(t, sa.Rules, 1)
|
||||||
|
require.Len(t, sa.Rules[0].Resources, 1)
|
||||||
|
require.Equal(t, sa.Rules[0].Resources[0], "DATA")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Create SA with multiple roles", func(t *testing.T) {
|
||||||
|
require.NoError(t, tests.HandleFunc(func(ctx context.Context) (bool, error) {
|
||||||
|
return EnsureServiceAccount(ctx, k, meta.OwnerReference{}, &obj, "test", tests.FakeNamespace, []rbac.PolicyRule{
|
||||||
|
{
|
||||||
|
Resources: []string{"DATA"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Resources: []string{"*"},
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
}))
|
||||||
|
|
||||||
|
require.NotNil(t, obj.Object)
|
||||||
|
require.NotNil(t, obj.Namespaced)
|
||||||
|
require.NotNil(t, obj.Namespaced.Binding)
|
||||||
|
require.NotNil(t, obj.Namespaced.Role)
|
||||||
|
require.Nil(t, obj.Cluster)
|
||||||
|
|
||||||
|
sa := tests.NewMetaObject[*rbac.Role](t, tests.FakeNamespace, obj.Namespaced.Role.GetName())
|
||||||
|
|
||||||
|
tests.RefreshObjects(t, k, nil, &sa)
|
||||||
|
|
||||||
|
require.Len(t, sa.Rules, 2)
|
||||||
|
require.Len(t, sa.Rules[0].Resources, 1)
|
||||||
|
require.Equal(t, sa.Rules[0].Resources[0], "DATA")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Create SA with updated multiple roles", func(t *testing.T) {
|
||||||
|
require.NoError(t, tests.HandleFunc(func(ctx context.Context) (bool, error) {
|
||||||
|
return EnsureServiceAccount(ctx, k, meta.OwnerReference{}, &obj, "test", tests.FakeNamespace, []rbac.PolicyRule{
|
||||||
|
{
|
||||||
|
Resources: []string{"*"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Resources: []string{"DATA"},
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
}))
|
||||||
|
|
||||||
|
require.NotNil(t, obj.Object)
|
||||||
|
require.NotNil(t, obj.Namespaced)
|
||||||
|
require.NotNil(t, obj.Namespaced.Binding)
|
||||||
|
require.NotNil(t, obj.Namespaced.Role)
|
||||||
|
require.Nil(t, obj.Cluster)
|
||||||
|
|
||||||
|
sa := tests.NewMetaObject[*rbac.Role](t, tests.FakeNamespace, obj.Namespaced.Role.GetName())
|
||||||
|
|
||||||
|
tests.RefreshObjects(t, k, nil, &sa)
|
||||||
|
|
||||||
|
require.Len(t, sa.Rules, 2)
|
||||||
|
require.Len(t, sa.Rules[0].Resources, 1)
|
||||||
|
require.Equal(t, sa.Rules[0].Resources[0], "*")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Remove SA Roles", func(t *testing.T) {
|
||||||
|
require.NoError(t, tests.HandleFunc(func(ctx context.Context) (bool, error) {
|
||||||
|
return EnsureServiceAccount(ctx, k, meta.OwnerReference{}, &obj, "test", tests.FakeNamespace, nil, nil)
|
||||||
|
}))
|
||||||
|
|
||||||
|
require.NotNil(t, obj.Object)
|
||||||
|
require.Nil(t, obj.Namespaced)
|
||||||
|
require.Nil(t, obj.Cluster)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_ServiceAccount_ClusterRoles(t *testing.T) {
|
||||||
|
k := fake.NewSimpleClientset()
|
||||||
|
|
||||||
|
var obj sharedApi.ServiceAccount
|
||||||
|
|
||||||
|
t.Run("PreCheck", func(t *testing.T) {
|
||||||
|
require.Nil(t, obj.Object)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Create SA without any roles", func(t *testing.T) {
|
||||||
|
require.NoError(t, tests.HandleFunc(func(ctx context.Context) (bool, error) {
|
||||||
|
return EnsureServiceAccount(ctx, k, meta.OwnerReference{}, &obj, "test", tests.FakeNamespace, nil, nil)
|
||||||
|
}))
|
||||||
|
|
||||||
|
require.NotNil(t, obj.Object)
|
||||||
|
require.Nil(t, obj.Cluster)
|
||||||
|
require.Nil(t, obj.Namespaced)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Create SA with roles", func(t *testing.T) {
|
||||||
|
require.NoError(t, tests.HandleFunc(func(ctx context.Context) (bool, error) {
|
||||||
|
return EnsureServiceAccount(ctx, k, meta.OwnerReference{}, &obj, "test", tests.FakeNamespace, nil, []rbac.PolicyRule{
|
||||||
|
{
|
||||||
|
Resources: []string{"*"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
|
||||||
|
require.NotNil(t, obj.Object)
|
||||||
|
require.NotNil(t, obj.Cluster)
|
||||||
|
require.NotNil(t, obj.Cluster.Binding)
|
||||||
|
require.NotNil(t, obj.Cluster.Role)
|
||||||
|
require.Nil(t, obj.Namespaced)
|
||||||
|
|
||||||
|
sa := tests.NewMetaObject[*rbac.ClusterRole](t, tests.FakeNamespace, obj.Cluster.Role.GetName())
|
||||||
|
|
||||||
|
tests.RefreshObjects(t, k, nil, &sa)
|
||||||
|
|
||||||
|
require.Len(t, sa.Rules, 1)
|
||||||
|
require.Len(t, sa.Rules[0].Resources, 1)
|
||||||
|
require.Equal(t, sa.Rules[0].Resources[0], "*")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Create SA with updated roles", func(t *testing.T) {
|
||||||
|
require.NoError(t, tests.HandleFunc(func(ctx context.Context) (bool, error) {
|
||||||
|
return EnsureServiceAccount(ctx, k, meta.OwnerReference{}, &obj, "test", tests.FakeNamespace, nil, []rbac.PolicyRule{
|
||||||
|
{
|
||||||
|
Resources: []string{"DATA"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
|
||||||
|
require.NotNil(t, obj.Object)
|
||||||
|
require.NotNil(t, obj.Cluster)
|
||||||
|
require.NotNil(t, obj.Cluster.Binding)
|
||||||
|
require.NotNil(t, obj.Cluster.Role)
|
||||||
|
require.Nil(t, obj.Namespaced)
|
||||||
|
|
||||||
|
sa := tests.NewMetaObject[*rbac.ClusterRole](t, tests.FakeNamespace, obj.Cluster.Role.GetName())
|
||||||
|
|
||||||
|
tests.RefreshObjects(t, k, nil, &sa)
|
||||||
|
|
||||||
|
require.Len(t, sa.Rules, 1)
|
||||||
|
require.Len(t, sa.Rules[0].Resources, 1)
|
||||||
|
require.Equal(t, sa.Rules[0].Resources[0], "DATA")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Create SA with multiple roles", func(t *testing.T) {
|
||||||
|
require.NoError(t, tests.HandleFunc(func(ctx context.Context) (bool, error) {
|
||||||
|
return EnsureServiceAccount(ctx, k, meta.OwnerReference{}, &obj, "test", tests.FakeNamespace, nil, []rbac.PolicyRule{
|
||||||
|
{
|
||||||
|
Resources: []string{"DATA"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Resources: []string{"*"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
|
||||||
|
require.NotNil(t, obj.Object)
|
||||||
|
require.NotNil(t, obj.Cluster)
|
||||||
|
require.NotNil(t, obj.Cluster.Binding)
|
||||||
|
require.NotNil(t, obj.Cluster.Role)
|
||||||
|
require.Nil(t, obj.Namespaced)
|
||||||
|
|
||||||
|
sa := tests.NewMetaObject[*rbac.ClusterRole](t, tests.FakeNamespace, obj.Cluster.Role.GetName())
|
||||||
|
|
||||||
|
tests.RefreshObjects(t, k, nil, &sa)
|
||||||
|
|
||||||
|
require.Len(t, sa.Rules, 2)
|
||||||
|
require.Len(t, sa.Rules[0].Resources, 1)
|
||||||
|
require.Equal(t, sa.Rules[0].Resources[0], "DATA")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Create SA with updated multiple roles", func(t *testing.T) {
|
||||||
|
require.NoError(t, tests.HandleFunc(func(ctx context.Context) (bool, error) {
|
||||||
|
return EnsureServiceAccount(ctx, k, meta.OwnerReference{}, &obj, "test", tests.FakeNamespace, nil, []rbac.PolicyRule{
|
||||||
|
{
|
||||||
|
Resources: []string{"*"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Resources: []string{"DATA"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
|
||||||
|
require.NotNil(t, obj.Object)
|
||||||
|
require.NotNil(t, obj.Cluster)
|
||||||
|
require.NotNil(t, obj.Cluster.Binding)
|
||||||
|
require.NotNil(t, obj.Cluster.Role)
|
||||||
|
require.Nil(t, obj.Namespaced)
|
||||||
|
|
||||||
|
sa := tests.NewMetaObject[*rbac.ClusterRole](t, tests.FakeNamespace, obj.Cluster.Role.GetName())
|
||||||
|
|
||||||
|
tests.RefreshObjects(t, k, nil, &sa)
|
||||||
|
|
||||||
|
require.Len(t, sa.Rules, 2)
|
||||||
|
require.Len(t, sa.Rules[0].Resources, 1)
|
||||||
|
require.Equal(t, sa.Rules[0].Resources[0], "*")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Remove SA Roles", func(t *testing.T) {
|
||||||
|
require.NoError(t, tests.HandleFunc(func(ctx context.Context) (bool, error) {
|
||||||
|
return EnsureServiceAccount(ctx, k, meta.OwnerReference{}, &obj, "test", tests.FakeNamespace, nil, nil)
|
||||||
|
}))
|
||||||
|
|
||||||
|
require.NotNil(t, obj.Object)
|
||||||
|
require.Nil(t, obj.Cluster)
|
||||||
|
require.Nil(t, obj.Namespaced)
|
||||||
|
})
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
batch "k8s.io/api/batch/v1"
|
batch "k8s.io/api/batch/v1"
|
||||||
core "k8s.io/api/core/v1"
|
core "k8s.io/api/core/v1"
|
||||||
|
rbac "k8s.io/api/rbac/v1"
|
||||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/uuid"
|
"k8s.io/apimachinery/pkg/util/uuid"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
|
@ -46,6 +47,27 @@ import (
|
||||||
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/kerrors"
|
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/kerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type handleFunc struct {
|
||||||
|
in func(ctx context.Context) (bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h handleFunc) Name() string {
|
||||||
|
return "mock"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h handleFunc) Handle(ctx context.Context, item operation.Item) error {
|
||||||
|
_, err := h.in(ctx)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h handleFunc) CanBeHandled(item operation.Item) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleFunc(in func(ctx context.Context) (bool, error)) error {
|
||||||
|
return Handle(handleFunc{in: in}, operation.Item{})
|
||||||
|
}
|
||||||
|
|
||||||
func Handle(handler operator.Handler, item operation.Item) error {
|
func Handle(handler operator.Handler, item operation.Item) error {
|
||||||
return HandleWithMax(handler, item, 128)
|
return HandleWithMax(handler, item, 128)
|
||||||
}
|
}
|
||||||
|
@ -80,17 +102,23 @@ func CreateObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe
|
||||||
vl := *v
|
vl := *v
|
||||||
_, err := k8s.BatchV1().Jobs(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
|
_, err := k8s.BatchV1().Jobs(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
case **core.Pod:
|
||||||
|
require.NotNil(t, v)
|
||||||
|
|
||||||
|
vl := *v
|
||||||
|
_, err := k8s.CoreV1().Pods(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
case **core.Secret:
|
case **core.Secret:
|
||||||
require.NotNil(t, v)
|
require.NotNil(t, v)
|
||||||
|
|
||||||
vl := *v
|
vl := *v
|
||||||
_, err := k8s.CoreV1().Secrets(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
|
_, err := k8s.CoreV1().Secrets(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
case **core.Pod:
|
case **core.ServiceAccount:
|
||||||
require.NotNil(t, v)
|
require.NotNil(t, v)
|
||||||
|
|
||||||
vl := *v
|
vl := *v
|
||||||
_, err := k8s.CoreV1().Pods(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
|
_, err := k8s.CoreV1().ServiceAccounts(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
case **api.ArangoDeployment:
|
case **api.ArangoDeployment:
|
||||||
require.NotNil(t, v)
|
require.NotNil(t, v)
|
||||||
|
@ -122,6 +150,30 @@ func CreateObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe
|
||||||
vl := *v
|
vl := *v
|
||||||
_, err := arango.MlV1alpha1().ArangoMLStorages(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
|
_, err := arango.MlV1alpha1().ArangoMLStorages(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
case **rbac.ClusterRole:
|
||||||
|
require.NotNil(t, v)
|
||||||
|
|
||||||
|
vl := *v
|
||||||
|
_, err := k8s.RbacV1().ClusterRoles().Create(context.Background(), vl, meta.CreateOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
case **rbac.ClusterRoleBinding:
|
||||||
|
require.NotNil(t, v)
|
||||||
|
|
||||||
|
vl := *v
|
||||||
|
_, err := k8s.RbacV1().ClusterRoleBindings().Create(context.Background(), vl, meta.CreateOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
case **rbac.Role:
|
||||||
|
require.NotNil(t, v)
|
||||||
|
|
||||||
|
vl := *v
|
||||||
|
_, err := k8s.RbacV1().Roles(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
case **rbac.RoleBinding:
|
||||||
|
require.NotNil(t, v)
|
||||||
|
|
||||||
|
vl := *v
|
||||||
|
_, err := k8s.RbacV1().RoleBindings(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
default:
|
default:
|
||||||
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
|
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
|
||||||
}
|
}
|
||||||
|
@ -153,6 +205,12 @@ func UpdateObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe
|
||||||
vl := *v
|
vl := *v
|
||||||
_, err := k8s.CoreV1().Secrets(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
|
_, err := k8s.CoreV1().Secrets(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
case **core.ServiceAccount:
|
||||||
|
require.NotNil(t, v)
|
||||||
|
|
||||||
|
vl := *v
|
||||||
|
_, err := k8s.CoreV1().ServiceAccounts(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
case **api.ArangoDeployment:
|
case **api.ArangoDeployment:
|
||||||
require.NotNil(t, v)
|
require.NotNil(t, v)
|
||||||
|
|
||||||
|
@ -183,6 +241,30 @@ func UpdateObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe
|
||||||
vl := *v
|
vl := *v
|
||||||
_, err := arango.MlV1alpha1().ArangoMLStorages(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
|
_, err := arango.MlV1alpha1().ArangoMLStorages(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
case **rbac.ClusterRole:
|
||||||
|
require.NotNil(t, v)
|
||||||
|
|
||||||
|
vl := *v
|
||||||
|
_, err := k8s.RbacV1().ClusterRoles().Update(context.Background(), vl, meta.UpdateOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
case **rbac.ClusterRoleBinding:
|
||||||
|
require.NotNil(t, v)
|
||||||
|
|
||||||
|
vl := *v
|
||||||
|
_, err := k8s.RbacV1().ClusterRoleBindings().Update(context.Background(), vl, meta.UpdateOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
case **rbac.Role:
|
||||||
|
require.NotNil(t, v)
|
||||||
|
|
||||||
|
vl := *v
|
||||||
|
_, err := k8s.RbacV1().Roles(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
case **rbac.RoleBinding:
|
||||||
|
require.NotNil(t, v)
|
||||||
|
|
||||||
|
vl := *v
|
||||||
|
_, err := k8s.RbacV1().RoleBindings(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
default:
|
default:
|
||||||
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
|
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
|
||||||
}
|
}
|
||||||
|
@ -241,6 +323,21 @@ func RefreshObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientS
|
||||||
} else {
|
} else {
|
||||||
*v = vn
|
*v = vn
|
||||||
}
|
}
|
||||||
|
case **core.ServiceAccount:
|
||||||
|
require.NotNil(t, v)
|
||||||
|
|
||||||
|
vl := *v
|
||||||
|
|
||||||
|
vn, err := k8s.CoreV1().ServiceAccounts(vl.GetNamespace()).Get(context.Background(), vl.GetName(), meta.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
if kerrors.IsNotFound(err) {
|
||||||
|
*v = nil
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*v = vn
|
||||||
|
}
|
||||||
case **api.ArangoDeployment:
|
case **api.ArangoDeployment:
|
||||||
require.NotNil(t, v)
|
require.NotNil(t, v)
|
||||||
|
|
||||||
|
@ -316,6 +413,66 @@ func RefreshObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientS
|
||||||
} else {
|
} else {
|
||||||
*v = vn
|
*v = vn
|
||||||
}
|
}
|
||||||
|
case **rbac.ClusterRole:
|
||||||
|
require.NotNil(t, v)
|
||||||
|
|
||||||
|
vl := *v
|
||||||
|
|
||||||
|
vn, err := k8s.RbacV1().ClusterRoles().Get(context.Background(), vl.GetName(), meta.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
if kerrors.IsNotFound(err) {
|
||||||
|
*v = nil
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*v = vn
|
||||||
|
}
|
||||||
|
case **rbac.ClusterRoleBinding:
|
||||||
|
require.NotNil(t, v)
|
||||||
|
|
||||||
|
vl := *v
|
||||||
|
|
||||||
|
vn, err := k8s.RbacV1().ClusterRoleBindings().Get(context.Background(), vl.GetName(), meta.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
if kerrors.IsNotFound(err) {
|
||||||
|
*v = nil
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*v = vn
|
||||||
|
}
|
||||||
|
case **rbac.Role:
|
||||||
|
require.NotNil(t, v)
|
||||||
|
|
||||||
|
vl := *v
|
||||||
|
|
||||||
|
vn, err := k8s.RbacV1().Roles(vl.GetNamespace()).Get(context.Background(), vl.GetName(), meta.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
if kerrors.IsNotFound(err) {
|
||||||
|
*v = nil
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*v = vn
|
||||||
|
}
|
||||||
|
case **rbac.RoleBinding:
|
||||||
|
require.NotNil(t, v)
|
||||||
|
|
||||||
|
vl := *v
|
||||||
|
|
||||||
|
vn, err := k8s.RbacV1().RoleBindings(vl.GetNamespace()).Get(context.Background(), vl.GetName(), meta.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
if kerrors.IsNotFound(err) {
|
||||||
|
*v = nil
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*v = vn
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
|
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
|
||||||
}
|
}
|
||||||
|
@ -344,6 +501,12 @@ func SetMetaBasedOnType(t *testing.T, object meta.Object) {
|
||||||
v.SetSelfLink(fmt.Sprintf("/api/v1/secrets/%s/%s",
|
v.SetSelfLink(fmt.Sprintf("/api/v1/secrets/%s/%s",
|
||||||
object.GetNamespace(),
|
object.GetNamespace(),
|
||||||
object.GetName()))
|
object.GetName()))
|
||||||
|
case *core.ServiceAccount:
|
||||||
|
v.Kind = "ServiceAccount"
|
||||||
|
v.APIVersion = "v1"
|
||||||
|
v.SetSelfLink(fmt.Sprintf("/api/v1/serviceaccounts/%s/%s",
|
||||||
|
object.GetNamespace(),
|
||||||
|
object.GetName()))
|
||||||
case *api.ArangoDeployment:
|
case *api.ArangoDeployment:
|
||||||
v.Kind = deployment.ArangoDeploymentResourceKind
|
v.Kind = deployment.ArangoDeploymentResourceKind
|
||||||
v.APIVersion = api.SchemeGroupVersion.String()
|
v.APIVersion = api.SchemeGroupVersion.String()
|
||||||
|
@ -384,6 +547,30 @@ func SetMetaBasedOnType(t *testing.T, object meta.Object) {
|
||||||
ml.ArangoMLStorageResourcePlural,
|
ml.ArangoMLStorageResourcePlural,
|
||||||
object.GetNamespace(),
|
object.GetNamespace(),
|
||||||
object.GetName()))
|
object.GetName()))
|
||||||
|
case *rbac.ClusterRole:
|
||||||
|
v.Kind = "ClusterRole"
|
||||||
|
v.APIVersion = "rbac.authorization.k8s.io/v1"
|
||||||
|
v.SetSelfLink(fmt.Sprintf("/api/rbac.authorization.k8s.io/v1/clusterroles/%s/%s",
|
||||||
|
object.GetNamespace(),
|
||||||
|
object.GetName()))
|
||||||
|
case *rbac.ClusterRoleBinding:
|
||||||
|
v.Kind = "ClusterRoleBinding"
|
||||||
|
v.APIVersion = "rbac.authorization.k8s.io/v1"
|
||||||
|
v.SetSelfLink(fmt.Sprintf("/api/rbac.authorization.k8s.io/v1/clusterrolebingings/%s/%s",
|
||||||
|
object.GetNamespace(),
|
||||||
|
object.GetName()))
|
||||||
|
case *rbac.Role:
|
||||||
|
v.Kind = "Role"
|
||||||
|
v.APIVersion = "rbac.authorization.k8s.io/v1"
|
||||||
|
v.SetSelfLink(fmt.Sprintf("/api/rbac.authorization.k8s.io/v1/roles/%s/%s",
|
||||||
|
object.GetNamespace(),
|
||||||
|
object.GetName()))
|
||||||
|
case *rbac.RoleBinding:
|
||||||
|
v.Kind = "RoleBinding"
|
||||||
|
v.APIVersion = "rbac.authorization.k8s.io/v1"
|
||||||
|
v.SetSelfLink(fmt.Sprintf("/api/rbac.authorization.k8s.io/v1/rolebingings/%s/%s",
|
||||||
|
object.GetNamespace(),
|
||||||
|
object.GetName()))
|
||||||
default:
|
default:
|
||||||
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
|
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
|
||||||
}
|
}
|
||||||
|
@ -398,7 +585,9 @@ func NewMetaObject[T meta.Object](t *testing.T, namespace, name string, mods ...
|
||||||
reflect.ValueOf(&obj).Elem().Set(newObj)
|
reflect.ValueOf(&obj).Elem().Set(newObj)
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.SetNamespace(namespace)
|
if IsNamespaced(obj) {
|
||||||
|
obj.SetNamespace(namespace)
|
||||||
|
}
|
||||||
obj.SetName(name)
|
obj.SetName(name)
|
||||||
obj.SetUID(uuid.NewUUID())
|
obj.SetUID(uuid.NewUUID())
|
||||||
|
|
||||||
|
@ -411,6 +600,15 @@ func NewMetaObject[T meta.Object](t *testing.T, namespace, name string, mods ...
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsNamespaced(in meta.Object) bool {
|
||||||
|
switch in.(type) {
|
||||||
|
case *rbac.ClusterRole, *rbac.ClusterRoleBinding:
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func NewItem(t *testing.T, o operation.Operation, object meta.Object) operation.Item {
|
func NewItem(t *testing.T, o operation.Operation, object meta.Object) operation.Item {
|
||||||
item := operation.Item{
|
item := operation.Item{
|
||||||
Operation: o,
|
Operation: o,
|
||||||
|
@ -432,6 +630,10 @@ func NewItem(t *testing.T, o operation.Operation, object meta.Object) operation.
|
||||||
item.Group = ""
|
item.Group = ""
|
||||||
item.Version = "v1"
|
item.Version = "v1"
|
||||||
item.Kind = "Secret"
|
item.Kind = "Secret"
|
||||||
|
case *core.ServiceAccount:
|
||||||
|
item.Group = ""
|
||||||
|
item.Version = "v1"
|
||||||
|
item.Kind = "ServiceAccount"
|
||||||
case *api.ArangoDeployment:
|
case *api.ArangoDeployment:
|
||||||
item.Group = deployment.ArangoDeploymentGroupName
|
item.Group = deployment.ArangoDeploymentGroupName
|
||||||
item.Version = api.ArangoDeploymentVersion
|
item.Version = api.ArangoDeploymentVersion
|
||||||
|
@ -452,6 +654,22 @@ func NewItem(t *testing.T, o operation.Operation, object meta.Object) operation.
|
||||||
item.Group = ml.ArangoMLGroupName
|
item.Group = ml.ArangoMLGroupName
|
||||||
item.Version = mlApi.ArangoMLVersion
|
item.Version = mlApi.ArangoMLVersion
|
||||||
item.Kind = ml.ArangoMLStorageResourceKind
|
item.Kind = ml.ArangoMLStorageResourceKind
|
||||||
|
case *rbac.ClusterRole:
|
||||||
|
item.Group = "rbac.authorization.k8s.io"
|
||||||
|
item.Version = "v1"
|
||||||
|
item.Kind = "ClusterRole"
|
||||||
|
case *rbac.ClusterRoleBinding:
|
||||||
|
item.Group = "rbac.authorization.k8s.io"
|
||||||
|
item.Version = "v1"
|
||||||
|
item.Kind = "ClusterRoleBinding"
|
||||||
|
case *rbac.Role:
|
||||||
|
item.Group = "rbac.authorization.k8s.io"
|
||||||
|
item.Version = "v1"
|
||||||
|
item.Kind = "Role"
|
||||||
|
case *rbac.RoleBinding:
|
||||||
|
item.Group = "rbac.authorization.k8s.io"
|
||||||
|
item.Version = "v1"
|
||||||
|
item.Kind = "RoleBinding"
|
||||||
default:
|
default:
|
||||||
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
|
require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
batch "k8s.io/api/batch/v1"
|
batch "k8s.io/api/batch/v1"
|
||||||
core "k8s.io/api/core/v1"
|
core "k8s.io/api/core/v1"
|
||||||
|
rbac "k8s.io/api/rbac/v1"
|
||||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
backupApi "github.com/arangodb/kube-arangodb/pkg/apis/backup/v1"
|
backupApi "github.com/arangodb/kube-arangodb/pkg/apis/backup/v1"
|
||||||
|
@ -62,6 +63,11 @@ func Test_NewMetaObject(t *testing.T) {
|
||||||
NewMetaObjectRun[*batch.Job](t)
|
NewMetaObjectRun[*batch.Job](t)
|
||||||
NewMetaObjectRun[*core.Pod](t)
|
NewMetaObjectRun[*core.Pod](t)
|
||||||
NewMetaObjectRun[*core.Secret](t)
|
NewMetaObjectRun[*core.Secret](t)
|
||||||
|
NewMetaObjectRun[*core.ServiceAccount](t)
|
||||||
|
NewMetaObjectRun[*rbac.Role](t)
|
||||||
|
NewMetaObjectRun[*rbac.RoleBinding](t)
|
||||||
|
NewMetaObjectRun[*rbac.ClusterRole](t)
|
||||||
|
NewMetaObjectRun[*rbac.ClusterRoleBinding](t)
|
||||||
NewMetaObjectRun[*api.ArangoDeployment](t)
|
NewMetaObjectRun[*api.ArangoDeployment](t)
|
||||||
NewMetaObjectRun[*api.ArangoClusterSynchronization](t)
|
NewMetaObjectRun[*api.ArangoClusterSynchronization](t)
|
||||||
NewMetaObjectRun[*backupApi.ArangoBackup](t)
|
NewMetaObjectRun[*backupApi.ArangoBackup](t)
|
||||||
|
|
Loading…
Reference in a new issue