Skip to content

Commit eae8434

Browse files
committed
Ref #29480: do not update ingress
1 parent 0052227 commit eae8434

10 files changed

Lines changed: 135 additions & 162 deletions

File tree

src/main/kotlin/eu/openanalytics/shinyproxyoperator/Operator.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import eu.openanalytics.shinyproxyoperator.controller.ShinyProxyController
3131
import eu.openanalytics.shinyproxyoperator.controller.ShinyProxyEvent
3232
import eu.openanalytics.shinyproxyoperator.controller.ShinyProxyListener
3333
import eu.openanalytics.shinyproxyoperator.crd.ShinyProxy
34-
import eu.openanalytics.shinyproxyoperator.controller.IngressController
34+
import eu.openanalytics.shinyproxyoperator.controller.ServiceController
3535
import io.fabric8.kubernetes.api.model.ConfigMap
3636
import io.fabric8.kubernetes.api.model.ConfigMapList
3737
import io.fabric8.kubernetes.api.model.Service
@@ -89,7 +89,7 @@ class Operator(client: NamespacedKubernetesClient? = null,
8989
private val serviceListener: ResourceListener<Service, ServiceList, ServiceResource<Service>>
9090
private val configMapListener: ResourceListener<ConfigMap, ConfigMapList, Resource<ConfigMap>>
9191
private val ingressListener: ResourceListener<Ingress, IngressList, Resource<Ingress>>
92-
private val ingressController: IngressController
92+
private val serviceController: ServiceController
9393

9494
private val channel = Channel<ShinyProxyEvent>(10000)
9595
val sendChannel: SendChannel<ShinyProxyEvent> = channel // public for tests
@@ -159,20 +159,20 @@ class Operator(client: NamespacedKubernetesClient? = null,
159159
serviceListener = ResourceListener(sendChannel, this.client.inAnyNamespace().services())
160160
configMapListener = ResourceListener(sendChannel, this.client.inAnyNamespace().configMaps())
161161
ingressListener = ResourceListener(sendChannel, this.client.inAnyNamespace().network().v1().ingresses())
162-
ingressController = IngressController(this.client.inAnyNamespace().network().v1().ingresses())
162+
serviceController = ServiceController(this.client.inAnyNamespace().services())
163163
} else {
164164
replicaSetListener = ResourceListener(sendChannel, this.client.inNamespace(namespace).apps().replicaSets())
165165
serviceListener = ResourceListener(sendChannel, this.client.inNamespace(namespace).services())
166166
configMapListener = ResourceListener(sendChannel, this.client.inNamespace(namespace).configMaps())
167167
ingressListener = ResourceListener(sendChannel, this.client.inNamespace(namespace).network().v1().ingresses())
168-
ingressController = IngressController(this.client.inNamespace(namespace).network().v1().ingresses())
168+
serviceController = ServiceController(this.client.inNamespace(namespace).services())
169169
}
170170
}
171171

172172
/**
173173
* Controllers
174174
*/
175-
val shinyProxyController = ShinyProxyController(channel, this.client, shinyProxyClient, ingressController, reconcileListener, this.recyclableChecker)
175+
val shinyProxyController = ShinyProxyController(channel, this.client, shinyProxyClient, serviceController, reconcileListener, this.recyclableChecker)
176176

