com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.SpinnakerProfile.java Source code

Java tutorial

Introduction

Here is the source code for com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.SpinnakerProfile.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.halyard.deploy.spinnaker.v1.profile;

import com.amazonaws.util.IOUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.spinnaker.halyard.config.config.v1.HalconfigParser;
import com.netflix.spinnaker.halyard.config.model.v1.node.DeploymentConfiguration;
import com.netflix.spinnaker.halyard.config.model.v1.node.Node;
import com.netflix.spinnaker.halyard.config.problem.v1.ConfigProblemBuilder;
import com.netflix.spinnaker.halyard.config.services.v1.DeploymentService;
import com.netflix.spinnaker.halyard.core.error.v1.HalException;
import com.netflix.spinnaker.halyard.core.problem.v1.ProblemBuilder;
import com.netflix.spinnaker.halyard.core.registry.v1.ProfileRegistry;
import com.netflix.spinnaker.halyard.deploy.services.v1.ArtifactService;
import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerArtifact;
import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerEndpoints;
import org.springframework.beans.factory.annotation.Autowired;
import org.yaml.snakeyaml.Yaml;
import retrofit.RetrofitError;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import static com.netflix.spinnaker.halyard.core.problem.v1.Problem.Severity.FATAL;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;

/**
 * A profile is a specialization of an artifact by means of feature flipping in .js and .yml
 * files.
 */
abstract public class SpinnakerProfile {
    @Autowired
    HalconfigParser parser;

    @Autowired
    Yaml yamlParser;

    @Autowired
    ObjectMapper objectMapper;

    @Autowired
    String spinnakerOutputDependencyPath;

    @Autowired
    DeploymentService deploymentService;

    @Autowired
    ProfileRegistry profileRegistry;

    @Autowired
    ArtifactService artifactService;

    final String EDIT_WARNING = commentPrefix() + "WARNING\n" + commentPrefix()
            + "This file was autogenerated, and _will_ be overwritten by Halyard.\n" + commentPrefix()
            + "Any edits you make here _will_ be lost.\n";

    String yamlToString(Object o) {
        return yamlParser.dump(objectMapper.convertValue(o, Map.class));
    }

    protected abstract String commentPrefix();

    public abstract SpinnakerArtifact getArtifact();

    public ProfileConfig getFullConfig(String deploymentName, SpinnakerEndpoints endpoints) {
        DeploymentConfiguration deploymentConfiguration = deploymentService
                .getDeploymentConfiguration(deploymentName);
        ProfileConfig result = generateFullConfig(getBaseConfig(deploymentConfiguration), deploymentConfiguration,
                endpoints);
        result.setConfig(result.getPrimaryConfigFile(), EDIT_WARNING + result.getPrimaryConfigContents());
        return result;
    }

    public abstract String getProfileFileName();

    /**
     * Overwrite this for components that need to specialize their config.
     *
     * @param config the base halconfig returned from the config storage.
     * @param deploymentConfiguration the deployment configuration being translated into Spinnaker config.
     * @param endpoints are the endpoints spinnaker will be running at.
     * @return the fully written configuration.
     */
    protected ProfileConfig generateFullConfig(ProfileConfig config,
            DeploymentConfiguration deploymentConfiguration, SpinnakerEndpoints endpoints) {
        return config;
    }

    /**
     * @return the base config (typically found in a profile's ./halconfig/ directory) for
     * the version of the profile specified by the Spinnaker version in the loaded halconfig.
     */
    private ProfileConfig getBaseConfig(DeploymentConfiguration deploymentConfiguration) {
        try {
            String componentVersion = artifactService.getArtifactVersion(deploymentConfiguration.getName(),
                    getArtifact());
            String componentObjectName = ProfileRegistry.profilePath(getArtifact().getName(), componentVersion,
                    getProfileFileName());

            return new ProfileConfig().setPrimaryConfigFile(getProfileFileName())
                    .extendConfig(getProfileFileName(),
                            IOUtils.toString(profileRegistry.getObjectContents(componentObjectName)))
                    .setVersion(componentVersion);
        } catch (RetrofitError | IOException e) {
            throw new HalException(new ConfigProblemBuilder(FATAL,
                    "Unable to retrieve a profile for \"" + getArtifact().getName() + "\": " + e.getMessage())
                            .build());
        }
    }

    /**
     * @param node is the node to find required files in.
     * @return the list of files required by the node to function.
     */
    List<String> processRequiredFiles(Node node) {
        List<String> files = new ArrayList<>();

        Consumer<Node> fileFinder = n -> files.addAll(n.localFiles().stream().map(f -> {
            try {
                f.setAccessible(true);
                String fPath = (String) f.get(n);
                if (fPath == null) {
                    return null;
                }

                File fFile = new File(fPath);
                String fName = fFile.getName();

                // Hash the path to uniquely flatten all files into the output directory
                Path newName = Paths.get(spinnakerOutputDependencyPath, Math.abs(fPath.hashCode()) + "-" + fName);
                File parent = newName.toFile().getParentFile();
                if (!parent.exists()) {
                    parent.mkdirs();
                } else if (fFile.getParent().equals(parent.toString())) {
                    // Don't move paths that are already in the right folder
                    return fPath;
                }
                Files.copy(Paths.get(fPath), newName, REPLACE_EXISTING);

                f.set(n, newName.toString());
                return newName.toString();
            } catch (IllegalAccessException e) {
                throw new RuntimeException("Failed to get local files for node " + n.getNodeName(), e);
            } catch (IOException e) {
                throw new HalException(
                        new ProblemBuilder(FATAL, "Failed to backup user file: " + e.getMessage()).build());
            } finally {
                f.setAccessible(false);
            }
        }).filter(Objects::nonNull).collect(Collectors.toList()));
        node.recursiveConsume(fileFinder);

        return files;
    }
}