Skip to content

Commit 319191e

Browse files
committed
gateway - Keep one Route and manage the rest via a Gateway
This change is part of an effort to re-enable the sfconfig gateway in order to give a technical solution for: - Provide a welcome page - Provide a central point for a global authentication - Provide an unique entry point for incoming http connections (logging) This gateway system can be more flexible than the Openshift Route or k8s Ingress. This change: - enables proxy path for logserver - enables the nodepool-builder log proxypass - enables the nodepool-launcher api proxypass - enables the zuul api proxypass - adds rule to redirect '/' to Zuul tenant page - cleans no longer needed Route resources Change-Id: I13541a9a40d9fbcdb0aaa986e049d38c80ca7866
1 parent 8e5b396 commit 319191e

File tree

11 files changed

+159
-38
lines changed

11 files changed

+159
-38
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
88
### Changed
99

1010
- Zookeeper version bumped to 3.8.4
11+
- The Operator handles only one Route resource as a 'gateway' pod dispatches incoming connections.
1112

1213
### Deprecated
1314
### Removed

controllers/gateway.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Copyright (C) 2024 Red Hat
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
// This package contains the git-server configuration.
5+
6+
package controllers
7+
8+
import (
9+
_ "embed"
10+
11+
"github.com/softwarefactory-project/sf-operator/controllers/libs/base"
12+
"github.com/softwarefactory-project/sf-operator/controllers/libs/utils"
13+
appsv1 "k8s.io/api/apps/v1"
14+
apiv1 "k8s.io/api/core/v1"
15+
)
16+
17+
//go:embed static/gateway/gateway.conf
18+
var gatewayConfig string
19+
20+
func (r *SFController) DeployHTTPDGateway() bool {
21+
22+
const (
23+
ident = "gateway"
24+
port = 8080
25+
)
26+
27+
srv := base.MkService(ident, r.ns, ident, []int32{port}, ident)
28+
r.GetOrCreate(&srv)
29+
30+
r.EnsureConfigMap(ident, map[string]string{
31+
"gateway.conf": gatewayConfig,
32+
})
33+
34+
annotations := map[string]string{
35+
"image": base.HTTPDImage(),
36+
"httpd-conf": utils.Checksum([]byte(gatewayConfig)),
37+
"serial": "1",
38+
}
39+
40+
dep := base.MkDeployment(ident, r.ns, base.HTTPDImage())
41+
dep.Spec.Template.ObjectMeta.Annotations = annotations
42+
dep.Spec.Template.Spec.Volumes = []apiv1.Volume{
43+
base.MkVolumeCM(ident, ident+"-config-map"),
44+
}
45+
dep.Spec.Template.Spec.Containers[0].VolumeMounts = []apiv1.VolumeMount{
46+
{
47+
Name: ident,
48+
MountPath: "/etc/httpd/conf.d/gateway.conf",
49+
ReadOnly: true,
50+
SubPath: "gateway.conf",
51+
},
52+
}
53+
54+
current := appsv1.Deployment{}
55+
if r.GetM(ident, &current) {
56+
if !utils.MapEquals(&current.Spec.Template.ObjectMeta.Annotations, &annotations) {
57+
r.log.V(1).Info("gateway configuration changed, rollout gateway pods ...")
58+
current.Spec = dep.DeepCopy().Spec
59+
r.UpdateR(&current)
60+
return false
61+
}
62+
} else {
63+
current := dep
64+
r.CreateR(&current)
65+
}
66+
67+
isDeploymentReady := r.IsDeploymentReady(&current)
68+
69+
routeReady := r.ensureHTTPSRoute(
70+
ident, r.cr.Spec.FQDN,
71+
ident, "/", port, map[string]string{}, r.cr.Spec.LetsEncrypt)
72+
73+
isReady := isDeploymentReady && routeReady
74+
75+
return isReady
76+
}

