@@ -18,19 +18,21 @@ package controller
18
18
19
19
import (
20
20
"context"
21
+ "fmt"
21
22
"os"
22
23
"strconv"
23
24
"time"
24
25
25
26
"github.com/miekg/dns"
26
27
"k8s.io/api/core/v1"
27
- errors "k8s.io/apimachinery/pkg/api/errors"
28
+ "k8s.io/apimachinery/pkg/api/errors"
28
29
"k8s.io/apimachinery/pkg/runtime"
29
30
"k8s.io/apimachinery/pkg/types"
30
31
ctrl "sigs.k8s.io/controller-runtime"
31
32
"sigs.k8s.io/controller-runtime/pkg/client"
32
33
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
33
34
"sigs.k8s.io/controller-runtime/pkg/log"
35
+ networking "k8s.io/api/networking/v1"
34
36
35
37
dnsv1alpha1 "github.com/delta10/dns-resolution-operator/api/v1alpha1"
36
38
)
@@ -40,17 +42,18 @@ type DNSResolverReconciler struct {
40
42
Scheme * runtime.Scheme
41
43
}
42
44
43
- type ipMapOptions struct {
44
- CreateDomainIPMapping bool
45
+ type resolverOptions struct {
46
+ GenerateType string
45
47
}
46
48
47
49
var Config struct {
48
- EnableIPv6 bool
49
- IPExpiration time.Duration
50
- MaxRequeueTime uint32
51
- DNS * dns.ClientConfig
52
- DNSProtocol string
53
- DNSEnvironment string
50
+ EnableIPv6 bool
51
+ IPExpiration time.Duration
52
+ MaxRequeueTime uint32
53
+ DNS * dns.ClientConfig
54
+ DNSProtocol string
55
+ DNSEnvironment string
56
+ UpstreamDNSService string
54
57
}
55
58
56
59
var IPCache IPCacheT
@@ -82,6 +85,12 @@ func init() {
82
85
Config .DNSProtocol = "udp"
83
86
Config .DNS .Port = "53"
84
87
Config .DNSEnvironment = "kubernetes"
88
+ s := os .Getenv ("DNS_UPSTREAM_SERVICE" )
89
+ if s == "" {
90
+ Config .UpstreamDNSService = "kube-dns"
91
+ } else {
92
+ Config .UpstreamDNSService = s
93
+ }
85
94
// We add the servers at the beginning of every Reconcile
86
95
}
87
96
duration , err := time .ParseDuration (os .Getenv ("IP_EXPIRATION" ))
@@ -109,22 +118,21 @@ func init() {
109
118
// It gets triggered by changes in DNSResolvers
110
119
func (r * DNSResolverReconciler ) Reconcile (ctx context.Context , req ctrl.Request ) (ctrl.Result , error ) {
111
120
log := log .FromContext (ctx )
112
- default_result_obj := ctrl.Result {
113
- RequeueAfter : time .Second * 10 ,
114
- }
121
+ // result object used for errors
122
+ default_result_obj := ctrl.Result {}
115
123
116
124
if Config .DNSEnvironment == "kubernetes" {
117
125
Config .DNS .Servers = make ([]string , 0 , 2 )
126
+
118
127
// Obtain the pod IPs of kube-dns
119
128
kube_dns_name := types.NamespacedName {
120
129
Namespace : "kube-system" ,
121
- Name : "kube-dns" ,
130
+ Name : Config . UpstreamDNSService ,
122
131
}
123
132
dns_ep := new (v1.Endpoints )
124
133
err := r .Get (ctx , kube_dns_name , dns_ep )
125
134
if err != nil {
126
- log .Error (err , "unable to fetch kube-dns Endpoints" )
127
- return default_result_obj , err
135
+ return default_result_obj , fmt .Errorf ("unable to fetch kube-dns Endpoints: %w" , err )
128
136
}
129
137
for i := range dns_ep .Subsets {
130
138
for _ , addr := range dns_ep .Subsets [i ].Addresses {
@@ -143,13 +151,13 @@ func (r *DNSResolverReconciler) Reconcile(ctx context.Context, req ctrl.Request)
143
151
IPCache .Delete (req .NamespacedName , "" )
144
152
log .Info ("Removed IPMap from cache" , "IPMap.Namespace" , req .Namespace , "IPMap.Name" , req .Name )
145
153
} else {
146
- log . Error ( err , "unable to fetch DNSResolver" )
154
+ err = fmt . Errorf ( "unable to fetch DNSResolver: %w" , err )
147
155
}
148
156
return default_result_obj , client .IgnoreNotFound (err )
149
157
}
150
158
151
- options := & ipMapOptions {
152
- CreateDomainIPMapping : resolver .Spec .CreateDomainIPMapping ,
159
+ options := & resolverOptions {
160
+ GenerateType : resolver .Spec .GenerateType ,
153
161
}
154
162
155
163
// Create an empty IPMap to populate later
@@ -159,6 +167,7 @@ func (r *DNSResolverReconciler) Reconcile(ctx context.Context, req ctrl.Request)
159
167
160
168
// First, check if `resolver` has an associated IPMap already
161
169
get_err := r .Get (ctx , req .NamespacedName , ip_map )
170
+ ip_map .ObjectMeta .Labels = resolver .ObjectMeta .Labels
162
171
163
172
// Make sure the ownerRef on `resolver` is set to the IPMap we are working on
164
173
// This will fail if IPMap is already owned by another resource
@@ -168,49 +177,68 @@ func (r *DNSResolverReconciler) Reconcile(ctx context.Context, req ctrl.Request)
168
177
169
178
if get_err != nil && errors .IsNotFound (get_err ) {
170
179
171
- // There is no IPMap matching `resolver`, so we create one
172
-
173
- log .Info ("Creating IPMap" , "IPMap.Namespace" , req .Namespace , "IPMap.Name" , req .Name )
180
+ // There is no IPMap matching `resolver`, so we create an IPMap and NetworkPolicy
174
181
175
182
_ , minttl , err := ipmapUpdate (ip_map , resolver .Spec .DomainList , options )
176
183
if err != nil {
177
- log .Error (err , "failed to generate IPMap Data" )
178
- return default_result_obj , err
184
+ return default_result_obj , fmt .Errorf ("failed to generate IPMap Data: %w" , err )
179
185
}
186
+
187
+ if options .GenerateType == "NetworkPolicy" {
188
+ if err := r .NPReconcile (ctx , ip_map ); err != nil {
189
+ // We return so the IPMap does not get updated. This ensure we take the same code path next time
190
+ return default_result_obj , fmt .Errorf ("failed to create NetworkPolicy: %w" , err )
191
+ }
192
+ }
193
+
194
+ log .Info ("Creating IPMap" , "IPMap.Namespace" , req .Namespace , "IPMap.Name" , req .Name )
180
195
if err := r .Create (ctx , ip_map ); err != nil {
181
- log .Error (err , "failed to create IPMap resource" )
182
- return default_result_obj , err
196
+ return default_result_obj , fmt .Errorf ("failed to create IPMap resource: %w" , err )
183
197
}
184
198
185
199
requeue := time .Second * time .Duration (minttl + 1 )
186
200
log .Info ("Requeueing DNSResolver" , "RequeueAfter" , requeue )
187
201
return ctrl.Result {RequeueAfter : requeue }, nil
188
202
189
- } else if get_err ! = nil {
203
+ } else if get_err = = nil {
190
204
191
- log .Error (get_err , "failed to get IPMap" )
192
- return default_result_obj , get_err
193
-
194
- } else {
195
-
196
- // The IPMap matching `resolver` exists, so we update it
205
+ // The IPMap matching `resolver` exists, so we update it and the NetworkPolicy
197
206
198
207
updated , minttl , err := ipmapUpdate (ip_map , resolver .Spec .DomainList , options )
199
208
if err != nil {
200
- log .Error (err , "failed to generate IPMap Data (update)" )
201
- return default_result_obj , err
209
+ return default_result_obj , fmt .Errorf ("failed to generate IPMap Data (update): %w" , err )
202
210
}
211
+
203
212
if updated {
213
+ if options .GenerateType == "NetworkPolicy" {
214
+ if err := r .NPReconcile (ctx , ip_map ); err != nil {
215
+ // We return so the IPMap does not get updated. This ensure we take the same code path next time
216
+ return default_result_obj , fmt .Errorf ("failed to update NetworkPolicy: %w" , err )
217
+ }
218
+ }
204
219
log .Info ("Updating IPMap" , "IPMap.Namespace" , req .Namespace , "IPMap.Name" , req .Name )
205
220
if err := r .Update (ctx , ip_map ); err != nil {
206
- log .Error (err , "failed to update IPMap resource" )
207
- return default_result_obj , err
221
+ return default_result_obj , fmt .Errorf ("failed to update IPMap resource: %w" , err )
222
+ }
223
+ } else {
224
+ if options .GenerateType == "NetworkPolicy" {
225
+ // Note that if a NetworkPolicy exists we assume it is synced with the IPMap already. We still
226
+ // want to check if it exists in the no-update scenario, in case it was inadvertently deleted
227
+ np := new (networking.NetworkPolicy )
228
+ name := types.NamespacedName {Name : ip_map .Name , Namespace : ip_map .Namespace }
229
+ if err := r .Get (ctx , name , np ); err != nil {
230
+ if err := r .NPReconcile (ctx , ip_map ); err != nil {
231
+ return default_result_obj , fmt .Errorf ("failed to create NetworkPolicy: %w" , err )
232
+ }
233
+ }
208
234
}
209
235
}
210
236
211
237
requeue := time .Second * time .Duration (minttl + 1 )
212
238
log .Info ("Requeueing DNSResolver" , "RequeueAfter" , requeue )
213
239
return ctrl.Result {RequeueAfter : requeue }, nil
240
+ } else {
241
+ return default_result_obj , fmt .Errorf ("failed to get IPMap: %w" , get_err )
214
242
}
215
243
}
216
244
0 commit comments