Skip to content
This repository has been archived by the owner on Oct 10, 2023. It is now read-only.

Commit

Permalink
Add serviceAccount to ReadinessProvider spec
Browse files Browse the repository at this point in the history
Signed-off-by: Avi Sharma <avi.08.sh@gmail.com>
  • Loading branch information
avi-08 committed Jun 20, 2023
1 parent 7fa2b72 commit 45c37c1
Show file tree
Hide file tree
Showing 16 changed files with 402 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,24 @@ spec:
- name
type: object
type: array
serviceAccount:
description: ServiceAccount represents the service account to be used
to make requests to the API server for evaluating conditions. If
not provided, it uses the default service account of the readiness
provider controller.
properties:
name:
description: Name is the name of the service account to be used
to make requests to the API server for evaluating conditions.
type: string
namespace:
description: Namespace is the namespace containing the service
account.
type: string
required:
- name
- namespace
type: object
required:
- checkRefs
- conditions
Expand Down Expand Up @@ -124,6 +142,10 @@ spec:
- state
type: object
type: array
message:
description: Message provides information about the ReadinessProvider
state
type: string
state:
description: State is the computed state of the provider. The state
will be success if all the conditions pass; The state will be failure
Expand All @@ -135,6 +157,7 @@ spec:
type: string
required:
- conditions
- message
- state
type: object
type: object
Expand Down
19 changes: 19 additions & 0 deletions apis/core/v1alpha2/readinessprovider_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,22 @@ type ReadinessProviderSpec struct {

// Conditions is the set of checks that must be evaluated to true to mark the provider as ready
Conditions []ReadinessProviderCondition `json:"conditions"`

// ServiceAccount represents the service account to be used
// to make requests to the API server for evaluating conditions.
// If not provided, it uses the default service account
// of the readiness provider controller.
//+kubebuilder:validation:Optional
ServiceAccount *ServiceAccountSource `json:"serviceAccount"`
}

type ServiceAccountSource struct {
// Namespace is the namespace containing the service account.
Namespace string `json:"namespace"`

// Name is the name of the service account to be used
// to make requests to the API server for evaluating conditions.
Name string `json:"name"`
}

// ReadinessProviderCondition defines the readiness provider condition
Expand Down Expand Up @@ -79,6 +95,9 @@ type ReadinessProviderStatus struct {
// +kubebuilder:validation:Enum=success;failure;inprogress
State ReadinessProviderState `json:"state"`

// Message provides information about the ReadinessProvider state
Message string `json:"message"`

// Conditions is the set of ReadinessConditions that are being evaluated
Conditions []ReadinessConditionStatus `json:"conditions"`
}
Expand Down
40 changes: 37 additions & 3 deletions apis/core/v1alpha2/readinessprovider_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,29 @@
package v1alpha2

import (
"context"
"fmt"

corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/webhook"
)

// log is for logging in this package.
var readinessproviderlog = logf.Log.WithName("readinessprovider-resource").WithValues("apigroup", "core")
var (
// log is for logging in this package.
readinessproviderlog = logf.Log.WithName("readinessprovider-resource").WithValues("apigroup", "core")
// cli is the client used for making calls to the k8s API server.
cli client.Client
)

