blob: 40883ef4fa2dfa6bdb373d58d478d012d4f5b266 [file] [log] [blame]
Giorgi Lekveishvilie8b2f012023-11-30 19:05:03 +04001/*
2Copyright 2023.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package controllers
18
19import (
20 "context"
21 "fmt"
22 "time"
23
24 corev1 "k8s.io/api/core/v1"
25 "k8s.io/apimachinery/pkg/runtime"
26 ctrl "sigs.k8s.io/controller-runtime"
27 "sigs.k8s.io/controller-runtime/pkg/client"
28 "sigs.k8s.io/controller-runtime/pkg/log"
29
30 dodocloudv1 "github.com/giolekva/pcloud/core/ns-controller/api/v1"
31)
32
33// DNSZoneReconciler reconciles a DNSZone object
34type DNSZoneReconciler struct {
35 client.Client
36 Scheme *runtime.Scheme
37 Store ZoneStoreFactory
38}
39
40type DNSSecKey struct {
41 Basename string `json:"basename,omitempty"`
42 Key []byte `json:"key,omitempty"`
43 Private []byte `json:"private,omitempty"`
44 DS []byte `json:"ds,omitempty"`
45}
46
47//+kubebuilder:rbac:groups=dodo.cloud.dodo.cloud,resources=dnszones,verbs=get;list;watch;create;update;patch;delete
48//+kubebuilder:rbac:groups=dodo.cloud.dodo.cloud,resources=dnszones/status,verbs=get;update;patch
49//+kubebuilder:rbac:groups=dodo.cloud.dodo.cloud,resources=dnszones/finalizers,verbs=update
50//+kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch;delete
51
52// Reconcile is part of the main kubernetes reconciliation loop which aims to
53// move the current state of the cluster closer to the desired state.
54// TODO(user): Modify the Reconcile function to compare the state specified by
55// the DNSZone object against the actual cluster state, and then
56// perform operations to make the cluster state reflect the state specified by
57// the user.
58//
59// For more details, check Reconcile and its Result here:
60// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile
61func (r *DNSZoneReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
62 r.Store.Debug()
63 defer func() {
64 r.Store.Debug()
65 }()
66 logger := log.FromContext(ctx)
67 logger.Info(req.String())
68
69 resource := &dodocloudv1.DNSZone{}
70 if err := r.Get(context.Background(), client.ObjectKey{
71 Namespace: req.Namespace,
72 Name: req.Name,
73 }, resource); err != nil {
74 return ctrl.Result{RequeueAfter: time.Minute}, err
75 }
76 if resource.Status.Ready {
77 return ctrl.Result{}, nil
78 }
79 zoneConfig := ZoneConfig{
80 Zone: resource.Spec.Zone,
81 PublicIPs: resource.Spec.PublicIPs,
82 PrivateIP: resource.Spec.PrivateIP,
83 Nameservers: resource.Spec.Nameservers,
84 }
85 if resource.Spec.DNSSec.Enabled {
86 var secret corev1.Secret
87 if err := r.Get(context.Background(), client.ObjectKey{
88 Namespace: resource.Namespace, // NOTE(gio): configurable on resource level?
89 Name: resource.Spec.DNSSec.SecretName,
90 }, &secret); err != nil {
91 return ctrl.Result{RequeueAfter: time.Minute}, err
92 }
93 basename, ok := secret.Data["basename"]
94 if !ok {
95 return ctrl.Result{RequeueAfter: time.Minute}, fmt.Errorf("basename not found")
96 }
97 key, ok := secret.Data["key"]
98 if !ok {
99 return ctrl.Result{RequeueAfter: time.Minute}, fmt.Errorf("key not found")
100 }
101 private, ok := secret.Data["private"]
102 if !ok {
103 return ctrl.Result{RequeueAfter: time.Minute}, fmt.Errorf("private not found")
104 }
105 ds, ok := secret.Data["ds"]
106 if !ok {
107 return ctrl.Result{RequeueAfter: time.Minute}, fmt.Errorf("ds not found")
108 }
109 zoneConfig.DNSSec = &DNSSecKey{
110 Basename: string(basename),
111 Key: key,
112 Private: private,
113 DS: ds,
114 }
115 }
116 _, err := r.Store.Create(zoneConfig)
117 if err != nil {
118 return ctrl.Result{RequeueAfter: time.Minute}, err
119 }
120 resource.Status.Ready = true
121 if zoneConfig.DNSSec != nil {
122 resource.Status.RecordsToPublish = string(zoneConfig.DNSSec.DS)
123 }
124 if err := r.Status().Update(context.Background(), resource); err != nil {
125 return ctrl.Result{RequeueAfter: time.Minute}, err
126 }
127 return ctrl.Result{}, nil
128}
129
130// SetupWithManager sets up the controller with the Manager.
131func (r *DNSZoneReconciler) SetupWithManager(mgr ctrl.Manager) error {
132 return ctrl.NewControllerManagedBy(mgr).
133 For(&dodocloudv1.DNSZone{}).
134 Complete(r)
135}