com.netflix.spinnaker.clouddriver.kubernetes.v2.op.manifest.KubernetesDeployManifestOperation.java Source code

Java tutorial

Introduction

Here is the source code for com.netflix.spinnaker.clouddriver.kubernetes.v2.op.manifest.KubernetesDeployManifestOperation.java

Source

/*
 * Copyright 2017 Google, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.netflix.spinnaker.clouddriver.kubernetes.v2.op.manifest;

import com.netflix.spinnaker.clouddriver.data.task.Task;
import com.netflix.spinnaker.clouddriver.data.task.TaskRepository;
import com.netflix.spinnaker.clouddriver.kubernetes.KubernetesCloudProvider;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.artifact.ArtifactReplacer.ReplaceResult;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.artifact.KubernetesArtifactConverter;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.KubernetesResourceProperties;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.KubernetesResourcePropertyRegistry;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.manifest.KubernetesDeployManifestDescription;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.manifest.KubernetesKind;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.manifest.KubernetesManifest;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.manifest.KubernetesManifestAnnotater;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.op.OperationResult;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.op.handler.KubernetesHandler;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.security.KubernetesV2Credentials;
import com.netflix.spinnaker.clouddriver.model.ArtifactProvider;
import com.netflix.spinnaker.clouddriver.names.NamerRegistry;
import com.netflix.spinnaker.clouddriver.orchestration.AtomicOperation;
import com.netflix.spinnaker.kork.artifacts.model.Artifact;
import com.netflix.spinnaker.moniker.Moniker;
import com.netflix.spinnaker.moniker.Namer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
public class KubernetesDeployManifestOperation implements AtomicOperation<OperationResult> {
    private final KubernetesDeployManifestDescription description;
    private final KubernetesV2Credentials credentials;
    private final ArtifactProvider provider;
    private final Namer namer;
    private final KubernetesResourcePropertyRegistry registry;
    private final String accountName;
    private static final String OP_NAME = "DEPLOY_KUBERNETES_MANIFEST";

    public KubernetesDeployManifestOperation(KubernetesDeployManifestDescription description,
            KubernetesResourcePropertyRegistry registry, ArtifactProvider provider) {
        this.description = description;
        this.credentials = (KubernetesV2Credentials) description.getCredentials().getCredentials();
        this.registry = registry;
        this.provider = provider;
        this.accountName = description.getCredentials().getName();
        this.namer = NamerRegistry.lookup().withProvider(KubernetesCloudProvider.getID()).withAccount(accountName)
                .withResource(KubernetesManifest.class);
    }

    private static Task getTask() {
        return TaskRepository.threadLocalTask.get();
    }

    @Override
    public OperationResult operate(List _unused) {
        getTask().updateStatus(OP_NAME, "Beginning deployment of manifest...");

        List<KubernetesManifest> inputManifests = description.getManifests();
        List<KubernetesManifest> deployManifests = new ArrayList<>();
        if (inputManifests == null || inputManifests.isEmpty()) {
            log.warn("Relying on deprecated single manifest input: " + description.getManifest());
            inputManifests = Collections.singletonList(description.getManifest());
        }

        inputManifests = inputManifests.stream().filter(Objects::nonNull).collect(Collectors.toList());

        List<Artifact> requiredArtifacts = description.getRequiredArtifacts();
        if (requiredArtifacts == null) {
            requiredArtifacts = new ArrayList<>();
        }

        List<Artifact> optionalArtifacts = description.getOptionalArtifacts();
        if (optionalArtifacts == null) {
            optionalArtifacts = new ArrayList<>();
        }

        List<Artifact> artifacts = new ArrayList<>();
        artifacts.addAll(requiredArtifacts);
        artifacts.addAll(optionalArtifacts);

        Set<Artifact> boundArtifacts = new HashSet<>();

        for (KubernetesManifest manifest : inputManifests) {
            if (StringUtils.isEmpty(manifest.getNamespace()) && manifest.getKind().isNamespaced()) {
                manifest.setNamespace(credentials.getDefaultNamespace());
            }

            KubernetesResourceProperties properties = findResourceProperties(manifest);
            if (properties == null) {
                throw new IllegalArgumentException("Unsupported Kubernetes object kind '"
                        + manifest.getKind().toString() + "', unable to continue.");
            }
            KubernetesHandler deployer = properties.getHandler();
            if (deployer == null) {
                throw new IllegalArgumentException("No deployer available for Kubernetes object kind '"
                        + manifest.getKind().toString() + "', unable to continue.");
            }

            getTask().updateStatus(OP_NAME,
                    "Swapping out artifacts in " + manifest.getFullResourceName() + " from context...");
            ReplaceResult replaceResult = deployer.replaceArtifacts(manifest, artifacts);
            deployManifests.add(replaceResult.getManifest());
            boundArtifacts.addAll(replaceResult.getBoundArtifacts());
        }

        Set<Artifact> unboundArtifacts = new HashSet<>(requiredArtifacts);
        unboundArtifacts.removeAll(boundArtifacts);

        getTask().updateStatus(OP_NAME, "Checking if all requested artifacts were bound...");
        if (!unboundArtifacts.isEmpty()) {
            throw new IllegalArgumentException("The following artifacts could not be bound: '" + unboundArtifacts
                    + "' . Failing the stage as this is likely a configuration error.");
        }

        getTask().updateStatus(OP_NAME, "Sorting manifests by priority...");
        deployManifests.sort(Comparator.comparingInt(m -> findResourceProperties(m).getHandler().deployPriority()));
        getTask().updateStatus(OP_NAME, "Deploy order is: " + String.join(", ", deployManifests.stream()
                .map(KubernetesManifest::getFullResourceName).collect(Collectors.toList())));

        OperationResult result = new OperationResult();
        for (KubernetesManifest manifest : deployManifests) {
            KubernetesResourceProperties properties = findResourceProperties(manifest);
            boolean versioned = description.getVersioned() == null ? properties.isVersioned()
                    : description.getVersioned();
            KubernetesArtifactConverter converter = versioned ? properties.getVersionedConverter()
                    : properties.getUnversionedConverter();
            KubernetesHandler deployer = properties.getHandler();

            Moniker moniker = description.getMoniker();
            Artifact artifact = converter.toArtifact(provider, manifest);

            getTask().updateStatus(OP_NAME, "Annotating manifest " + manifest.getFullResourceName()
                    + " with artifact, relationships & moniker...");
            KubernetesManifestAnnotater.annotateManifest(manifest, artifact);

            namer.applyMoniker(manifest, moniker);
            manifest.setName(converter.getDeployedName(artifact));

            getTask().updateStatus(OP_NAME,
                    "Swapping out artifacts in " + manifest.getFullResourceName() + " from other deployments...");
            ReplaceResult replaceResult = deployer.replaceArtifacts(manifest,
                    new ArrayList<>(result.getCreatedArtifacts()));
            boundArtifacts.addAll(replaceResult.getBoundArtifacts());
            manifest = replaceResult.getManifest();

            getTask().updateStatus(OP_NAME,
                    "Submitting manifest " + manifest.getFullResourceName() + " to kubernetes master...");
            result.merge(deployer.deploy(credentials, manifest));

            result.getCreatedArtifacts().add(artifact);
        }

        result.getBoundArtifacts().addAll(boundArtifacts);
        result.removeSensitiveKeys(registry, accountName);
        return result;
    }

    private KubernetesResourceProperties findResourceProperties(KubernetesManifest manifest) {
        KubernetesKind kind = manifest.getKind();
        getTask().updateStatus(OP_NAME, "Finding deployer for " + kind + "...");
        return registry.get(accountName, kind);
    }
}