blob: 8b32ecf0d9b88f9f1e4a488f1fa7fe35e7b8fc7f [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"
Giorgi Lekveishvilie58fc592023-12-07 13:24:07 +040025 apierrors "k8s.io/apimachinery/pkg/api/errors"
Giorgi Lekveishvilie8b2f012023-11-30 19:05:03 +040026 "k8s.io/apimachinery/pkg/runtime"
27 ctrl "sigs.k8s.io/controller-runtime"
28 "sigs.k8s.io/controller-runtime/pkg/client"
29 "sigs.k8s.io/controller-runtime/pkg/log"
30
31 dodocloudv1 "github.com/giolekva/pcloud/core/ns-controller/api/v1"
32)
33
34// DNSZoneReconciler reconciles a DNSZone object
35type DNSZoneReconciler struct {
36 client.Client
37 Scheme *runtime.Scheme
38 Store ZoneStoreFactory
39}
40
41type DNSSecKey struct {
42 Basename string `json:"basename,omitempty"`
43 Key []byte `json:"key,omitempty"`
44 Private []byte `json:"private,omitempty"`
45 DS []byte `json:"ds,omitempty"`
46}
47
48//+kubebuilder:rbac:groups=dodo.cloud.dodo.cloud,resources=dnszones,verbs=get;list;watch;create;update;patch;delete
49//+kubebuilder:rbac:groups=dodo.cloud.dodo.cloud,resources=dnszones/status,verbs=get;update;patch
50//+kubebuilder:rbac:groups=dodo.cloud.dodo.cloud,resources=dnszones/finalizers,verbs=update
51//+kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch;delete
52
53// Reconcile is part of the main kubernetes reconciliation loop which aims to
54// move the current state of the cluster closer to the desired state.
55// TODO(user): Modify the Reconcile function to compare the state specified by
56// the DNSZone object against the actual cluster state, and then
57// perform operations to make the cluster state reflect the state specified by
58// the user.
59//
60// For more details, check Reconcile and its Result here:
61// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.2/pkg/reconcile
62func (r *DNSZoneReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
63 r.Store.Debug()
64 defer func() {
65 r.Store.Debug()
66 }()
67 logger := log.FromContext(ctx)
68 logger.Info(req.String())
69
70 resource := &dodocloudv1.DNSZone{}
71 if err := r.Get(context.Background(), client.ObjectKey{
72 Namespace: req.Namespace,
73 Name: req.Name,
74 }, resource); err != nil {
Giorgi Lekveishvilie58fc592023-12-07 13:24:07 +040075 if apierrors.IsGone(err) {
76 fmt.Printf("GONE %s %s\n", req.Name, req.Namespace)
77 } else {
78 return ctrl.Result{RequeueAfter: time.Minute}, err
79 }
Giorgi Lekveishvilie8b2f012023-11-30 19:05:03 +040080 }
81 if resource.Status.Ready {
82 return ctrl.Result{}, nil
83 }
84 zoneConfig := ZoneConfig{
85 Zone: resource.Spec.Zone,
86 PublicIPs: resource.Spec.PublicIPs,
87 PrivateIP: resource.Spec.PrivateIP,
88 Nameservers: resource.Spec.Nameservers,
89 }
90 if resource.Spec.DNSSec.Enabled {
91 var secret corev1.Secret
92 if err := r.Get(context.Background(), client.ObjectKey{
93 Namespace: resource.Namespace, // NOTE(gio): configurable on resource level?
94 Name: resource.Spec.DNSSec.SecretName,
95 }, &secret); err != nil {
96 return ctrl.Result{RequeueAfter: time.Minute}, err
97 }
98 basename, ok := secret.Data["basename"]
99 if !ok {
100 return ctrl.Result{RequeueAfter: time.Minute}, fmt.Errorf("basename not found")
101 }
102 key, ok := secret.Data["key"]
103 if !ok {
104 return ctrl.Result{RequeueAfter: time.Minute}, fmt.Errorf("key not found")
105 }
106 private, ok := secret.Data["private"]
107 if !ok {
108 return ctrl.Result{RequeueAfter: time.Minute}, fmt.Errorf("private not found")
109 }
110 ds, ok := secret.Data["ds"]
111 if !ok {
112 return ctrl.Result{RequeueAfter: time.Minute}, fmt.Errorf("ds not found")
113 }
114 zoneConfig.DNSSec = &DNSSecKey{
115 Basename: string(basename),
116 Key: key,
117 Private: private,
118 DS: ds,
119 }
120 }
Giorgi Lekveishvilie58fc592023-12-07 13:24:07 +0400121 zs, err := r.Store.Create(zoneConfig)
Giorgi Lekveishvilie8b2f012023-11-30 19:05:03 +0400122 if err != nil {
123 return ctrl.Result{RequeueAfter: time.Minute}, err
124 }
Giorgi Lekveishvilie58fc592023-12-07 13:24:07 +0400125 if err := zs.CreateConfigFile(); err != nil {
126 return ctrl.Result{RequeueAfter: time.Minute}, err
127 }
Giorgi Lekveishvilie8b2f012023-11-30 19:05:03 +0400128 resource.Status.Ready = true
129 if zoneConfig.DNSSec != nil {
130 resource.Status.RecordsToPublish = string(zoneConfig.DNSSec.DS)
131 }
132 if err := r.Status().Update(context.Background(), resource); err != nil {
133 return ctrl.Result{RequeueAfter: time.Minute}, err
134 }
135 return ctrl.Result{}, nil
136}
137
138// SetupWithManager sets up the controller with the Manager.
139func (r *DNSZoneReconciler) SetupWithManager(mgr ctrl.Manager) error {
140 return ctrl.NewControllerManagedBy(mgr).
141 For(&dodocloudv1.DNSZone{}).
142 Complete(r)
143}