controllers/logserver.go

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -286,20 +286,12 @@ func (r *SFController) DeployLogserver() bool {
286286

287287
pvcReadiness := r.reconcileExpandPVC(logserverIdent+"-"+logserverIdent+"-0", r.cr.Spec.Logserver.Storage)
288288

289-
routeReady := r.ensureHTTPSRoute(
290-
r.cr.Name+"-logserver", r.cr.Spec.FQDN,
291-
logserverIdent, "/logs/", httpdPort, map[string]string{}, r.cr.Spec.LetsEncrypt)
292-
// The icons Route is for the mod_autoindex that build icon links such as <fqdn>/icons/back.gif
293-
iconsRouteReady := r.ensureHTTPSRoute(
294-
r.cr.Name+"-icons", r.cr.Spec.FQDN,
295-
logserverIdent, "/icons/", httpdPort, map[string]string{}, r.cr.Spec.LetsEncrypt)
296-
297289
// TODO(mhu) We may want to open an ingress to port 9100 for an external prometheus instance.
298290
// TODO(mhu) we may want to include monitoring objects' status in readiness computation
299291
r.ensureLogserverPodMonitor()
300292
r.ensureLogserverPromRule()
301293

302-
isReady := r.IsStatefulSetReady(current) && !stsUpdated && pvcReadiness && routeReady && iconsRouteReady
294+
isReady := r.IsStatefulSetReady(current) && !stsUpdated && pvcReadiness
303295
conds.UpdateConditions(&r.cr.Status.Conditions, logserverIdent, isReady)
304296

305297
return isReady

controllers/nodepool.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -636,10 +636,7 @@ func (r *SFController) DeployNodepoolBuilder(statsdExporterVolume apiv1.Volume,
636636

637637
pvcReadiness := r.reconcileExpandPVC(BuilderIdent+"-"+BuilderIdent+"-0", r.cr.Spec.Nodepool.Builder.Storage)
638638

639-
routeReady := r.ensureHTTPSRoute(r.cr.Name+"-nodepool-builder", r.cr.Spec.FQDN, BuilderIdent, "/nodepool/builds/",
640-
buildLogsHttpdPort, map[string]string{}, r.cr.Spec.LetsEncrypt)
641-
642-
var isReady = r.IsStatefulSetReady(current) && routeReady && pvcReadiness
639+
var isReady = r.IsStatefulSetReady(current) && pvcReadiness
643640

644641
conds.UpdateConditions(&r.cr.Status.Conditions, BuilderIdent, isReady)
645642

@@ -797,15 +794,10 @@ func (r *SFController) DeployNodepoolLauncher(statsdExporterVolume apiv1.Volume,
797794
srv := base.MkService(LauncherIdent, r.ns, LauncherIdent, []int32{launcherPort}, LauncherIdent)
798795
r.GetOrCreate(&srv)
799796

800-
routeReady := r.ensureHTTPSRoute(r.cr.Name+"-nodepool-launcher", r.cr.Spec.FQDN, LauncherIdent, "/nodepool/api",
801-
launcherPort, map[string]string{
802-
"haproxy.router.openshift.io/rewrite-target": "/",
803-
}, r.cr.Spec.LetsEncrypt)
804-
805797
isDeploymentReady := r.IsDeploymentReady(&current)
806798
conds.UpdateConditions(&r.cr.Status.Conditions, LauncherIdent, isDeploymentReady)
807799

808-
return isDeploymentReady && routeReady
800+
return isDeploymentReady
809801
}
810802

811803
func (r *SFController) DeployNodepool() map[string]bool {

controllers/softwarefactory_controller.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,41 @@ func (r *SFController) cleanup() {
141141
if r.GetM("zookeeper-headless", &currentZKHeadlessSVC) {
142142
r.DeleteR(&currentZKHeadlessSVC)
143143
}
144+
// remove a legacy Route definition for logserver
145+
r.DeleteR(&apiroutev1.Route{
146+
ObjectMeta: metav1.ObjectMeta{
147+
Namespace: r.ns,
148+
Name: r.cr.Name + "-logserver",
149+
},
150+
})
151+
// remove a legacy Route definition for icons path
152+
r.DeleteR(&apiroutev1.Route{
153+
ObjectMeta: metav1.ObjectMeta{
154+
Namespace: r.ns,
155+
Name: r.cr.Name + "-icons",
156+
},
157+
})
158+
// remove a legacy Route definition for nodepool-builder
159+
r.DeleteR(&apiroutev1.Route{
160+
ObjectMeta: metav1.ObjectMeta{
161+
Namespace: r.ns,
162+
Name: r.cr.Name + "-nodepool-builder",
163+
},
164+
})
165+
// remove a legacy Route definition for nodepool-launcher
166+
r.DeleteR(&apiroutev1.Route{
167+
ObjectMeta: metav1.ObjectMeta{
168+
Namespace: r.ns,
169+
Name: r.cr.Name + "-nodepool-launcher",
170+
},
171+
})
172+
// remove a legacy Route definition for zuul
173+
r.DeleteR(&apiroutev1.Route{
174+
ObjectMeta: metav1.ObjectMeta{
175+
Namespace: r.ns,
176+
Name: r.cr.Name + "-zuul",
177+
},
178+
})
144179
}
145180

146181
func (r *SFController) validateZuulConnectionsSecrets() error {
@@ -283,6 +318,8 @@ func (r *SFController) deploySFStep(services map[string]bool) map[string]bool {
283318
}
284319
}
285320

321+
services["Gateway"] = r.DeployHTTPDGateway()
322+
286323
podMonitorSelector := metav1.LabelSelector{
287324
MatchLabels: map[string]string{
288325
"app": "sf",
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# LogLevel alert proxy:trace6
2+
3+
<IfModule mod_proxy.c>
4+
ProxyVia On
5+
ProxyRequests Off
6+
7+
# Redirect root requests to Zuul web
8+
ProxyPassMatch "^/?$" "http://zuul-web:9000/" retry=0
9+
10+
# Handle logserver requests
11+
ProxyPassMatch "^/logs$" "http://logserver:8080/" retry=0
12+
ProxyPassMatch "^/logs/(.*)$" "http://logserver:8080/logs/$1" retry=0
13+
ProxyPassReverse /logs http://logserver:8080/logs
14+
15+
# Handle nodepool build logs requests
16+
ProxyPassMatch "^/nodepool/builds$" "http://nodepool-builder:8080/" retry=0
17+
ProxyPassMatch "^/nodepool/builds/(.*)$" "http://nodepool-builder:8080/nodepool/builds/$1" retry=0
18+
ProxyPassReverse /nodepool/builds http://nodepool-builder:8080/nodepool/builds
19+
20+
# Handle nodepool API requests
21+
ProxyPassMatch "^/nodepool/api/(.*)$" "http://nodepool-launcher:8006/$1" retry=0
22+
ProxyPassReverse /nodepool/api http://nodepool-launcher:8006/
23+
24+
# Handle Zuul requests
25+
ProxyPassMatch "^/zuul/api/tenant/(.*)/console-stream$" "ws://zuul-web:9000/api/tenant/$1/console-stream" retry=0
26+
ProxyPassMatch "^/zuul$" "http://zuul-web:9000/" retry=0
27+
ProxyPassMatch "^/zuul/(.*)$" "http://zuul-web:9000/$1" retry=0
28+
ProxyPassReverse /zuul http://zuul-web:9000/
29+
</IfModule>

controllers/zuul.go

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,7 +1272,7 @@ func (r *SFController) DeployZuulSecrets() {
12721272
}
12731273

12741274
func (r *SFController) DeployZuul() bool {
1275-
return r.EnsureZuulComponents() && r.setupZuulIngress()
1275+
return r.EnsureZuulComponents()
12761276
}
12771277

12781278
func (r *SFController) runZuulInternalTenantReconfigure() bool {
@@ -1282,12 +1282,3 @@ func (r *SFController) runZuulInternalTenantReconfigure() bool {
12821282
[]string{"zuul-scheduler", "tenant-reconfigure", "internal"})
12831283
return err == nil
12841284
}
1285-
1286-
func (r *SFController) setupZuulIngress() bool {
1287-
route1Ready := r.ensureHTTPSRoute(r.cr.Name+"-zuul", r.cr.Spec.FQDN, "zuul-web", "/zuul", zuulWEBPort,
1288-
map[string]string{
1289-
"haproxy.router.openshift.io/rewrite-target": "/",
1290-
}, r.cr.Spec.LetsEncrypt)
1291-
1292-
return route1Ready
1293-
}

doc/deployment/getting_started.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ The `sf-operator` handles the `Route`s installation. Here is the lists of availa
6666
endpoints:
6767

6868
- https://sfop.me/zuul
69-
- https://sfop.me/logs/
69+
- https://sfop.me/logs
7070
- https://sfop.me/nodepool/api/image-list
71-
- https://sfop.me/nodepool/builds/
71+
- https://sfop.me/nodepool/builds
7272

7373
At that point you have successfully deployed a **SoftwareFactory** instance. You can access the Zuul Web UI at https://sfop.me/zuul.
7474

doc/developer/getting_started.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,11 @@ To iterate on the development of the `sf-operator` you can either start the oper
9090
=== "manager mode"
9191

9292
First, apply the `SoftwareFactory`'s `CR`:
93-
93+
9494
```sh
9595
kubectl apply -f playbooks/files/sf.yaml
9696
```
97-
97+
9898
then run the operator with the following command:
9999

100100
```sh
@@ -129,9 +129,9 @@ You can verify that the services are properly exposed with Firefox (you may have
129129

130130
```sh
131131
firefox https://<FQDN>/zuul
132-
firefox https://<FQDN>/logs/
132+
firefox https://<FQDN>/logs
133133
firefox https://<FQDN>/nodepool/api/image-list
134-
firefox https://<FQDN>/nodepool/builds/
134+
firefox https://<FQDN>/nodepool/builds
135135
firefox https://gerrit.<FQDN>
136136
```
137137

roles/health-check/check-service-uri/tasks/main.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969

7070
- name: Attempt to access Logserver web
7171
ansible.builtin.uri:
72-
url: "https://{{ logserver_endpoint }}/"
72+
url: "https://{{ logserver_endpoint }}"
7373
method: GET
7474
return_content: true
7575
validate_certs: "{{ validate_certs }}"
@@ -95,7 +95,7 @@
9595

9696
- name: Attempt to access Nodepool builder build logs
9797
ansible.builtin.uri:
98-
url: "https://{{ nodepool_endpoint }}/builds/"
98+
url: "https://{{ nodepool_endpoint }}/builds"
9999
method: GET
100100
return_content: true
101101
validate_certs: "{{ validate_certs }}"

roles/health-check/repo-submit-change/tasks/ensure-zuul-console-success.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
ansible.builtin.shell: |
55
curl -sk https://{{ zuul_endpoint }}/api/tenant/{{ zuul_tenant }}/status | jq -r '.pipelines[].change_queues[].heads[][].jobs[]' | jq -rc 'select(.name == "{{ success_job }}")' | jq -r '.uuid'
66
register: _job_uuid
7-
until: _job_uuid.stdout != "" and "null" not in _job_uuid.stdout
7+
until:
8+
- _job_uuid.stdout != ""
9+
- "'null' not in _job_uuid.stdout"
10+
- "'parse error' not in _job_uuid.stdout"
811
retries: "{{ zuul_api_retries }}"
912
delay: "{{ zuul_api_delay }}"
1013
tags:

0 commit comments

Comments
 (0)