Skip to content

Commit

Permalink
feat(cloudfoundry): add support for manifest random route (#5383)
Browse files Browse the repository at this point in the history
  • Loading branch information
rvazquezglez committed Jun 15, 2021
1 parent faf36cb commit b431f10
Show file tree
Hide file tree
Showing 6 changed files with 291 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,13 @@ public List<CloudFoundryDomain> all() throws CloudFoundryApiException {
}
return domains;
}

public CloudFoundryDomain getDefault() {
return map(
safelyCall(() -> api.all(null))
.orElseThrow(() -> new CloudFoundryApiException("Unable to retrieve default domain"))
.getResources()
.iterator()
.next());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,7 @@ public interface DomainService {

@GET("/v2/shared_domains")
Call<Page<Domain>> allShared(@Query("page") Integer page);

@GET("/v2/domains")
Call<Page<Domain>> all(@Query("page") Integer page);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,19 @@
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
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;
Expand Down Expand Up @@ -90,16 +95,40 @@ public DeployCloudFoundryServerGroupDescription convertDescription(Map input) {
// 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));
converted.setApplicationAttributes(
DeployCloudFoundryServerGroupDescription.ApplicationAttributes applicationAttributes =
convertManifest(
converted.getManifest().stream().findFirst().orElse(Collections.emptyMap())));
converted.getManifest().stream().findFirst().orElse(Collections.emptyMap()));
converted.setApplicationAttributes(applicationAttributes);
converted.setDocker(
converted.getArtifactCredentials().getTypes().contains("docker/image")
? resolveDockerAccount(converted.getApplicationArtifact())
: null);
List<String> 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 =
dockerRegistryNamedAccountCredentials.stream()
Expand Down Expand Up @@ -183,6 +212,7 @@ DeployCloudFoundryServerGroupDescription.ApplicationAttributes convertManifest(
attrs.setStack(app.getStack());
attrs.setCommand(app.getCommand());
attrs.setProcesses(app.getProcesses());
attrs.setRandomRoute(app.getRandomRoute());
return attrs;
})
.get();
Expand Down Expand Up @@ -216,6 +246,8 @@ private static class CloudFoundryManifest {

@Nullable private String command;

@Nullable private Boolean randomRoute;

private List<ProcessRequest> processes = Collections.emptyList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import lombok.AccessLevel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;

@Data
@EqualsAndHashCode(callSuper = true)
Expand Down Expand Up @@ -73,5 +75,13 @@ public static class ApplicationAttributes {
@Nullable private String command;

private List<ProcessRequest> processes = Collections.emptyList();

@Getter(AccessLevel.NONE)
@Nullable
private Boolean randomRoute;

public boolean getRandomRoute() {
return randomRoute != null && randomRoute;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
package com.netflix.spinnaker.clouddriver.cloudfoundry.deploy.util;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

// Based on
// https://github.com/cloudfoundry/cli/blob/8c20e5118d7cb38f52d52b69060f6b77943dce6e/util/randomword/generator.go
public class RandomWordGenerator {
private static final List<String> adjectives =
Arrays.asList(
"accountable",
"active",
"agile",
"anxious",
"appreciative",
"balanced",
"boisterous",
"bold",
"boring",
"brash",
"brave",
"bright",
"busy",
"chatty",
"cheerful",
"chipper",
"comedic",
"courteous",
"daring",
"delightful",
"empathic",
"excellent",
"exhausted",
"fantastic",
"fearless",
"fluent",
"forgiving",
"friendly",
"funny",
"generous",
"grateful",
"grouchy",
"grumpy",
"happy",
"hilarious",
"humble",
"impressive",
"insightful",
"intelligent",
"interested",
"kind",
"lean",
"nice",
"noisy",
"optimistic",
"patient",
"persistent",
"proud",
"quick",
"quiet",
"reflective",
"relaxed",
"reliable",
"responsible",
"responsive",
"rested",
"restless",
"shiny",
"shy",
"silly",
"sleepy",
"smart",
"spontaneous",
"surprised",
"sweet",
"talkative",
"terrific",
"thankful",
"timely",
"tired",
"turbulent",
"unexpected",
"wacky",
"wise",
"zany");

private static final List<String> nouns =
Arrays.asList(
"ardvark",
"alligator",
"antelope",
"baboon",
"badger",
"bandicoot",
"bat",
"bear",
"bilby",
"bongo",
"bonobo",
"buffalo",
"bushbuck",
"camel",
"cassowary",
"cat",
"cheetah",
"chimpanzee",
"chipmunk",
"civet",
"crane",
"crocodile",
"dingo",
"dog",
"dugong",
"duiker",
"echidna",
"eland",
"elephant",
"emu",
"fossa",
"fox",
"gazelle",
"gecko",
"gelada",
"genet",
"gerenuk",
"giraffe",
"gnu",
"gorilla",
"grysbok",
"hartebeest",
"hedgehog",
"hippopotamus",
"hyena",
"hyrax",
"impala",
"jackal",
"jaguar",
"kangaroo",
"klipspringer",
"koala",
"kob",
"kookaburra",
"kudu",
"lemur",
"leopard",
"lion",
"lizard",
"llama",
"lynx",
"manatee",
"mandrill",
"meerkat",
"mongoose",
"mouse",
"numbat",
"nyala",
"okapi",
"oribi",
"oryx",
"ostrich",
"otter",
"panda",
"pangolin",
"panther",
"parrot",
"platypus",
"porcupine",
"possum",
"puku",
"quokka",
"quoll",
"rabbit",
"ratel",
"raven",
"reedbuck",
"rhinocerous",
"roan",
"sable",
"serval",
"shark",
"sitatunga",
"springhare",
"squirrel",
"swan",
"tasmaniandevil",
"tiger",
"topi",
"toucan",
"turtle",
"wallaby",
"warthog",
"waterbuck",
"wildebeest",
"wolf",
"wolverine",
"wombat",
"zebra");

public static String randomQualifiedNoun() {
return randomAdjective() + randomNoun();
}

public static String randomAdjective() {
return randomElement(adjectives);
}

public static String randomNoun() {
return randomElement(nouns);
}

public static String randomElement(List<String> elements) {
return elements.get(ThreadLocalRandom.current().nextInt(elements.size()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.v3.ProcessRequest;
import com.netflix.spinnaker.clouddriver.cloudfoundry.config.CloudFoundryConfigurationProperties;
import com.netflix.spinnaker.clouddriver.cloudfoundry.deploy.description.DeployCloudFoundryServerGroupDescription;
import com.netflix.spinnaker.clouddriver.cloudfoundry.model.CloudFoundryDomain;
import com.netflix.spinnaker.clouddriver.cloudfoundry.model.CloudFoundryLoadBalancer;
import com.netflix.spinnaker.clouddriver.cloudfoundry.model.CloudFoundryOrganization;
import com.netflix.spinnaker.clouddriver.cloudfoundry.model.CloudFoundrySpace;
import com.netflix.spinnaker.clouddriver.cloudfoundry.provider.CloudFoundryProvider;
Expand Down Expand Up @@ -80,6 +82,12 @@ private static CloudFoundryCredentials createCredentials(String name) {

when(cloudFoundryClient.getApplications().findServerGroupId(any(), any()))
.thenReturn("servergroup-id");

when(cloudFoundryClient.getDomains().getDefault())
.thenReturn(CloudFoundryDomain.builder().name("cf-app.com").build());
when(cloudFoundryClient.getRoutes().find(any(), any()))
.thenReturn(CloudFoundryLoadBalancer.builder().build())
.thenReturn(null);
}

return new CloudFoundryCredentials(
Expand Down Expand Up @@ -240,7 +248,8 @@ void convertDescriptionTest() {
"credentials",
"test",
"manifest",
ImmutableList.of(ImmutableMap.of("applications", ImmutableList.of(ImmutableMap.of()))));
ImmutableList.of(
ImmutableMap.of("applications", List.of(Map.of("random-route", true)))));

DeployCloudFoundryServerGroupDescription result = converter.convertDescription(description);

Expand All @@ -251,6 +260,7 @@ void convertDescriptionTest() {
assertThat(result.getApplicationArtifact().getArtifactAccount())
.isEqualTo("destinationAccount");
assertThat(result.getApplicationArtifact().getUuid()).isEqualTo("servergroup-id");
assertThat(result.getApplicationAttributes().getRoutes()).isNotEmpty();
}

@Test
Expand All @@ -275,4 +285,13 @@ void convertDescriptionWithProcesses() {
List.of(
new ProcessRequest().setType("web").setInstances(2).setMemory("800M"))));
}

@Test
void convertRandomRoutes() {
DeployCloudFoundryServerGroupDescription.ApplicationAttributes applicationAttributes =
converter.convertManifest(
ImmutableMap.of("applications", List.of(Map.of("random-route", true))));

assertThat(applicationAttributes.getRandomRoute()).isTrue();
}
}

0 comments on commit b431f10

Please sign in to comment.