Skip to content

Commit 0b50c99

Browse files
sodre90lacikaaa
authored andcommitted
CB-16056 Support recipes for FreeIPA provisioning/termination
It is phase1 implementation. I will rename CM recipe types like post_CM_install to something like post_service_install etc, but not in this PR, it will be a separated PR. Attaching / detaching recipes are not supported yet, but it is part of the plan, so it will be implemented in phase2. Recipes saved into both env service then freeipa service because of restartable flows. Salt states moved to the common salt directory and reused the whole original salt logic.
1 parent d63cb36 commit 0b50c99

File tree

81 files changed

+1669
-48
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+1669
-48
lines changed

core-common/build.gradle

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
plugins {
2+
id "java"
3+
}
4+
5+
repositories {
6+
mavenCentral()
7+
}
8+
9+
dependencies {
10+
11+
implementation project(":core-api")
12+
implementation project(":common")
13+
14+
testImplementation group: 'org.assertj', name: 'assertj-core', version: assertjVersion
15+
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.sequenceiq.cloudbreak.recipe;
2+
3+
import java.util.List;
4+
import java.util.stream.Collectors;
5+
6+
import javax.inject.Inject;
7+
8+
import org.slf4j.Logger;
9+
import org.slf4j.LoggerFactory;
10+
import org.springframework.stereotype.Service;
11+
12+
import com.sequenceiq.cloudbreak.api.endpoint.v4.common.CompactViewV4Response;
13+
import com.sequenceiq.cloudbreak.api.endpoint.v4.recipes.RecipeV4Endpoint;
14+
import com.sequenceiq.cloudbreak.api.endpoint.v4.recipes.responses.RecipeViewV4Responses;
15+
import com.sequenceiq.cloudbreak.common.exception.NotFoundException;
16+
17+
@Service
18+
public class RecipeCrnListProviderService {
19+
20+
private static final Logger LOGGER = LoggerFactory.getLogger(RecipeCrnListProviderService.class);
21+
22+
@Inject
23+
private RecipeV4Endpoint recipeV4Endpoint;
24+
25+
public List<String> getResourceCrnListByResourceNameList(List<String> resourceNames) {
26+
LOGGER.info("Get resources crn list for recipes: {}", resourceNames);
27+
RecipeViewV4Responses recipes = recipeV4Endpoint.list(0L);
28+
validateRequestedRecipesExistsByName(resourceNames, recipes);
29+
List<String> resourceCrns = recipes.getResponses().stream()
30+
.filter(recipe -> resourceNames.contains(recipe.getName())).map(CompactViewV4Response::getCrn).collect(Collectors.toList());
31+
LOGGER.info("Resource crns for recipes: {}", resourceCrns);
32+
return resourceCrns;
33+
}
34+
35+
private void validateRequestedRecipesExistsByName(List<String> resourceNames, RecipeViewV4Responses recipes) {
36+
List<String> recipeNamesFromCore = recipes.getResponses().stream().map(CompactViewV4Response::getName).collect(Collectors.toList());
37+
List<String> recipesNotFound = resourceNames.stream().filter(recipeName -> !recipeNamesFromCore.contains(recipeName)).collect(Collectors.toList());
38+
if (recipesNotFound.size() > 0) {
39+
LOGGER.info("Missing recipes: {}", recipesNotFound);
40+
throw new NotFoundException("Following recipes does not exist: " + recipesNotFound);
41+
}
42+
}
43+
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.sequenceiq.cloudbreak.recipe;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
import static org.mockito.ArgumentMatchers.any;
5+
import static org.mockito.Mockito.when;
6+
7+
import java.util.List;
8+
import java.util.Set;
9+
10+
import org.junit.jupiter.api.Assertions;
11+
import org.junit.jupiter.api.Test;
12+
import org.junit.jupiter.api.extension.ExtendWith;
13+
import org.mockito.InjectMocks;
14+
import org.mockito.Mock;
15+
import org.mockito.junit.jupiter.MockitoExtension;
16+
17+
import com.sequenceiq.cloudbreak.api.endpoint.v4.recipes.RecipeV4Endpoint;
18+
import com.sequenceiq.cloudbreak.api.endpoint.v4.recipes.responses.RecipeViewV4Response;
19+
import com.sequenceiq.cloudbreak.api.endpoint.v4.recipes.responses.RecipeViewV4Responses;
20+
import com.sequenceiq.cloudbreak.common.exception.NotFoundException;
21+
22+
@ExtendWith(MockitoExtension.class)
23+
class RecipeCrnListProviderServiceTest {
24+
25+
@Mock
26+
private RecipeV4Endpoint recipeV4Endpoint;
27+
28+
@InjectMocks
29+
private RecipeCrnListProviderService recipeCrnListProviderService;
30+
31+
@Test
32+
public void testGetResourceCrnListByResourceNameList() {
33+
RecipeViewV4Responses recipeViewV4Responses = new RecipeViewV4Responses();
34+
RecipeViewV4Response recipeResponse1 = new RecipeViewV4Response();
35+
recipeResponse1.setName("recipe1");
36+
recipeResponse1.setCrn("crn1");
37+
RecipeViewV4Response recipeResponse2 = new RecipeViewV4Response();
38+
recipeResponse2.setName("recipe2");
39+
recipeResponse2.setCrn("crn2");
40+
recipeViewV4Responses.setResponses(Set.of(recipeResponse1, recipeResponse2));
41+
when(recipeV4Endpoint.list(any())).thenReturn(recipeViewV4Responses);
42+
List<String> resourceCrnListByResourceNameList = recipeCrnListProviderService.getResourceCrnListByResourceNameList(List.of("recipe1", "recipe2"));
43+
assertThat(resourceCrnListByResourceNameList).containsExactlyInAnyOrder("crn1", "crn2");
44+
}
45+
46+
@Test
47+
public void testGetResourceCrnListByResourceNameListButOnlyOneRecipeWasFound() {
48+
RecipeViewV4Responses recipeViewV4Responses = new RecipeViewV4Responses();
49+
RecipeViewV4Response recipeResponse1 = new RecipeViewV4Response();
50+
recipeResponse1.setName("recipe1");
51+
recipeResponse1.setCrn("crn1");
52+
recipeViewV4Responses.setResponses(Set.of(recipeResponse1));
53+
when(recipeV4Endpoint.list(any())).thenReturn(recipeViewV4Responses);
54+
NotFoundException cloudbreakRuntimeException = Assertions.assertThrows(NotFoundException.class,
55+
() -> recipeCrnListProviderService.getResourceCrnListByResourceNameList(List.of("recipe1", "recipe2")));
56+
Assertions.assertEquals("Following recipes does not exist: [recipe2]", cloudbreakRuntimeException.getMessage());
57+
}
58+
59+
}

core/src/main/java/com/sequenceiq/cloudbreak/converter/v4/recipes/RecipeToRecipeV4RequestConverter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public class RecipeToRecipeV4RequestConverter {
1515

1616
public RecipeV4Request convert(Recipe source) {
1717
RecipeV4Request recipeRequest = new RecipeV4Request();
18-
recipeRequest.setName("");
18+
recipeRequest.setName(source.getName());
1919
recipeRequest.setDescription(source.getDescription());
2020
recipeRequest.setType(RecipeV4Type.valueOf(source.getRecipeType().name()));
2121
recipeRequest.setContent(source.getContent());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.sequenceiq.cloudbreak.converter.v4.recipes;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import org.junit.jupiter.api.Test;
6+
import org.junit.jupiter.api.extension.ExtendWith;
7+
import org.mockito.InjectMocks;
8+
import org.mockito.junit.jupiter.MockitoExtension;
9+
10+
import com.sequenceiq.cloudbreak.api.endpoint.v4.recipes.requests.RecipeV4Request;
11+
import com.sequenceiq.cloudbreak.api.endpoint.v4.recipes.requests.RecipeV4Type;
12+
import com.sequenceiq.cloudbreak.common.model.recipe.RecipeType;
13+
import com.sequenceiq.cloudbreak.domain.Recipe;
14+
15+
@ExtendWith(MockitoExtension.class)
16+
class RecipeToRecipeV4RequestConverterTest {
17+
18+
@InjectMocks
19+
private RecipeToRecipeV4RequestConverter recipeToRecipeV4RequestConverter;
20+
21+
@Test
22+
public void testRecipeToRecipeV4RequestConverter() {
23+
Recipe source = new Recipe();
24+
source.setName("recipeName");
25+
source.setRecipeType(RecipeType.POST_CLUSTER_INSTALL);
26+
source.setContent("content");
27+
source.setDescription("description");
28+
RecipeV4Request converted = recipeToRecipeV4RequestConverter.convert(source);
29+
assertEquals(converted.getName(), source.getName());
30+
assertEquals(converted.getType(), RecipeV4Type.POST_CLUSTER_INSTALL);
31+
assertEquals(converted.getDescription(), source.getDescription());
32+
assertEquals(converted.getContent(), source.getContent());
33+
}
34+
35+
}

environment-api/src/main/java/com/sequenceiq/environment/api/doc/environment/EnvironmentModelDescription.java

+1
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ public class EnvironmentModelDescription {
128128
public static final String ENCRYPTION_KEY = "Key Resource of the Customer Managed Encryption Key to encrypt GCP resources";
129129

130130
public static final String FREEIPA_AWS_PARAMETERS = "Aws specific FreeIpa parameters";
131+
public static final String FREEIPA_RECIPE_LIST = "FreeIpa recipe list";
131132
public static final String FREEIPA_AZURE_PARAMETERS = "Azure specific FreeIpa parameters";
132133
public static final String FREEIPA_GCP_PARAMETERS = "Gcp specific FreeIpa parameters";
133134
public static final String FREEIPA_AWS_SPOT_PARAMETERS = "Aws spot instance related parameters.";

environment-api/src/main/java/com/sequenceiq/environment/api/v1/environment/model/request/AttachedFreeIpaRequest.java

+13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.sequenceiq.environment.api.v1.environment.model.request;
22

33
import java.io.Serializable;
4+
import java.util.Set;
45

56
import javax.validation.Valid;
67
import javax.validation.constraints.NotNull;
@@ -31,6 +32,9 @@ public class AttachedFreeIpaRequest implements Serializable {
3132
@ApiModelProperty(value = EnvironmentModelDescription.MULTIAZ_FREEIPA)
3233
private boolean enableMultiAz;
3334

35+
@ApiModelProperty(EnvironmentModelDescription.FREEIPA_RECIPE_LIST)
36+
private Set<String> recipes;
37+
3438
@Valid
3539
@ApiModelProperty(EnvironmentModelDescription.FREEIPA_AWS_PARAMETERS)
3640
private AwsFreeIpaParameters aws;
@@ -124,4 +128,13 @@ public boolean isEnableMultiAz() {
124128
public void setEnableMultiAz(boolean enableMultiAz) {
125129
this.enableMultiAz = enableMultiAz;
126130
}
131+
132+
public Set<String> getRecipes() {
133+
return recipes;
134+
}
135+
136+
public void setRecipes(Set<String> recipes) {
137+
this.recipes = recipes;
138+
}
139+
127140
}

environment/build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ dependencies {
5252
implementation project(':audit-connector')
5353
implementation project(":authorization-common")
5454
implementation project(":common")
55+
implementation project(':core-common')
5556
implementation project(":secret-engine")
5657
implementation project(":flow")
5758
implementation project(":auth-connector")

environment/src/main/java/com/sequenceiq/environment/environment/domain/EnvironmentView.java

+17
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
import java.util.Set;
66

77
import javax.persistence.CascadeType;
8+
import javax.persistence.CollectionTable;
89
import javax.persistence.Column;
910
import javax.persistence.Convert;
11+
import javax.persistence.ElementCollection;
1012
import javax.persistence.Entity;
13+
import javax.persistence.FetchType;
1114
import javax.persistence.JoinColumn;
1215
import javax.persistence.ManyToOne;
1316
import javax.persistence.OneToOne;
@@ -124,6 +127,11 @@ public class EnvironmentView extends CompactView implements AuthResource {
124127

125128
private String freeIpaImageId;
126129

130+
@ElementCollection(fetch = FetchType.EAGER)
131+
@CollectionTable(name = "environment_freeiparecipes", joinColumns = @JoinColumn(name = "environment_id", referencedColumnName = "id"))
132+
@Column(name = "recipe")
133+
private Set<String> freeipaRecipes;
134+
127135
@Column(nullable = false)
128136
private boolean freeIpaEnableMultiAz;
129137

@@ -481,6 +489,14 @@ public void setFreeIpaEnableMultiAz(boolean freeIpaEnableMultiAz) {
481489
this.freeIpaEnableMultiAz = freeIpaEnableMultiAz;
482490
}
483491

492+
public Set<String> getFreeipaRecipes() {
493+
return freeipaRecipes;
494+
}
495+
496+
public void setFreeipaRecipes(Set<String> freeipaRecipes) {
497+
this.freeipaRecipes = freeipaRecipes;
498+
}
499+
484500
@Override
485501
public boolean equals(Object o) {
486502
if (this == o) {
@@ -514,6 +530,7 @@ public String toString() {
514530
", accountId='" + accountId + '\'' +
515531
", resourceCrn='" + resourceCrn + '\'' +
516532
", status=" + status +
533+
", freeipaRecipes='" + freeipaRecipes + '\'' +
517534
", deletionType=" + deletionType +
518535
'}';
519536
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package com.sequenceiq.environment.environment.domain;
2+
3+
import javax.persistence.Column;
4+
import javax.persistence.Entity;
5+
import javax.persistence.GeneratedValue;
6+
import javax.persistence.GenerationType;
7+
import javax.persistence.Id;
8+
import javax.persistence.SequenceGenerator;
9+
import javax.persistence.Table;
10+
11+
@Entity
12+
@Table(name = "environment_freeiparecipes")
13+
public class FreeIpaRecipe {
14+
15+
@Id
16+
@GeneratedValue(strategy = GenerationType.AUTO, generator = "environment_freeiparecipes_generator")
17+
@SequenceGenerator(name = "environment_freeiparecipes_generator", sequenceName = "environment_freeiparecipes_id_seq", allocationSize = 1)
18+
private Long id;
19+
20+
@Column(name = "environment_id")
21+
private long environmentId;
22+
23+
private String recipe;
24+
25+
public FreeIpaRecipe() {
26+
}
27+
28+
public FreeIpaRecipe(long environmentId, String recipe) {
29+
this.environmentId = environmentId;
30+
this.recipe = recipe;
31+
}
32+
33+
public Long getId() {
34+
return id;
35+
}
36+
37+
public void setId(Long id) {
38+
this.id = id;
39+
}
40+
41+
public long getEnvironmentId() {
42+
return environmentId;
43+
}
44+
45+
public void setEnvironmentId(long environmentId) {
46+
this.environmentId = environmentId;
47+
}
48+
49+
public String getRecipe() {
50+
return recipe;
51+
}
52+
53+
public void setRecipe(String recipe) {
54+
this.recipe = recipe;
55+
}
56+
57+
@Override
58+
public String toString() {
59+
return "FreeIpaRecipe{" +
60+
"id=" + id +
61+
", environmentId=" + environmentId +
62+
", recipe='" + recipe + '\'' +
63+
'}';
64+
}
65+
66+
}

0 commit comments

Comments
 (0)