package com.github.containersolutions.operator.sample; import com.github.containersolutions.operator.api.Controller; import com.github.containersolutions.operator.api.ResourceController; import io.fabric8.kubernetes.api.model.*; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.DoneableDeployment; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.dsl.Resource; import io.fabric8.kubernetes.client.dsl.RollableScalableResource; import io.fabric8.kubernetes.client.dsl.ServiceResource; import io.fabric8.kubernetes.client.utils.Serialization; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import java.util.Optional; @Controller(customResourceClass = WebServer.class, crdName = "webservers.sample.javaoperatorsdk") public class WebServerController implements ResourceController<WebServer> { private final Logger log = LoggerFactory.getLogger(getClass()); private final KubernetesClient kubernetesClient; public WebServerController(KubernetesClient kubernetesClient) { this.kubernetesClient = kubernetesClient; } @Override public Optional<WebServer> createOrUpdateResource(WebServer webServer) { if (webServer.getSpec().getHtml().contains("error")) { throw new ErrorSimulationException("Simulating error"); } String ns = webServer.getMetadata().getNamespace(); Map<String, String> data = new HashMap<>(); data.put("index.html", webServer.getSpec().getHtml()); ConfigMap htmlConfigMap = new ConfigMapBuilder() .withMetadata(new ObjectMetaBuilder() .withName(configMapName(webServer)) .withNamespace(ns) .build()) .withData(data) .build(); Deployment deployment = loadYaml(Deployment.class, "deployment.yaml"); deployment.getMetadata().setName(deploymentName(webServer)); deployment.getMetadata().setNamespace(ns); deployment.getSpec().getSelector().getMatchLabels().put("app", deploymentName(webServer)); deployment.getSpec().getTemplate().getMetadata().getLabels().put("app", deploymentName(webServer)); deployment.getSpec().getTemplate().getSpec().getVolumes().get(0).setConfigMap( new ConfigMapVolumeSourceBuilder().withName(configMapName(webServer)).build()); Service service = loadYaml(Service.class, "service.yaml"); service.getMetadata().setName(serviceName(webServer)); service.getMetadata().setNamespace(ns); service.getSpec().setSelector(deployment.getSpec().getTemplate().getMetadata().getLabels()); ConfigMap existingConfigMap = kubernetesClient.configMaps() .inNamespace(htmlConfigMap.getMetadata().getNamespace()) .withName(htmlConfigMap.getMetadata().getName()).get(); log.info("Creating or updating ConfigMap {} in {}", htmlConfigMap.getMetadata().getName(), ns); kubernetesClient.configMaps().inNamespace(ns).createOrReplace(htmlConfigMap); log.info("Creating or updating Deployment {} in {}", deployment.getMetadata().getName(), ns); kubernetesClient.apps().deployments().inNamespace(ns).createOrReplace(deployment); if (kubernetesClient.services().inNamespace(ns).withName(service.getMetadata().getName()).get() == null) { log.info("Creating Service {} in {}", service.getMetadata().getName(), ns); kubernetesClient.services().inNamespace(ns).createOrReplace(service); } if (existingConfigMap != null) { if (!StringUtils.equals(existingConfigMap.getData().get("index.html"), htmlConfigMap.getData().get("index.html"))) { log.info("Restarting pods because HTML has changed in {}", ns); kubernetesClient.pods().inNamespace(ns).withLabel("app", deploymentName(webServer)).delete(); } } WebServerStatus status = new WebServerStatus(); status.setHtmlConfigMap(htmlConfigMap.getMetadata().getName()); status.setAreWeGood("Yes!"); webServer.setStatus(status); // throw new RuntimeException("Creating object failed, because it failed"); return Optional.of(webServer); } @Override public boolean deleteResource(WebServer nginx) { log.info("Execution deleteResource for: {}", nginx.getMetadata().getName()); log.info("Deleting ConfigMap {}", configMapName(nginx)); Resource<ConfigMap, DoneableConfigMap> configMap = kubernetesClient.configMaps() .inNamespace(nginx.getMetadata().getNamespace()) .withName(configMapName(nginx)); if (configMap.get() != null) { configMap.delete(); } log.info("Deleting Deployment {}", deploymentName(nginx)); RollableScalableResource<Deployment, DoneableDeployment> deployment = kubernetesClient.apps().deployments() .inNamespace(nginx.getMetadata().getNamespace()) .withName(deploymentName(nginx)); if (deployment.get() != null) { deployment.cascading(true).delete(); } log.info("Deleting Service {}", serviceName(nginx)); ServiceResource<Service, DoneableService> service = kubernetesClient.services() .inNamespace(nginx.getMetadata().getNamespace()) .withName(serviceName(nginx)); if (service.get() != null) { service.delete(); } return true; } private static String configMapName(WebServer nginx) { return nginx.getMetadata().getName() + "-html"; } private static String deploymentName(WebServer nginx) { return nginx.getMetadata().getName(); } private static String serviceName(WebServer nginx) { return nginx.getMetadata().getName(); } private <T> T loadYaml(Class<T> clazz, String yaml) { try (InputStream is = getClass().getResourceAsStream(yaml)) { return Serialization.unmarshal(is, clazz); } catch (IOException ex) { throw new IllegalStateException("Cannot find yaml on classpath: " + yaml); } } }