177177
private fun _checkCrdExists(name: String, shortName: String) {
178178
try {

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

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,32 +21,24 @@
2121
package eu.openanalytics.shinyproxyoperator.components
2222

2323
import eu.openanalytics.shinyproxyoperator.crd.ShinyProxy
24-
import eu.openanalytics.shinyproxyoperator.crd.ShinyProxyInstance
2524
import io.fabric8.kubernetes.api.model.networking.v1.HTTPIngressPath
2625
import io.fabric8.kubernetes.api.model.networking.v1.HTTPIngressPathBuilder
27-
import io.fabric8.kubernetes.api.model.networking.v1.Ingress
2826
import io.fabric8.kubernetes.api.model.networking.v1.IngressBuilder
29-
import io.fabric8.kubernetes.api.model.networking.v1.IngressList
30-
import io.fabric8.kubernetes.client.dsl.MixedOperation
31-
import io.fabric8.kubernetes.client.dsl.Resource
27+
import io.fabric8.kubernetes.client.KubernetesClient
3228
import mu.KotlinLogging
3329

34-
class IngressFactory(private val kubeClient: MixedOperation<Ingress, IngressList, Resource<Ingress>>) {
30+
class IngressFactory(private val kubeClient: KubernetesClient) {
3531

3632
private val logger = KotlinLogging.logger {}
3733

3834
private val ingressPatcher = IngressPatcher()
3935

40-
fun createOrReplaceIngress(shinyProxy: ShinyProxy, latestInstance: ShinyProxyInstance) {
41-
val labels = LabelFactory.labelsForShinyProxy(shinyProxy).toMutableMap()
42-
labels[LabelFactory.LATEST_INSTANCE_LABEL] = latestInstance.hashOfSpec
43-
labels[LabelFactory.INSTANCE_LABEL] = latestInstance.hashOfSpec
44-
36+
fun create(shinyProxy: ShinyProxy) {
4537
//@formatter:off
4638
val ingressDefinition = IngressBuilder()
4739
.withNewMetadata()
4840
.withName(ResourceNameFactory.createNameForIngress(shinyProxy))
49-
.withLabels<String, String>(labels)
41+
.withLabels<String, String>(LabelFactory.labelsForShinyProxy(shinyProxy))
5042
.addNewOwnerReference()
5143
.withController(true)
5244
.withKind("ShinyProxy")
@@ -56,41 +48,30 @@ class IngressFactory(private val kubeClient: MixedOperation<Ingress, IngressList
5648
.endOwnerReference()
5749
.endMetadata()
5850
.withNewSpec()
59-
.withIngressClassName("nginx")
51+
.withIngressClassName("nginx") // TODO
6052
.addNewRule()
6153
.withHost(shinyProxy.fqdn)
6254
.withNewHttp()
63-
.addAllToPaths(createPaths(shinyProxy, latestInstance))
55+
.addToPaths(createPathV1(shinyProxy))
6456
.endHttp()
6557
.endRule()
6658
.endSpec()
6759
.build()
6860
//@formatter:on
6961

7062
val patchedIngress = ingressPatcher.patch(ingressDefinition, shinyProxy.parsedIngressPatches)
71-
val createdIngress = kubeClient.inNamespace(shinyProxy.metadata.namespace).resource(patchedIngress).createOrReplace()
63+
val createdIngress = kubeClient.network().v1().ingresses().inNamespace(shinyProxy.metadata.namespace).resource(patchedIngress).createOrReplace()
7264
logger.debug { "${shinyProxy.logPrefix()} [Component/Ingress] Created ${createdIngress.metadata.name}" }
7365
}
7466

75-
private fun createPaths(shinyProxy: ShinyProxy, latestInstance: ShinyProxyInstance): ArrayList<HTTPIngressPath> {
76-
val res = arrayListOf(createPathV1(shinyProxy, shinyProxy.subPath, latestInstance))
77-
78-
for (instance in shinyProxy.status.instances) {
79-
val path = shinyProxy.subPath + instance.hashOfSpec + "/"
80-
res.add(createPathV1(shinyProxy, path, instance))
81-
}
82-
83-
return res
84-
}
85-
86-
private fun createPathV1(shinyProxy: ShinyProxy, path: String, shinyProxyInstance: ShinyProxyInstance): HTTPIngressPath {
67+
private fun createPathV1(shinyProxy: ShinyProxy): HTTPIngressPath {
8768
//@formatter:off
8869
val builder = HTTPIngressPathBuilder()
8970
.withPathType("Prefix")
90-
.withPath(path)
71+
.withPath(shinyProxy.subPath)
9172
.withNewBackend()
9273
.withNewService()
93-
.withName(ResourceNameFactory.createNameForService(shinyProxy, shinyProxyInstance))
74+
.withName(ResourceNameFactory.createNameForService(shinyProxy))
9475
.withNewPort()
9576
.withNumber(80)
9677
.endPort()

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,8 @@ import mu.KotlinLogging
2626

2727
object ResourceNameFactory {
2828

29-
private val logger = KotlinLogging.logger {}
30-
3129
const val KUBE_RESOURCE_NAME_MAX_LENGTH = 63
3230

33-
fun createNameForService(shinyProxy: ShinyProxy, shinyProxyInstance: ShinyProxyInstance): String {
34-
return "sp-${shinyProxy.metadata.name}-svc-${shinyProxyInstance.hashOfSpec}".take(KUBE_RESOURCE_NAME_MAX_LENGTH)
35-
}
36-
3731
fun createNameForConfigMap(shinyProxy: ShinyProxy, shinyProxyInstance: ShinyProxyInstance): String {
3832
return "sp-${shinyProxy.metadata.name}-cm-${shinyProxyInstance.hashOfSpec}".take(KUBE_RESOURCE_NAME_MAX_LENGTH)
3933
}
@@ -46,6 +40,10 @@ object ResourceNameFactory {
4640
return "sp-${shinyProxy.metadata.name}-rs-${shinyProxyInstance.hashOfSpec}".take(KUBE_RESOURCE_NAME_MAX_LENGTH)
4741
}
4842

43+
fun createNameForService(shinyProxy: ShinyProxy): String {
44+
return "sp-${shinyProxy.metadata.name}-svc".take(KUBE_RESOURCE_NAME_MAX_LENGTH)
45+
}
46+
4947
fun createNameForIngress(shinyProxy: ShinyProxy): String {
5048
return "sp-${shinyProxy.metadata.name}-ing".take(KUBE_RESOURCE_NAME_MAX_LENGTH)
5149
}

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

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,25 @@ import eu.openanalytics.shinyproxyoperator.crd.ShinyProxyInstance
2525
import io.fabric8.kubernetes.api.model.IntOrString
2626
import io.fabric8.kubernetes.api.model.Service
2727
import io.fabric8.kubernetes.api.model.ServiceBuilder
28-
import io.fabric8.kubernetes.client.KubernetesClient
28+
import io.fabric8.kubernetes.api.model.ServiceList
29+
import io.fabric8.kubernetes.client.dsl.MixedOperation
30+
import io.fabric8.kubernetes.client.dsl.ServiceResource
2931
import mu.KotlinLogging
3032

31-
class ServiceFactory(private val kubeClient: KubernetesClient) {
33+
class ServiceFactory(private val serviceClient: MixedOperation<Service, ServiceList, ServiceResource<Service>>) {
3234

3335
private val logger = KotlinLogging.logger {}
3436

35-
fun create(shinyProxy: ShinyProxy, shinyProxyInstance: ShinyProxyInstance) {
37+
fun create(shinyProxy: ShinyProxy, latestShinyProxyInstance: ShinyProxyInstance) {
38+
val labels = LabelFactory.labelsForShinyProxy(shinyProxy).toMutableMap()
39+
labels[LabelFactory.LATEST_INSTANCE_LABEL] = latestShinyProxyInstance.hashOfSpec
40+
3641
//@formatter:off
3742
val serviceDefinition: Service = ServiceBuilder()
3843
.withNewMetadata()
39-
.withName(ResourceNameFactory.createNameForService(shinyProxy, shinyProxyInstance))
44+
.withName(ResourceNameFactory.createNameForService(shinyProxy))
4045
.withNamespace(shinyProxy.metadata.namespace)
41-
.withLabels<String, String>(LabelFactory.labelsForShinyProxyInstance(shinyProxy, shinyProxyInstance))
46+
.withLabels<String, String>(labels)
4247
.addNewOwnerReference()
4348
.withController(true)
4449
.withKind("ShinyProxy")
@@ -53,13 +58,13 @@ class ServiceFactory(private val kubeClient: KubernetesClient) {
5358
.withPort(80)
5459
.withTargetPort(IntOrString(8080))
5560
.endPort()
56-
.withSelector<String, String>(LabelFactory.labelsForShinyProxyInstance(shinyProxy, shinyProxyInstance))
61+
.withSelector<String, String>(LabelFactory.labelsForShinyProxyInstance(shinyProxy, latestShinyProxyInstance))
5762
.endSpec()
5863
.build()
5964
//@formatter:on
6065

61-
val createdService = kubeClient.services().inNamespace(shinyProxy.metadata.namespace).createOrReplace(serviceDefinition)
62-
logger.debug { "${shinyProxy.logPrefix(shinyProxyInstance)} [Component/Service] Created ${createdService.metadata.name}" }
66+
val createdService = serviceClient.inNamespace(shinyProxy.metadata.namespace).resource(serviceDefinition).createOrReplace()
67+
logger.debug { "${shinyProxy.logPrefix(latestShinyProxyInstance)} [Component/Service] Created ${createdService.metadata.name}" }
6368
}
6469

6570
}

src/main/kotlin/eu/openanalytics/shinyproxyoperator/controller/ResourceListener.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,8 @@ class ResourceListener<T : HasMetadata, L : KubernetesResourceList<T>, R : Resou
7272
val shinyProxy = shinyProxyLister.namespace(resource.metadata.namespace)[ownerReference.name] ?: return
7373
if (!isInManagedNamespace(shinyProxy)) return
7474
val hashOfInstance = resource.metadata.labels[LabelFactory.INSTANCE_LABEL]
75-
if (hashOfInstance == null) {
76-
logger.warn { "[${resource.kind}] [${resource.metadata.namespace}/${resource.metadata.name}] Cannot find hash of instance for this resource - probably the resource is being deleted" }
77-
return
78-
}
75+
?: shinyProxy.status.latestInstance()?.hashOfSpec
76+
?: return
7977

8078
val shinyProxyInstance = shinyProxy.status.getInstanceByHash(hashOfInstance)
8179
if (shinyProxyInstance == null) {

src/main/kotlin/eu/openanalytics/shinyproxyoperator/controller/IngressController.kt renamed to src/main/kotlin/eu/openanalytics/shinyproxyoperator/controller/ServiceController.kt

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,52 +23,47 @@ package eu.openanalytics.shinyproxyoperator.controller
2323
import eu.openanalytics.shinyproxyoperator.components.LabelFactory
2424
import eu.openanalytics.shinyproxyoperator.crd.ShinyProxy
2525
import eu.openanalytics.shinyproxyoperator.crd.ShinyProxyInstance
26-
import eu.openanalytics.shinyproxyoperator.components.IngressFactory
26+
import eu.openanalytics.shinyproxyoperator.components.ServiceFactory
27+
import io.fabric8.kubernetes.api.model.Service
28+
import io.fabric8.kubernetes.api.model.ServiceList
2729
import io.fabric8.kubernetes.api.model.apps.ReplicaSet
28-
import io.fabric8.kubernetes.api.model.networking.v1.Ingress
29-
import io.fabric8.kubernetes.api.model.networking.v1.IngressList
3030
import io.fabric8.kubernetes.client.dsl.MixedOperation
31-
import io.fabric8.kubernetes.client.dsl.Resource
31+
import io.fabric8.kubernetes.client.dsl.ServiceResource
3232
import io.fabric8.kubernetes.client.readiness.Readiness
3333
import mu.KotlinLogging
3434

35-
class IngressController(
36-
ingressClient: MixedOperation<Ingress, IngressList, Resource<Ingress>>
35+
class ServiceController(
36+
serviceClient: MixedOperation<Service, ServiceList, ServiceResource<Service>>
3737
) {
3838

3939
private val logger = KotlinLogging.logger {}
40-
private val ingressFactory = IngressFactory(ingressClient)
40+
private val serviceFactory = ServiceFactory(serviceClient)
4141

4242
fun reconcile(resourceRetriever: ResourceRetriever, shinyProxy: ShinyProxy) {
4343
reconcileLatestInstance(resourceRetriever, shinyProxy)
4444
}
4545

46-
fun onRemoveInstance(resourceRetriever: ResourceRetriever, shinyProxy: ShinyProxy, shinyProxyInstance: ShinyProxyInstance) {
47-
reconcileLatestInstance(resourceRetriever, shinyProxy)
48-
}
49-
5046
private fun reconcileLatestInstance(resourceRetriever: ResourceRetriever, shinyProxy: ShinyProxy) {
5147
val latestInstance = shinyProxy.status.latestInstance() ?: return
5248

53-
val ingresses = resourceRetriever.getIngressByLabels(LabelFactory.labelsForShinyProxy(shinyProxy), shinyProxy.metadata.namespace)
54-
val mustBeUpdated = ingresses.isEmpty()
55-
|| ingresses[0].metadata?.labels?.get(LabelFactory.LATEST_INSTANCE_LABEL) != latestInstance.hashOfSpec
56-
|| ingresses[0].spec?.rules?.get(0)?.http?.paths?.size != shinyProxy.status.instances.size + 1
49+
val services = resourceRetriever.getServiceByLabels(LabelFactory.labelsForShinyProxy(shinyProxy), shinyProxy.metadata.namespace)
50+
val mustBeUpdated = services.isEmpty()
51+
|| services[0].metadata?.labels?.get(LabelFactory.LATEST_INSTANCE_LABEL) != latestInstance.hashOfSpec
5752

5853
if (mustBeUpdated) {
5954
val replicaSet = getReplicaSet(resourceRetriever, shinyProxy, latestInstance)
6055
if (replicaSet == null) {
61-
logger.warn { "${shinyProxy.logPrefix(latestInstance)} [Component/Ingress] Cannot reconcile Ingress since it has no ReplicaSet - probably this resource is being deleted" }
56+
logger.warn { "${shinyProxy.logPrefix(latestInstance)} [Component/Service] Cannot reconcile Service since it has no ReplicaSet - probably this resource is being deleted" }
6257
return
6358
}
6459
if (!Readiness.getInstance().isReady(replicaSet)) {
65-
logger.warn { "${shinyProxy.logPrefix(latestInstance)} [Component/Ingress] Cannot reconcile Ingress since the corresponding ReplicaSet is not ready yet - it is probably being created" }
60+
logger.warn { "${shinyProxy.logPrefix(latestInstance)} [Component/Service] Cannot reconcile Service since the corresponding ReplicaSet is not ready yet - it is probably being created" }
6661
return
6762
}
6863
// ReplicaSet exists and is ready -> time to create ingress
6964
// By only creating the ingress now, we ensure no 502 bad gateways are generated
70-
logger.debug { "${shinyProxy.logPrefix(latestInstance)} [Component/Ingress] Reconciling" }
71-
ingressFactory.createOrReplaceIngress(shinyProxy, latestInstance)
65+
logger.debug { "${shinyProxy.logPrefix(latestInstance)} [Component/Service] Reconciling" }
66+
serviceFactory.create(shinyProxy, latestInstance)
7267
}
7368
}
7469

0 commit comments

Comments
 (0)