// SetupWebhookWithManager adds the webhook to the manager.
func (r *ReadinessProvider) SetupWebhookWithManager(mgr ctrl.Manager) error {
cli = mgr.GetClient()
return ctrl.NewWebhookManagedBy(mgr).
For(r).
Complete()
Expand Down Expand Up @@ -46,13 +54,39 @@ func (r *ReadinessProvider) ValidateDelete() error {

func (r *ReadinessProvider) validateObject() error {
var allErrors field.ErrorList
specPath := field.NewPath("spec")

saSource := r.Spec.ServiceAccount
if saSource != nil {
if saSource.Name == "" {
allErrors = append(allErrors, field.Required(specPath.Child("serviceAccount").Child("Name"), "missing required field"))
}

if saSource.Namespace == "" {
allErrors = append(allErrors, field.Required(specPath.Child("serviceAccount").Child("Namespace"), "missing required field"))
}
}

// Checking if provided serviceaccount is valid
if saSource != nil && len(allErrors) == 0 {
sa := &corev1.ServiceAccount{}
readinessproviderlog.Info("checking if service account is present", "source", saSource)
err := cli.Get(context.Background(), client.ObjectKey{
Namespace: saSource.Namespace,
Name: saSource.Name,
}, sa)

if err != nil {
allErrors = append(allErrors, field.Invalid(specPath.Child("serviceAccount"), saSource, err.Error()))
}
}

for _, condition := range r.Spec.Conditions {
if condition.ResourceExistenceCondition == nil {
allErrors = append(
allErrors,
field.Invalid(
field.NewPath("spec").Child("conditions"),
specPath.Child("conditions"),
r.Spec.Conditions, fmt.Sprintf("Expected condition %s to have exactly one type defined", condition.Name)))
}
}
Expand Down
20 changes: 20 additions & 0 deletions apis/core/v1alpha2/zz_generated.deepcopy.go

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

Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,24 @@ spec:
- name
type: object
type: array
serviceAccount:
description: ServiceAccount represents the service account to be used
to make requests to the API server for evaluating conditions. If
not provided, it uses the default service account of the readiness
provider controller.
properties:
name:
description: Name is the name of the service account to be used
to make requests to the API server for evaluating conditions.
type: string
namespace:
description: Namespace is the namespace containing the service
account.
type: string
required:
- name
- namespace
type: object
required:
- checkRefs
- conditions
Expand Down Expand Up @@ -124,6 +142,10 @@ spec:
- state
type: object
type: array
message:
description: Message provides information about the ReadinessProvider
state
type: string
state:
description: State is the computed state of the provider. The state
will be success if all the conditions pass; The state will be failure
Expand All @@ -135,6 +157,7 @@ spec:
type: string
required:
- conditions
- message
- state
type: object
type: object
Expand Down
38 changes: 11 additions & 27 deletions packages/readiness/bundle/config/upstream/rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,6 @@ rules:
- core.tanzu.vmware.com
resources:
- readinesses
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- core.tanzu.vmware.com
resources:
- readinesses/finalizers
verbs:
- update
- apiGroups:
- core.tanzu.vmware.com
resources:
- readinesses/status
verbs:
- get
- patch
- update
- apiGroups:
- core.tanzu.vmware.com
resources:
- readinessproviders
verbs:
- create
Expand All @@ -58,12 +33,14 @@ rules:
- apiGroups:
- core.tanzu.vmware.com
resources:
- readinesses/finalizers
- readinessproviders/finalizers
verbs:
- update
- apiGroups:
- core.tanzu.vmware.com
resources:
- readinesses/status
- readinessproviders/status
verbs:
- get
Expand All @@ -88,11 +65,18 @@ rules:
- list
- update
- apiGroups:
- "*"
- ""
resources:
- serviceaccounts/token
verbs:
- create
- apiGroups:
- ""
resources:
- "*"
- serviceaccounts
verbs:
- get
- list
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
Expand Down
2 changes: 1 addition & 1 deletion readiness/controller/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
github.com/go-logr/logr v1.2.3
github.com/onsi/ginkgo/v2 v2.9.2
github.com/onsi/gomega v1.27.6
github.com/pkg/errors v0.9.1
github.com/vmware-tanzu/tanzu-framework/apis/core v0.0.0-00010101000000-000000000000
github.com/vmware-tanzu/tanzu-framework/capabilities/client v0.0.0-00010101000000-000000000000
github.com/vmware-tanzu/tanzu-framework/util v0.0.0-00010101000000-000000000000
Expand Down Expand Up @@ -54,7 +55,6 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
Expand Down
5 changes: 5 additions & 0 deletions readiness/controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
cliflag "k8s.io/component-base/cli/flag"
ctrl "sigs.k8s.io/controller-runtime"
Expand Down Expand Up @@ -108,6 +109,8 @@ func main() {
os.Exit(1)
}

k8sClientset := kubernetes.NewForConfigOrDie(restConfig)

dynamicClient, err := dynamic.NewForConfig(restConfig)
if err != nil {
setupLog.Error(err, "unable to create dynamic client")
Expand Down Expand Up @@ -147,9 +150,11 @@ func main() {

if err = (&readinessprovidercontroller.ReadinessProviderReconciler{
Client: mgr.GetClient(),
Clientset: k8sClientset,
Log: ctrl.Log.WithName("controllers").WithName("ReadinessProvider").WithValues("apigroup", "core"),
Scheme: mgr.GetScheme(),
ResourceExistenceCondition: conditions.NewResourceExistenceConditionFunc(dynamicClient, discoveryClient),
RestConfig: restConfig,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "ReadinessProvider")
os.Exit(1)
Expand Down
15 changes: 10 additions & 5 deletions readiness/controller/pkg/conditions/resourceexistence.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,22 @@ import (
)

// NewResourceExistenceConditionFunc returns a function for evaluating evaluate a ResourceExistenceCondition
func NewResourceExistenceConditionFunc(dynamicClient *dynamic.DynamicClient, discoveryClient *discovery.DiscoveryClient) func(context.Context, *corev1alpha2.ResourceExistenceCondition, string) (corev1alpha2.ReadinessConditionState, string) {
return func(ctx context.Context, c *corev1alpha2.ResourceExistenceCondition, conditionName string) (corev1alpha2.ReadinessConditionState, string) {
func NewResourceExistenceConditionFunc(dynamicClient *dynamic.DynamicClient, discoveryClient *discovery.DiscoveryClient) func(context.Context, *capabilitiesDiscovery.ClusterQueryClient, *corev1alpha2.ResourceExistenceCondition, string) (corev1alpha2.ReadinessConditionState, string) {
return func(ctx context.Context, client *capabilitiesDiscovery.ClusterQueryClient, c *corev1alpha2.ResourceExistenceCondition, conditionName string) (corev1alpha2.ReadinessConditionState, string) {
if c == nil {
return corev1alpha2.ConditionFailureState, "resourceExistenceCondition is not defined"
}

var err error
var queryClient *capabilitiesDiscovery.ClusterQueryClient

queryClient, err := capabilitiesDiscovery.NewClusterQueryClient(dynamicClient, discoveryClient)
if err != nil {
return corev1alpha2.ConditionFailureState, err.Error()
// Create client using default config if no ClusterQueryClient provided
if client != nil {
queryClient = client
} else {
if queryClient, err = capabilitiesDiscovery.NewClusterQueryClient(dynamicClient, discoveryClient); err != nil {
return corev1alpha2.ConditionFailureState, err.Error()
}
}

var resourceToFind corev1.ObjectReference
Expand Down
Loading

0 comments on commit 45c37c1

Please sign in to comment.