Skip to content

Commit

Permalink
feat(bakeManifest/kustomize): add support for kustomize renderer (#3120)
Browse files Browse the repository at this point in the history
* Bake (Manifest) Stage: Add support both Helm and Kustomize

* fix(kustomize): clean up kustomize bake code
  • Loading branch information
ethanfrogers committed Aug 31, 2019
1 parent ab89a0d commit 2a39bb8
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,18 @@
package com.netflix.spinnaker.orca.bakery.api

import com.netflix.spinnaker.kork.artifacts.model.Artifact
import com.netflix.spinnaker.orca.bakery.api.manifests.helm.HelmBakeManifestRequest
import com.netflix.spinnaker.orca.bakery.api.manifests.BakeManifestRequest
import retrofit.http.*
import rx.Observable


/**
* An interface to the Bakery's REST API.
*/
interface BakeryService {
@POST("/api/v2/manifest/bake/helm")
Artifact bakeManifest(@Body HelmBakeManifestRequest bakeRequest)

@POST("/api/v2/manifest/bake/{type}")
Artifact bakeManifest(@Path("type") String type, @Body BakeManifestRequest bake)

@POST("/api/v1/{region}/bake")
Observable<BakeStatus> createBake(@Path("region") String region, @Body BakeRequest bake, @Query("rebake") String rebake)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,23 @@
package com.netflix.spinnaker.orca.bakery.api.manifests;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.netflix.spinnaker.kork.artifacts.model.Artifact;
import java.util.List;
import java.util.Map;
import lombok.Data;

@Data
public class BakeManifestRequest {
@JsonProperty("templateRenderer")
String templateRenderer;

@JsonProperty("inputArtifacts")
List<Artifact> inputArtifacts;

List<Artifact> values;
private String templateRenderer;

@JsonProperty("outputName")
String outputName;
private String outputName;

@JsonProperty("outputArtifactName")
private String outputArtifactName;

@JsonProperty("overrides")
Map<String, Object> overrides;
public BakeManifestRequest(
String templateRenderer, String outputArtifactName, String outputName) {
this.templateRenderer = templateRenderer;
this.outputArtifactName = outputArtifactName;
this.outputName = outputName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,39 @@
package com.netflix.spinnaker.orca.bakery.api.manifests.helm;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.netflix.spinnaker.kork.artifacts.model.Artifact;
import com.netflix.spinnaker.orca.bakery.api.manifests.BakeManifestRequest;
import com.netflix.spinnaker.orca.bakery.tasks.manifests.BakeManifestContext;
import java.util.List;
import java.util.Map;
import lombok.Data;
import lombok.EqualsAndHashCode;

@Data
@EqualsAndHashCode(callSuper = true)
public class HelmBakeManifestRequest extends BakeManifestRequest {
@JsonProperty("namespace")
String namespace;
private String namespace;

@JsonProperty("outputArtifactName")
String outputArtifactName;
@JsonProperty("overrides")
private Map<String, Object> overrides;

@JsonProperty("inputArtifacts")
private List<Artifact> inputArtifacts;

private List<Artifact> values;

public HelmBakeManifestRequest(
BakeManifestContext bakeManifestContext,
List<Artifact> inputArtifacts,
String outputArtifactName,
Map<String, Object> overrides) {
super(
bakeManifestContext.getTemplateRenderer(),
outputArtifactName,
bakeManifestContext.getOutputName());
this.setOverrides(overrides);
this.setNamespace(bakeManifestContext.getNamespace());
this.setInputArtifacts(inputArtifacts);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2019 Armory
*
* 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.orca.bakery.api.manifests.kustomize;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.netflix.spinnaker.kork.artifacts.model.Artifact;
import com.netflix.spinnaker.orca.bakery.api.manifests.BakeManifestRequest;
import com.netflix.spinnaker.orca.bakery.tasks.manifests.BakeManifestContext;
import lombok.Data;
import lombok.EqualsAndHashCode;

@Data
@EqualsAndHashCode(callSuper = true)
public class KustomizeBakeManifestRequest extends BakeManifestRequest {
@JsonProperty("inputArtifact")
private Artifact inputArtifact;

public KustomizeBakeManifestRequest(
BakeManifestContext bakeManifestContext, Artifact inputArtifact, String outputArtifactName) {
super(
bakeManifestContext.getTemplateRenderer(),
outputArtifactName,
bakeManifestContext.getOutputName());
this.inputArtifact = inputArtifact;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
import com.netflix.spinnaker.kork.artifacts.model.ExpectedArtifact;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import lombok.Getter;

@Getter
public class BakeManifestContext {
private final List<CreateBakeManifestTask.InputArtifactPair> inputArtifacts;
@Nullable private final List<CreateBakeManifestTask.InputArtifactPair> inputArtifacts;
@Nullable private final CreateBakeManifestTask.InputArtifactPair inputArtifact;
private final List<ExpectedArtifact> expectedArtifacts;
private final Map<String, Object> overrides;
private final Boolean evaluateOverrideExpressions;
Expand All @@ -36,19 +38,23 @@ public class BakeManifestContext {
// Lombok (1.16.20) that
// Jackson can use to deserialize.
public BakeManifestContext(
@JsonProperty("inputArtifacts") List<CreateBakeManifestTask.InputArtifactPair> inputArtifacts,
@Nullable @JsonProperty("inputArtifacts")
List<CreateBakeManifestTask.InputArtifactPair> inputArtifacts,
@JsonProperty("expectedArtifacts") List<ExpectedArtifact> expectedArtifacts,
@JsonProperty("overrides") Map<String, Object> overrides,
@JsonProperty("evaluateOverrideExpressions") Boolean evaluateOverrideExpressions,
@JsonProperty("templateRenderer") String templateRenderer,
@JsonProperty("outputName") String outputName,
@JsonProperty("namespace") String namespace) {
@JsonProperty("namespace") String namespace,
@Nullable @JsonProperty("inputArtifact")
CreateBakeManifestTask.InputArtifactPair inputArtifact) {
this.inputArtifacts = inputArtifacts;
this.expectedArtifacts = expectedArtifacts;
this.overrides = overrides;
this.evaluateOverrideExpressions = evaluateOverrideExpressions;
this.templateRenderer = templateRenderer;
this.outputName = outputName;
this.namespace = namespace;
this.inputArtifact = inputArtifact;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
import com.netflix.spinnaker.orca.RetryableTask;
import com.netflix.spinnaker.orca.TaskResult;
import com.netflix.spinnaker.orca.bakery.api.BakeryService;
import com.netflix.spinnaker.orca.bakery.api.manifests.BakeManifestRequest;
import com.netflix.spinnaker.orca.bakery.api.manifests.helm.HelmBakeManifestRequest;
import com.netflix.spinnaker.orca.bakery.api.manifests.kustomize.KustomizeBakeManifestRequest;
import com.netflix.spinnaker.orca.pipeline.model.Stage;
import com.netflix.spinnaker.orca.pipeline.util.ArtifactResolver;
import com.netflix.spinnaker.orca.pipeline.util.ContextParameterProcessor;
Expand Down Expand Up @@ -69,8 +71,14 @@ public TaskResult execute(@Nonnull Stage stage) {
List<InputArtifactPair> inputArtifactsObj = context.getInputArtifacts();
List<Artifact> inputArtifacts;

// kustomize depends on a single input artifact so we may not have a list here
// but we still want the resolution provided by the stream below
if (inputArtifactsObj == null || inputArtifactsObj.isEmpty()) {
throw new IllegalArgumentException("At least one input artifact to bake must be supplied");
if (context.getInputArtifact() != null) {
inputArtifactsObj.add(context.getInputArtifact());
} else {
throw new IllegalArgumentException("At least one input artifact to bake must be supplied");
}
}

inputArtifacts =
Expand Down Expand Up @@ -104,24 +112,32 @@ public TaskResult execute(@Nonnull Stage stage) {

String outputArtifactName = expectedArtifacts.get(0).getMatchArtifact().getName();

// TODO(ethanfrogers): encapsulate this into the HelmBakeManifestRequest
Map<String, Object> overrides = context.getOverrides();
Boolean evaluateOverrideExpressions = context.getEvaluateOverrideExpressions();
if (evaluateOverrideExpressions != null && evaluateOverrideExpressions) {

overrides =
contextParameterProcessor.process(
overrides, contextParameterProcessor.buildExecutionContext(stage, true), true);
}

HelmBakeManifestRequest request = new HelmBakeManifestRequest();
request.setInputArtifacts(inputArtifacts);
request.setTemplateRenderer(context.getTemplateRenderer());
request.setOutputName(context.getOutputName());
request.setOverrides(overrides);
request.setNamespace(context.getNamespace());
request.setOutputArtifactName(outputArtifactName);
BakeManifestRequest request;
switch (context.getTemplateRenderer().toUpperCase()) {
case "HELM2":
request =
new HelmBakeManifestRequest(context, inputArtifacts, outputArtifactName, overrides);
break;
case "KUSTOMIZE":
Artifact inputArtifact = inputArtifacts.get(0);
request = new KustomizeBakeManifestRequest(context, inputArtifact, outputArtifactName);
break;
default:
throw new IllegalArgumentException(
"Invalid template renderer " + context.getTemplateRenderer());
}

log.info("Requesting {}", request);
Artifact result = bakery.bakeManifest(request);
Artifact result = bakery.bakeManifest(request.getTemplateRenderer(), request);

Map<String, Object> outputs = new HashMap<>();
outputs.put("artifacts", Collections.singleton(result));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.netflix.spinnaker.orca.bakery.api.BakeRequest
import com.netflix.spinnaker.orca.bakery.api.BakeStatus
import com.netflix.spinnaker.orca.bakery.api.BakeryService
import com.netflix.spinnaker.orca.bakery.api.BaseImage
import com.netflix.spinnaker.orca.bakery.api.manifests.BakeManifestRequest
import com.netflix.spinnaker.orca.bakery.api.manifests.helm.HelmBakeManifestRequest
import com.netflix.spinnaker.orca.bakery.config.BakeryConfigurationProperties
import com.netflix.spinnaker.orca.pipeline.model.Execution
Expand All @@ -39,7 +40,7 @@ import static com.netflix.spinnaker.orca.test.model.ExecutionBuilder.stage

class BakerySelectorSpec extends Specification {
def bakeryConfigProperties = new BakeryConfigurationProperties(
baseUrl: "http://bakery.com",
baseUrl: "http://bakery.com",
baseUrls: [
new BaseUrl(
baseUrl: "http://rosco.us-east-1.com",
Expand Down Expand Up @@ -126,7 +127,7 @@ class BakerySelectorSpec extends Specification {
}

@Override
Artifact bakeManifest(@Body HelmBakeManifestRequest bakeRequest) {
Artifact bakeManifest(@Path("type") String type, @Body BakeManifestRequest bakeRequest) {
return null
}

Expand Down

0 comments on commit 2a39bb8

Please sign in to comment.