
package io.quarkus.kubernetes.deployment;

import static io.quarkus.kubernetes.deployment.Constants.DEPLOYMENT_TARGET;
import static io.quarkus.kubernetes.deployment.Constants.KUBERNETES;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
import org.jboss.logging.Logger;

import io.dekorate.deps.kubernetes.api.model.HasMetadata;
import io.dekorate.deps.kubernetes.api.model.KubernetesList;
import io.dekorate.deps.kubernetes.client.KubernetesClient;
import io.dekorate.utils.Clients;
import io.dekorate.utils.Serialization;
import io.quarkus.container.spi.ContainerImageResultBuildItem;
import io.quarkus.deployment.IsNormal;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.ApplicationInfoBuildItem;
import io.quarkus.deployment.pkg.builditem.DeploymentResultBuildItem;
import io.quarkus.deployment.pkg.builditem.OutputTargetBuildItem;
import io.quarkus.kubernetes.client.spi.KubernetesClientBuildItem;

public class KubernetesDeployer {

    private static final Logger LOG = Logger.getLogger(KubernetesDeployer.class);

    @BuildStep(onlyIf = { IsNormal.class, KubernetesDeploy.class })
    public void deploy(KubernetesClientBuildItem kubernetesClient,
            ApplicationInfoBuildItem applicationInfo,
            Optional<ContainerImageResultBuildItem> containerImage,
            OutputTargetBuildItem outputTarget,
            BuildProducer<DeploymentResultBuildItem> deploymentResult) {

        Config config = ConfigProvider.getConfig();
        List<DeploymentTarget> deploymentTargets = Arrays
                .stream(config.getOptionalValue(DEPLOYMENT_TARGET, String.class).orElse(KUBERNETES).split(","))
                .map(String::trim).map(String::toUpperCase).map(DeploymentTarget::valueOf).collect(Collectors.toList());

        final KubernetesClient client = Clients.fromConfig(kubernetesClient.getClient().getConfiguration());
        DeploymentTarget target = deploymentTargets.stream().findFirst().orElse(DeploymentTarget.KUBERNETES);
        deploymentResult.produce(deploy(target, client, outputTarget.getOutputDirectory()));
    }

    private DeploymentResultBuildItem deploy(DeploymentTarget deploymentTarget, KubernetesClient client, Path outputDir) {
        String namespace = Optional.ofNullable(client.getNamespace()).orElse("default");
        LOG.info("Deploying to " + deploymentTarget.name().toLowerCase() + " server: " + client.getMasterUrl()
                + " in namespace:" + namespace + ".");
        File manifest = outputDir.resolve("kubernetes")
                .resolve(deploymentTarget.name().toLowerCase() + ".yml").toFile();
        try (FileInputStream fis = new FileInputStream(manifest)) {
            KubernetesList list = Serialization.unmarshalAsList(fis);
            list.getItems().forEach(i -> {
                client.resource(i).inNamespace(namespace).createOrReplace();
                LOG.info("Applied: " + i.getKind() + " " + i.getMetadata().getName() + ".");
            });

            HasMetadata m = list.getItems().stream().filter(r -> r.getKind().equals(deploymentTarget.getKind())).findFirst()
                    .orElseThrow(() -> new IllegalStateException(
                            "No " + deploymentTarget.getKind() + " found under: " + manifest.getAbsolutePath()));

            return new DeploymentResultBuildItem(m.getMetadata().getName(), m.getMetadata().getLabels());
        } catch (FileNotFoundException e) {
            throw new IllegalStateException(
                    "Can't find generated kubernetes manifest: " + manifest.getAbsolutePath());
        } catch (IOException e) {
            throw new RuntimeException("Error closing file: " + manifest.getAbsolutePath());
        }

    }
}

@@ -441,16 +441,61 @@
 ctors;%0A%0A
+import javax.net.ssl.SSLHandshakeException;%0A%0A
 import o
@@ -533,16 +533,16 @@
 Config;%0A
-
 import o
@@ -801,16 +801,85 @@
 Client;%0A
+import io.dekorate.deps.kubernetes.client.KubernetesClientException;%0A
 import i
@@ -1916,24 +1916,365 @@
 tResult) %7B%0A%0A
+        if (!containerImage.isPresent()) %7B%0A            LOG.warn(%0A                    %22A Kubernetes deployment was requested by no extension was found to build a container image. Consider adding one of following extensions: %5C%22quarkus-container-image-jib%5C%22, %5C%22quarkus-container-image-docker%5C%22 or %5C%22quarkus-container-image-s2i%5C%22,%22);%0A        %7D%0A%0A
         Conf
@@ -3622,16 +3622,110 @@
 (i -%3E %7B%0A
+                LOG.info(%22Applying: %22 + i.getKind() + %22 %22 + i.getMetadata().getName() + %22.%22);%0A
         
@@ -4396,32 +4396,32 @@
 StateException(%0A
-
                 
@@ -4492,32 +4492,778 @@
 bsolutePath());%0A
+        %7D catch (KubernetesClientException e) %7B%0A            if (e.getCause() instanceof SSLHandshakeException) %7B%0A                String message = %22The application could not be deployed to the cluster because the Kubernetes API Server certificates are not trusted. The certificates can be configured using the relevant configuration propertiers under the 'quarkus.kubernetes-client' config root, or %5C%22quarkus.kubernetes-client.trust-certs=true%5C%22 can be set to explicitly trust the certificates (not recommended)%22;%0A                LOG.error(message);%0A                throw new RuntimeException(e.getCause());%0A            %7D%0A            LOG.error(%22Unable to deploy the application to the Kubernetes cluster: %22 + e.getMessage());%0A            throw e;%0A
         %7D catch 

Improve output of the Kubernetes deploy process