Skip to content

Commit a7d81c2

Browse files
committed
Fix #31108: support additional fqdns
1 parent 58bac9c commit a7d81c2

4 files changed

Lines changed: 132 additions & 7 deletions

File tree

src/main/kotlin/eu/openanalytics/shinyproxyoperator/components/IngressFactory.kt

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import eu.openanalytics.shinyproxyoperator.crd.ShinyProxyInstance
2525
import io.fabric8.kubernetes.api.model.networking.v1.HTTPIngressPath
2626
import io.fabric8.kubernetes.api.model.networking.v1.HTTPIngressPathBuilder
2727
import io.fabric8.kubernetes.api.model.networking.v1.IngressBuilder
28+
import io.fabric8.kubernetes.api.model.networking.v1.IngressRule
29+
import io.fabric8.kubernetes.api.model.networking.v1.IngressRuleBuilder
2830
import io.fabric8.kubernetes.client.KubernetesClient
2931
import mu.KotlinLogging
3032

@@ -37,7 +39,18 @@ class IngressFactory(private val kubeClient: KubernetesClient) {
3739
fun create(shinyProxy: ShinyProxy, latestShinyProxyInstance: ShinyProxyInstance) {
3840
val labels = LabelFactory.labelsForShinyProxy(shinyProxy).toMutableMap()
3941
labels[LabelFactory.LATEST_INSTANCE_LABEL] = latestShinyProxyInstance.hashOfSpec
42+
4043
//@formatter:off
44+
val fqdns = listOf(shinyProxy.fqdn) + shinyProxy.additionalFqdns
45+
val rules = fqdns.map { host ->
46+
IngressRuleBuilder()
47+
.withHost(host)
48+
.withNewHttp()
49+
.addToPaths(createPathV1(shinyProxy))
50+
.endHttp()
51+
.build()
52+
}
53+
4154
val ingressDefinition = IngressBuilder()
4255
.withNewMetadata()
4356
.withName(ResourceNameFactory.createNameForIngress(shinyProxy))
@@ -52,12 +65,7 @@ class IngressFactory(private val kubeClient: KubernetesClient) {
5265
.endMetadata()
5366
.withNewSpec()
5467
.withIngressClassName("nginx")
55-
.addNewRule()
56-
.withHost(shinyProxy.fqdn)
57-
.withNewHttp()
58-
.addToPaths(createPathV1(shinyProxy))
59-
.endHttp()
60-
.endRule()
68+
.withRules(rules)
6169
.endSpec()
6270
.build()
6371
//@formatter:on

src/main/kotlin/eu/openanalytics/shinyproxyoperator/crd/ShinyProxy.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ class ShinyProxy : CustomResource<JsonNode, ShinyProxyStatus>(), Namespaced {
4141
return ShinyProxyStatus()
4242
}
4343

44-
4544
@get:JsonIgnore
4645
val image: String by lazy {
4746
if (spec.get("image")?.isTextual == true) {
@@ -66,6 +65,14 @@ class ShinyProxy : CustomResource<JsonNode, ShinyProxyStatus>(), Namespaced {
6665
throw IllegalStateException("Cannot create ShinyProxy instance when no FQDN is specified!")
6766
}
6867

68+
@get:JsonIgnore
69+
val additionalFqdns: List<String> by lazy {
70+
if (spec.get("additionalFqdns")?.isArray == true) {
71+
return@lazy spec.get("additionalFqdns").elements().asSequence().map { it.textValue() }.toList();
72+
}
73+
return@lazy listOf()
74+
}
75+
6976
@get:JsonIgnore
7077
val replicas: Int by lazy {
7178
if (spec.get("replicas")?.isInt == true) {

src/test/kotlin/eu/openanalytics/shinyproxyoperator/MainIntegrationTest.kt

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,5 +1060,79 @@ class MainIntegrationTest : IntegrationTestBase() {
10601060
job.cancel()
10611061
}
10621062

1063+
@Test
1064+
fun `test additional fqns`() =
1065+
setup(Mode.NAMESPACED) { namespace, shinyProxyClient, namespacedClient, _, operator, reconcileListener, _ ->
1066+
// 1. create a SP instance
1067+
val spTestInstance = ShinyProxyTestInstance(
1068+
namespace,
1069+
namespacedClient,
1070+
shinyProxyClient,
1071+
"additional_fqdns.yaml",
1072+
reconcileListener
1073+
)
1074+
spTestInstance.create()
1075+
1076+
val (resourceRetriever, shinyProxyLister) = operator.prepare()
1077+
// 2. start the operator and let it do it's work
1078+
val job = GlobalScope.launch {
1079+
operator.run(resourceRetriever, shinyProxyLister)
1080+
}
1081+
1082+
// 3. wait until instance is created
1083+
spTestInstance.waitForOneReconcile()
1084+
1085+
// 4. assert correctness
1086+
val sp = spTestInstance.retrieveInstance()
1087+
assertNotNull(sp)
1088+
val instance = sp.status.instances[0]
1089+
assertNotNull(instance)
1090+
assertTrue(instance.isLatestInstance)
1091+
1092+
// check configmap
1093+
spTestInstance.assertConfigMapIsCorrect(sp)
1094+
1095+
// check replicaset
1096+
spTestInstance.assertReplicaSetIsCorrect(sp)
1097+
1098+
// check service
1099+
spTestInstance.assertServiceIsCorrect(spTestInstance.retrieveInstance())
1100+
1101+
// check ingress
1102+
val allIngresses = namespacedClient.network().v1().ingresses().list().items
1103+
assertEquals(1, allIngresses.size)
1104+
val ingress = allIngresses.firstOrNull { it.metadata.name == "sp-${sp.metadata.name}-ing".take(63) }
1105+
assertNotNull(ingress)
1106+
1107+
assertEquals(mapOf(
1108+
LabelFactory.APP_LABEL to LabelFactory.APP_LABEL_VALUE,
1109+
LabelFactory.REALM_ID_LABEL to sp.realmId,
1110+
LabelFactory.LATEST_INSTANCE_LABEL to sp.status.latestInstance()!!.hashOfSpec
1111+
), ingress.metadata.labels)
1112+
1113+
assertEquals(2, ingress.spec.rules.size)
1114+
val rule1 = ingress.spec.rules[0]
1115+
assertNotNull(rule1)
1116+
assertEquals(sp.fqdn, rule1.host)
1117+
assertEquals(1, rule1.http.paths.size)
1118+
val path1 = rule1.http.paths[0]
1119+
assertNotNull(path1)
1120+
assertEquals(sp.subPath, path1.path)
1121+
assertEquals("sp-${sp.metadata.name}-svc".take(63), path1.backend.service.name)
1122+
assertEquals(80, path1.backend.service.port.number)
1123+
1124+
val rule2 = ingress.spec.rules[1]
1125+
assertNotNull(rule2)
1126+
assertEquals(sp.additionalFqdns[0], rule2.host)
1127+
assertEquals(1, rule2.http.paths.size)
1128+
val path2 = rule2.http.paths[0]
1129+
assertNotNull(path2)
1130+
assertEquals(sp.subPath, path2.path)
1131+
assertEquals("sp-${sp.metadata.name}-svc".take(63), path2.backend.service.name)
1132+
assertEquals(80, path2.backend.service.port.number)
1133+
1134+
job.cancel()
1135+
}
1136+
10631137

10641138
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
apiVersion: openanalytics.eu/v1
2+
kind: ShinyProxy
3+
metadata:
4+
name: example-shinyproxy
5+
spec:
6+
fqdn: itest.local
7+
additionalFqdns:
8+
- itest2.locals
9+
image: openanalytics/shinyproxy:2.6.1
10+
proxy:
11+
title: Open Analytics Shiny Proxy
12+
logoUrl: http://www.openanalytics.eu/sites/www.openanalytics.eu/themes/oa/logo.png
13+
landingPage: /
14+
heartbeatRate: 10000
15+
heartbeatTimeout: 60000
16+
port: 8080
17+
authentication: simple
18+
containerBackend: kubernetes
19+
kubernetes:
20+
namespace: itest
21+
users:
22+
- name: demo
23+
password: demo
24+
groups: scientists
25+
- name: demo2
26+
password: demo2
27+
groups: mathematicians
28+
specs:
29+
- id: 01_hello
30+
displayName: Hello Application
31+
description: Application which demonstrates the basics of a Shiny app
32+
containerCmd: [ "R", "-e", "shinyproxy::run_01_hello()" ]
33+
containerImage: openanalytics/shinyproxy-demo
34+
- id: 06_tabsets
35+
container-cmd: [ "R", "-e", "shinyproxy::run_06_tabsets()" ]
36+
container-image: openanalytics/shinyproxy-demo

0 commit comments

Comments
 (0)