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