/
controller.go
157 lines (127 loc) · 5.99 KB
/
controller.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package certificaterequest
import (
"context"
"time"
"github.com/kyma-project/kyma/components/connectivity-certs-controller/internal/centralconnection"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/util/retry"
"github.com/kyma-project/kyma/components/connectivity-certs-controller/internal/certificates"
"github.com/kyma-project/kyma/components/connectivity-certs-controller/internal/connectorservice"
"github.com/kyma-project/kyma/components/connectivity-certs-controller/pkg/apis/applicationconnector/v1alpha1"
log "github.com/sirupsen/logrus"
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
)
//go:generate mockery -name Client
type Client interface {
Get(ctx context.Context, key client.ObjectKey, obj runtime.Object) error
Update(ctx context.Context, obj runtime.Object, opts ...client.UpdateOption) error
Delete(ctx context.Context, obj runtime.Object, opts ...client.DeleteOption) error
}
type Controller struct {
certificateRequestClient Client
initialConnectionClient connectorservice.InitialConnectionClient
certificatePreserver certificates.Preserver
connectionClient centralconnection.Client
logger *log.Entry
}
func InitCertificatesRequestController(mgr manager.Manager, appName string, connectorClient connectorservice.InitialConnectionClient, certPreserver certificates.Preserver, connectionClient centralconnection.Client) error {
return startController(appName, mgr, connectorClient, certPreserver, connectionClient)
}
func startController(appName string, mgr manager.Manager, initialConnectionClient connectorservice.InitialConnectionClient, certPreserver certificates.Preserver, connectionClient centralconnection.Client) error {
certRequestController := newCertificatesRequestController(mgr.GetClient(), initialConnectionClient, certPreserver, connectionClient)
c, err := controller.New(appName, mgr, controller.Options{Reconciler: certRequestController})
if err != nil {
return err
}
return c.Watch(&source.Kind{Type: &v1alpha1.CertificateRequest{}}, &handler.EnqueueRequestForObject{})
}
func newCertificatesRequestController(client Client, connectorClient connectorservice.InitialConnectionClient, certPreserver certificates.Preserver, connectionManager centralconnection.Client) *Controller {
return &Controller{
certificateRequestClient: client,
initialConnectionClient: connectorClient,
certificatePreserver: certPreserver,
connectionClient: connectionManager,
logger: log.WithField("Controller", "Certificate Request"),
}
}
func (c *Controller) Reconcile(request reconcile.Request) (reconcile.Result, error) {
instance := &v1alpha1.CertificateRequest{}
c.logger.Infof("Processing %s request", request.Name)
err := c.certificateRequestClient.Get(context.Background(), request.NamespacedName, instance)
if err != nil {
return c.handleErrorWhileGettingInstance(err, request)
}
if instance.Status.Error != "" {
c.logger.Infof("Certificate Request %s has an error status, certificate will not be fetched", instance.Name)
return reconcile.Result{}, nil
}
c.logger.Infof("Establishing connection with Connector Service for %s Cert Request...", instance.Name)
establishedConnection, err := c.initialConnectionClient.Establish(instance.Spec.CSRInfoURL)
if err != nil {
c.logger.Errorf("Error while requesting certificates from Connector Service: %s", err.Error())
return reconcile.Result{}, c.setRequestErrorStatus(instance, err)
}
c.logger.Infof("Certificates for %s Cert Request fetched successfully", instance.Name)
err = c.manageResources(instance.Name, establishedConnection)
if err != nil {
return reconcile.Result{}, c.setRequestErrorStatus(instance, err)
}
err = c.certificateRequestClient.Delete(context.Background(), instance)
if err != nil {
return reconcile.Result{}, err
}
c.logger.Infof("CertificatesRequest %s successfully deleted", instance.Name)
return reconcile.Result{}, nil
}
func (c *Controller) manageResources(connectionName string, connection connectorservice.EstablishedConnection) error {
err := c.certificatePreserver.PreserveCertificates(connection.Certificates)
if err != nil {
c.logger.Errorf("Error while saving certificates to secrets: %s", err.Error())
return err
}
c.logger.Infoln("Certificates saved successfully")
centralConnectionSpec := v1alpha1.CentralConnectionSpec{
ManagementInfoURL: connection.ManagementInfoURL,
EstablishedAt: metav1.NewTime(time.Now()),
}
_, err = c.connectionClient.Upsert(connectionName, centralConnectionSpec)
if err != nil {
c.logger.Errorf("Error while upserting Central Connection resource: %s", err.Error())
return err
}
return nil
}
func (c *Controller) handleErrorWhileGettingInstance(err error, request reconcile.Request) (reconcile.Result, error) {
if k8sErrors.IsNotFound(err) {
c.logger.Infof("Request %s has been deleted", request.Name)
return reconcile.Result{}, nil
}
c.logger.Errorf("Error while getting instance, %s", err.Error())
return reconcile.Result{}, err
}
func (c *Controller) setRequestErrorStatus(instance *v1alpha1.CertificateRequest, statusError error) error {
name := types.NamespacedName{
Name: instance.Name,
Namespace: instance.Namespace,
}
upToDateInstance := &v1alpha1.CertificateRequest{}
return retry.RetryOnConflict(retry.DefaultBackoff, func() error {
err := c.certificateRequestClient.Get(context.Background(), name, upToDateInstance)
if err != nil {
c.logger.Errorf("Failed to get up to date resource: %s", err.Error())
return err
}
upToDateInstance.Status = v1alpha1.CertificateRequestStatus{
Error: statusError.Error(),
}
return c.certificateRequestClient.Update(context.Background(), upToDateInstance)
})
}