package io.radanalytics.operator; import io.fabric8.kubernetes.api.model.*; import io.fabric8.kubernetes.api.model.extensions.HTTPIngressPathBuilder; import io.fabric8.kubernetes.api.model.extensions.Ingress; import io.fabric8.kubernetes.api.model.extensions.IngressBuilder; import io.fabric8.kubernetes.api.model.extensions.IngressRuleBuilder; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.openshift.api.model.Route; import io.fabric8.openshift.api.model.RouteBuilder; import io.fabric8.openshift.client.DefaultOpenShiftClient; import io.quarkus.runtime.ShutdownEvent; import io.quarkus.runtime.StartupEvent; import io.radanalytics.operator.common.AnsiColors; import org.slf4j.Logger; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.event.Observes; import javax.inject.Inject; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import static java.util.concurrent.TimeUnit.SECONDS; @ApplicationScoped public class SparkOperatorEntrypoint{ @Inject private Logger log; @Inject private SDKEntrypoint entrypoint; public void onStart(@Observes StartupEvent event) { log.info("onStart.."); try { exposeMetrics(); } catch (Exception e) { // ignore, not critical (service may have been already exposed) log.warn("Unable to expose the metrics, cause: {}", e.getMessage()); } } void onStop(@Observes ShutdownEvent event) { // nothing special } private void exposeMetrics() { if (entrypoint.getConfig() != null && entrypoint.getConfig().isMetrics()) { List<HasMetadata> resources = new ArrayList<>(); KubernetesClient client = entrypoint.getClient(); Service svc = createServiceForMetrics(); resources.add(svc); if (entrypoint.isOpenShift()) { client = new DefaultOpenShiftClient(); Route route = createRouteForMetrics(); resources.add(route); } else { Ingress ingress = createIngressForMetrics(); resources.add(ingress); } KubernetesList k8sResources = new KubernetesListBuilder().withItems(resources).build(); client.resourceList(k8sResources).inNamespace(client.getNamespace()).createOrReplace(); if (entrypoint.isOpenShift()) { ScheduledExecutorService s = Executors.newScheduledThreadPool(1); int delay = 6; ScheduledFuture<?> future = s.schedule(() -> { try { List<Route> routes = new DefaultOpenShiftClient().routes().withLabels(Collections.singletonMap("type", "operator-metrics")).list().getItems(); if (!routes.isEmpty()) { Route metrics = routes.iterator().next(); String host = metrics.getSpec().getHost(); log.info("Metrics for the Spark Operator are available at {} http://{} {}", AnsiColors.ye(), host, AnsiColors.xx()); } } catch (Throwable t) { log.warn("error during route retrieval: {}", t.getMessage()); t.printStackTrace(); } }, delay, SECONDS); } } } private Ingress createIngressForMetrics() { Ingress ingress = new IngressBuilder().withNewMetadata().withName("spark-operator-metrics") .withLabels(Collections.singletonMap("type", "operator-metrics")).endMetadata() .withNewSpec().withRules(new IngressRuleBuilder().withNewHttp() .withPaths(new HTTPIngressPathBuilder().withNewBackend().withServiceName("spark-operator-metrics") .withNewServicePort(entrypoint.getConfig().getMetricsPort()).endBackend().build()).endHttp().build()) .endSpec().build(); return ingress; } private Route createRouteForMetrics() { Route route = new RouteBuilder().withNewMetadata().withName("spark-operator-metrics") .withLabels(Collections.singletonMap("type", "operator-metrics")).endMetadata() .withNewSpec() .withNewTo("Service", "spark-operator-metrics", 100) .endSpec().build(); return route; } private Service createServiceForMetrics() { Service svc = entrypoint.getClient().services().createNew().withNewMetadata().withName("spark-operator-metrics") .withLabels(Collections.singletonMap("type", "operator-metrics")) .endMetadata().withNewSpec() .withSelector(Collections.singletonMap("app.kubernetes.io/name", "spark-operator")) .withPorts(new ServicePortBuilder().withPort(entrypoint.getConfig().getMetricsPort()) .withNewTargetPort().withIntVal(entrypoint.getConfig().getMetricsPort()).endTargetPort() .withProtocol("TCP").build()) .endSpec().done(); return svc; } }