github.com/argoproj-labs/argocd-operator@v0.10.0/controllers/argocd/ingress.go (about) 1 // Copyright 2019 ArgoCD Operator Developers 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package argocd 16 17 import ( 18 "context" 19 "fmt" 20 21 networkingv1 "k8s.io/api/networking/v1" 22 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" 24 25 argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" 26 "github.com/argoproj-labs/argocd-operator/common" 27 "github.com/argoproj-labs/argocd-operator/controllers/argoutil" 28 ) 29 30 // getArgoServerPath will return the Ingress Path for the Argo CD component. 31 func getPathOrDefault(path string) string { 32 result := common.ArgoCDDefaultIngressPath 33 if len(path) > 0 { 34 result = path 35 } 36 return result 37 } 38 39 // newIngress returns a new Ingress instance for the given ArgoCD. 40 func newIngress(cr *argoproj.ArgoCD) *networkingv1.Ingress { 41 return &networkingv1.Ingress{ 42 ObjectMeta: metav1.ObjectMeta{ 43 Name: cr.Name, 44 Namespace: cr.Namespace, 45 Labels: argoutil.LabelsForCluster(cr), 46 }, 47 } 48 } 49 50 // newIngressWithName returns a new Ingress with the given name and ArgoCD. 51 func newIngressWithName(name string, cr *argoproj.ArgoCD) *networkingv1.Ingress { 52 ingress := newIngress(cr) 53 ingress.ObjectMeta.Name = name 54 55 lbls := ingress.ObjectMeta.Labels 56 lbls[common.ArgoCDKeyName] = name 57 ingress.ObjectMeta.Labels = lbls 58 59 return ingress 60 } 61 62 // newIngressWithSuffix returns a new Ingress with the given name suffix for the ArgoCD. 63 func newIngressWithSuffix(suffix string, cr *argoproj.ArgoCD) *networkingv1.Ingress { 64 return newIngressWithName(fmt.Sprintf("%s-%s", cr.Name, suffix), cr) 65 } 66 67 // reconcileIngresses will ensure that all ArgoCD Ingress resources are present. 68 func (r *ReconcileArgoCD) reconcileIngresses(cr *argoproj.ArgoCD) error { 69 if err := r.reconcileArgoServerIngress(cr); err != nil { 70 return err 71 } 72 73 if err := r.reconcileArgoServerGRPCIngress(cr); err != nil { 74 return err 75 } 76 77 if err := r.reconcileGrafanaIngress(cr); err != nil { 78 return err 79 } 80 81 if err := r.reconcilePrometheusIngress(cr); err != nil { 82 return err 83 } 84 85 if err := r.reconcileApplicationSetControllerIngress(cr); err != nil { 86 return err 87 } 88 89 return nil 90 } 91 92 // reconcileArgoServerIngress will ensure that the ArgoCD Server Ingress is present. 93 func (r *ReconcileArgoCD) reconcileArgoServerIngress(cr *argoproj.ArgoCD) error { 94 ingress := newIngressWithSuffix("server", cr) 95 if argoutil.IsObjectFound(r.Client, cr.Namespace, ingress.Name, ingress) { 96 if !cr.Spec.Server.Ingress.Enabled { 97 // Ingress exists but enabled flag has been set to false, delete the Ingress 98 return r.Client.Delete(context.TODO(), ingress) 99 } 100 return nil // Ingress found and enabled, do nothing 101 } 102 103 if !cr.Spec.Server.Ingress.Enabled { 104 return nil // Ingress not enabled, move along... 105 } 106 107 // Add default annotations 108 atns := make(map[string]string) 109 atns[common.ArgoCDKeyIngressSSLRedirect] = "true" 110 atns[common.ArgoCDKeyIngressBackendProtocol] = "HTTP" 111 112 // Override default annotations if specified 113 if len(cr.Spec.Server.Ingress.Annotations) > 0 { 114 atns = cr.Spec.Server.Ingress.Annotations 115 } 116 117 ingress.ObjectMeta.Annotations = atns 118 119 ingress.Spec.IngressClassName = cr.Spec.Server.Ingress.IngressClassName 120 121 pathType := networkingv1.PathTypeImplementationSpecific 122 // Add rules 123 ingress.Spec.Rules = []networkingv1.IngressRule{ 124 { 125 Host: getArgoServerHost(cr), 126 IngressRuleValue: networkingv1.IngressRuleValue{ 127 HTTP: &networkingv1.HTTPIngressRuleValue{ 128 Paths: []networkingv1.HTTPIngressPath{ 129 { 130 Path: getPathOrDefault(cr.Spec.Server.Ingress.Path), 131 Backend: networkingv1.IngressBackend{ 132 Service: &networkingv1.IngressServiceBackend{ 133 Name: nameWithSuffix("server", cr), 134 Port: networkingv1.ServiceBackendPort{ 135 Name: "http", 136 }, 137 }, 138 }, 139 PathType: &pathType, 140 }, 141 }, 142 }, 143 }, 144 }, 145 } 146 147 // Add default TLS options 148 ingress.Spec.TLS = []networkingv1.IngressTLS{ 149 { 150 Hosts: []string{ 151 getArgoServerHost(cr), 152 }, 153 SecretName: common.ArgoCDSecretName, 154 }, 155 } 156 157 // Allow override of TLS options if specified 158 if len(cr.Spec.Server.Ingress.TLS) > 0 { 159 ingress.Spec.TLS = cr.Spec.Server.Ingress.TLS 160 } 161 162 if err := controllerutil.SetControllerReference(cr, ingress, r.Scheme); err != nil { 163 return err 164 } 165 return r.Client.Create(context.TODO(), ingress) 166 } 167 168 // reconcileArgoServerGRPCIngress will ensure that the ArgoCD Server GRPC Ingress is present. 169 func (r *ReconcileArgoCD) reconcileArgoServerGRPCIngress(cr *argoproj.ArgoCD) error { 170 ingress := newIngressWithSuffix("grpc", cr) 171 if argoutil.IsObjectFound(r.Client, cr.Namespace, ingress.Name, ingress) { 172 if !cr.Spec.Server.GRPC.Ingress.Enabled { 173 // Ingress exists but enabled flag has been set to false, delete the Ingress 174 return r.Client.Delete(context.TODO(), ingress) 175 } 176 return nil // Ingress found and enabled, do nothing 177 } 178 179 if !cr.Spec.Server.GRPC.Ingress.Enabled { 180 return nil // Ingress not enabled, move along... 181 } 182 183 // Add default annotations 184 atns := make(map[string]string) 185 atns[common.ArgoCDKeyIngressBackendProtocol] = "GRPC" 186 187 // Override default annotations if specified 188 if len(cr.Spec.Server.GRPC.Ingress.Annotations) > 0 { 189 atns = cr.Spec.Server.GRPC.Ingress.Annotations 190 } 191 192 ingress.ObjectMeta.Annotations = atns 193 194 ingress.Spec.IngressClassName = cr.Spec.Server.GRPC.Ingress.IngressClassName 195 196 pathType := networkingv1.PathTypeImplementationSpecific 197 // Add rules 198 ingress.Spec.Rules = []networkingv1.IngressRule{ 199 { 200 Host: getArgoServerGRPCHost(cr), 201 IngressRuleValue: networkingv1.IngressRuleValue{ 202 HTTP: &networkingv1.HTTPIngressRuleValue{ 203 Paths: []networkingv1.HTTPIngressPath{ 204 { 205 Path: getPathOrDefault(cr.Spec.Server.GRPC.Ingress.Path), 206 Backend: networkingv1.IngressBackend{ 207 Service: &networkingv1.IngressServiceBackend{ 208 Name: nameWithSuffix("server", cr), 209 Port: networkingv1.ServiceBackendPort{ 210 Name: "https", 211 }, 212 }, 213 }, 214 PathType: &pathType, 215 }, 216 }, 217 }, 218 }, 219 }, 220 } 221 222 // Add TLS options 223 ingress.Spec.TLS = []networkingv1.IngressTLS{ 224 { 225 Hosts: []string{ 226 getArgoServerGRPCHost(cr), 227 }, 228 SecretName: common.ArgoCDSecretName, 229 }, 230 } 231 232 // Allow override of TLS options if specified 233 if len(cr.Spec.Server.GRPC.Ingress.TLS) > 0 { 234 ingress.Spec.TLS = cr.Spec.Server.GRPC.Ingress.TLS 235 } 236 237 if err := controllerutil.SetControllerReference(cr, ingress, r.Scheme); err != nil { 238 return err 239 } 240 return r.Client.Create(context.TODO(), ingress) 241 } 242 243 // reconcileGrafanaIngress will ensure that the ArgoCD Server GRPC Ingress is present. 244 func (r *ReconcileArgoCD) reconcileGrafanaIngress(cr *argoproj.ArgoCD) error { 245 ingress := newIngressWithSuffix("grafana", cr) 246 if argoutil.IsObjectFound(r.Client, cr.Namespace, ingress.Name, ingress) { 247 if !cr.Spec.Grafana.Enabled || !cr.Spec.Grafana.Ingress.Enabled { 248 // Ingress exists but enabled flag has been set to false, delete the Ingress 249 return r.Client.Delete(context.TODO(), ingress) 250 } 251 log.Info(grafanaDeprecatedWarning) 252 return nil // Ingress found and enabled, do nothing 253 } 254 255 if !cr.Spec.Grafana.Enabled || !cr.Spec.Grafana.Ingress.Enabled { 256 return nil // Grafana itself or Ingress not enabled, move along... 257 } 258 259 log.Info(grafanaDeprecatedWarning) 260 261 return nil 262 } 263 264 // reconcilePrometheusIngress will ensure that the Prometheus Ingress is present. 265 func (r *ReconcileArgoCD) reconcilePrometheusIngress(cr *argoproj.ArgoCD) error { 266 ingress := newIngressWithSuffix("prometheus", cr) 267 if argoutil.IsObjectFound(r.Client, cr.Namespace, ingress.Name, ingress) { 268 if !cr.Spec.Prometheus.Enabled || !cr.Spec.Prometheus.Ingress.Enabled { 269 // Ingress exists but enabled flag has been set to false, delete the Ingress 270 return r.Client.Delete(context.TODO(), ingress) 271 } 272 return nil // Ingress found and enabled, do nothing 273 } 274 275 if !cr.Spec.Prometheus.Enabled || !cr.Spec.Prometheus.Ingress.Enabled { 276 return nil // Prometheus itself or Ingress not enabled, move along... 277 } 278 279 // Add default annotations 280 atns := make(map[string]string) 281 atns[common.ArgoCDKeyIngressSSLRedirect] = "true" 282 atns[common.ArgoCDKeyIngressBackendProtocol] = "HTTP" 283 284 // Override default annotations if specified 285 if len(cr.Spec.Prometheus.Ingress.Annotations) > 0 { 286 atns = cr.Spec.Prometheus.Ingress.Annotations 287 } 288 289 ingress.ObjectMeta.Annotations = atns 290 291 ingress.Spec.IngressClassName = cr.Spec.Prometheus.Ingress.IngressClassName 292 293 pathType := networkingv1.PathTypeImplementationSpecific 294 // Add rules 295 ingress.Spec.Rules = []networkingv1.IngressRule{ 296 { 297 Host: getPrometheusHost(cr), 298 IngressRuleValue: networkingv1.IngressRuleValue{ 299 HTTP: &networkingv1.HTTPIngressRuleValue{ 300 Paths: []networkingv1.HTTPIngressPath{ 301 { 302 Path: getPathOrDefault(cr.Spec.Prometheus.Ingress.Path), 303 Backend: networkingv1.IngressBackend{ 304 Service: &networkingv1.IngressServiceBackend{ 305 Name: "prometheus-operated", 306 Port: networkingv1.ServiceBackendPort{ 307 Name: "web", 308 }, 309 }, 310 }, 311 PathType: &pathType, 312 }, 313 }, 314 }, 315 }, 316 }, 317 } 318 319 // Add TLS options 320 ingress.Spec.TLS = []networkingv1.IngressTLS{ 321 { 322 Hosts: []string{cr.Name}, 323 SecretName: common.ArgoCDSecretName, 324 }, 325 } 326 327 // Allow override of TLS options if specified 328 if len(cr.Spec.Prometheus.Ingress.TLS) > 0 { 329 ingress.Spec.TLS = cr.Spec.Prometheus.Ingress.TLS 330 } 331 332 if err := controllerutil.SetControllerReference(cr, ingress, r.Scheme); err != nil { 333 return err 334 } 335 return r.Client.Create(context.TODO(), ingress) 336 } 337 338 // reconcileApplicationSetControllerIngress will ensure that the ApplicationSetController Ingress is present. 339 func (r *ReconcileArgoCD) reconcileApplicationSetControllerIngress(cr *argoproj.ArgoCD) error { 340 ingress := newIngressWithSuffix(common.ApplicationSetServiceNameSuffix, cr) 341 if argoutil.IsObjectFound(r.Client, cr.Namespace, ingress.Name, ingress) { 342 if cr.Spec.ApplicationSet == nil || !cr.Spec.ApplicationSet.WebhookServer.Ingress.Enabled { 343 return r.Client.Delete(context.TODO(), ingress) 344 } 345 return nil // Ingress found and enabled, do nothing 346 } 347 348 if cr.Spec.ApplicationSet == nil || !cr.Spec.ApplicationSet.WebhookServer.Ingress.Enabled { 349 log.Info("not enabled") 350 return nil // Ingress not enabled, move along... 351 } 352 353 // Add annotations 354 atns := make(map[string]string) 355 atns[common.ArgoCDKeyIngressSSLRedirect] = "true" 356 atns[common.ArgoCDKeyIngressBackendProtocol] = "HTTP" 357 358 // Override default annotations if specified 359 if len(cr.Spec.ApplicationSet.WebhookServer.Ingress.Annotations) > 0 { 360 atns = cr.Spec.ApplicationSet.WebhookServer.Ingress.Annotations 361 } 362 363 ingress.ObjectMeta.Annotations = atns 364 365 pathType := networkingv1.PathTypeImplementationSpecific 366 httpServerHost, err := getApplicationSetHTTPServerHost(cr) 367 if err != nil { 368 return err 369 } 370 371 // Add rules 372 ingress.Spec.Rules = []networkingv1.IngressRule{ 373 { 374 Host: httpServerHost, 375 IngressRuleValue: networkingv1.IngressRuleValue{ 376 HTTP: &networkingv1.HTTPIngressRuleValue{ 377 Paths: []networkingv1.HTTPIngressPath{ 378 { 379 Path: "/api/webhook", 380 Backend: networkingv1.IngressBackend{ 381 Service: &networkingv1.IngressServiceBackend{ 382 Name: nameWithSuffix(common.ApplicationSetServiceNameSuffix, cr), 383 Port: networkingv1.ServiceBackendPort{ 384 Name: "webhook", 385 }, 386 }, 387 }, 388 PathType: &pathType, 389 }, 390 }, 391 }, 392 }, 393 }, 394 } 395 396 // Allow override of TLS options if specified 397 if len(cr.Spec.ApplicationSet.WebhookServer.Ingress.TLS) > 0 { 398 ingress.Spec.TLS = cr.Spec.ApplicationSet.WebhookServer.Ingress.TLS 399 } 400 401 if err := controllerutil.SetControllerReference(cr, ingress, r.Scheme); err != nil { 402 return err 403 } 404 return r.Client.Create(context.TODO(), ingress) 405 }