com.netflix.spinnaker.clouddriver.cloudfoundry.deploy.converters.DeployCloudFoundryServerGroupAtomicOperationConverter Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2018 Pivotal, 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.cloudfoundry.deploy.converters;
import static io.vavr.API.*;
import static java.util.stream.Collectors.toList;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.google.common.collect.Lists;
import com.netflix.spinnaker.clouddriver.artifacts.ArtifactCredentialsRepository;
import com.netflix.spinnaker.clouddriver.artifacts.config.ArtifactCredentials;
import com.netflix.spinnaker.clouddriver.cloudfoundry.CloudFoundryOperation;
import com.netflix.spinnaker.clouddriver.cloudfoundry.artifacts.CloudFoundryArtifactCredentials;
import com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.RouteId;
import com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.v3.Docker;
import com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.v3.ProcessRequest;
import com.netflix.spinnaker.clouddriver.cloudfoundry.deploy.description.DeployCloudFoundryServerGroupDescription;
import com.netflix.spinnaker.clouddriver.cloudfoundry.deploy.ops.DeployCloudFoundryServerGroupAtomicOperation;
import com.netflix.spinnaker.clouddriver.cloudfoundry.deploy.util.RandomWordGenerator;
import com.netflix.spinnaker.clouddriver.cloudfoundry.model.CloudFoundryDomain;
import com.netflix.spinnaker.clouddriver.cloudfoundry.model.CloudFoundryLoadBalancer;
import com.netflix.spinnaker.clouddriver.cloudfoundry.security.CloudFoundryCredentials;
import com.netflix.spinnaker.clouddriver.docker.registry.security.DockerRegistryNamedAccountCredentials;
import com.netflix.spinnaker.clouddriver.helpers.OperationPoller;
import com.netflix.spinnaker.clouddriver.orchestration.AtomicOperation;
import com.netflix.spinnaker.clouddriver.orchestration.AtomicOperations;
import com.netflix.spinnaker.credentials.CredentialsRepository;
import com.netflix.spinnaker.kork.artifacts.model.Artifact;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import lombok.Data;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@CloudFoundryOperation(AtomicOperations.CREATE_SERVER_GROUP)
@Component
public class DeployCloudFoundryServerGroupAtomicOperationConverter
extends AbstractCloudFoundryServerGroupAtomicOperationConverter {
private final OperationPoller operationPoller;
private final ArtifactCredentialsRepository credentialsRepository;
private final CredentialsRepository
dockerRegistryCredentialsRepository;
public DeployCloudFoundryServerGroupAtomicOperationConverter(
@Qualifier("cloudFoundryOperationPoller") OperationPoller operationPoller,
ArtifactCredentialsRepository credentialsRepository,
CredentialsRepository
dockerRegistryCredentialsRepository) {
this.operationPoller = operationPoller;
this.credentialsRepository = credentialsRepository;
this.dockerRegistryCredentialsRepository = dockerRegistryCredentialsRepository;
}
@Override
public AtomicOperation convertOperation(Map input) {
return new DeployCloudFoundryServerGroupAtomicOperation(
operationPoller, convertDescription(input));
}
@Override
public DeployCloudFoundryServerGroupDescription convertDescription(Map input) {
DeployCloudFoundryServerGroupDescription converted =
getObjectMapper().convertValue(input, DeployCloudFoundryServerGroupDescription.class);
CloudFoundryCredentials credentials = getCredentialsObject(input.get("credentials").toString());
converted.setCredentials(credentials);
converted.setClient(credentials.getClient());
converted.setAccountName(credentials.getName());
String region = converted.getRegion();
converted.setSpace(
findSpace(region, converted.getClient())
.orElseThrow(
() ->
new IllegalArgumentException(
"Unable to find organization and space '" + region + "'.")));
// fail early if we're not going to be able to locate credentials to download the artifact in
// the deploy operation.
converted.setArtifactCredentials(getArtifactCredentials(converted));
DeployCloudFoundryServerGroupDescription.ApplicationAttributes applicationAttributes =
convertManifest(
converted.getManifest().stream().findFirst().orElse(Collections.emptyMap()));
converted.setApplicationAttributes(applicationAttributes);
converted.setDocker(
converted.getArtifactCredentials().getTypes().contains("docker/image")
? resolveDockerAccount(converted.getApplicationArtifact())
: null);
List routes = applicationAttributes.getRoutes();
if ((routes == null || routes.isEmpty()) && applicationAttributes.getRandomRoute()) {
setRandomRoute(converted);
}
return converted;
}
private void setRandomRoute(DeployCloudFoundryServerGroupDescription client) {
CloudFoundryDomain defaultDomain = client.getClient().getDomains().getDefault();
if (defaultDomain != null) {
String routeName = null;
for (int i = 0; i < 10; i++) {
routeName = RandomWordGenerator.randomQualifiedNoun() + "." + defaultDomain.getName();
RouteId routeId = client.getClient().getRoutes().toRouteId(routeName);
CloudFoundryLoadBalancer cloudFoundryLoadBalancer =
client.getClient().getRoutes().find(routeId, client.getSpace().getId());
if (cloudFoundryLoadBalancer == null) {
break;
}
}
client.getApplicationAttributes().setRoutes(Lists.newArrayList(routeName));
}
}
private Docker resolveDockerAccount(Artifact artifact) {
DockerRegistryNamedAccountCredentials dockerCreds =
dockerRegistryCredentialsRepository.getAll().stream()
.filter(reg -> reg.getRegistry().equals(artifact.getReference().split("/")[0]))
.filter(reg -> reg.getRepositories().contains(artifact.getName().split("/", 2)[1]))
.findFirst()
.orElseThrow(
() ->
new IllegalArgumentException(
"Could not find a docker registry for the docker image: "
+ artifact.getName()));
return Docker.builder()
.image(artifact.getReference())
.username(dockerCreds.getUsername())
.password(dockerCreds.getPassword())
.build();
}
private ArtifactCredentials getArtifactCredentials(
DeployCloudFoundryServerGroupDescription converted) {
Artifact artifact = converted.getApplicationArtifact();
if (artifact == null) {
throw new IllegalArgumentException("No artifact definition in stage configuration");
}
String artifactAccount = artifact.getArtifactAccount();
if (CloudFoundryArtifactCredentials.TYPE.equals(artifact.getType())) {
CloudFoundryCredentials credentials = getCredentialsObject(artifactAccount);
String uuid =
getServerGroupId(artifact.getName(), artifact.getLocation(), credentials.getClient());
converted.setApplicationArtifact(artifact.toBuilder().uuid(uuid).build());
return new CloudFoundryArtifactCredentials(credentials.getClient());
}
ArtifactCredentials credentials =
credentialsRepository.getFirstCredentialsWithName(artifactAccount);
if (credentials == null) {
throw new IllegalArgumentException(
"Unable to find artifact credentials '" + artifactAccount + "'");
}
return credentials;
}
// visible for testing
DeployCloudFoundryServerGroupDescription.ApplicationAttributes convertManifest(
Map
© 2015 - 2025 Weber Informatics LLC | Privacy Policy