Skip to content

Commit

Permalink
feat(kubernetes): add expression evaluation options to bake and deplo…
Browse files Browse the repository at this point in the history
…y manifest stages
  • Loading branch information
maggieneterval committed Mar 18, 2019
1 parent 2bcb0f7 commit 0d54daa
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2019 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.orca.bakery.tasks.manifests;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.netflix.spinnaker.kork.artifacts.model.ExpectedArtifact;
import lombok.Getter;

import java.util.List;
import java.util.Map;

@Getter
public class BakeManifestContext {
private final List<CreateBakeManifestTask.InputArtifactPair> inputArtifacts;
private final List<ExpectedArtifact> expectedArtifacts;
private final Map<String, Object> overrides;
private final Boolean evaluateOverrideExpressions;
private final String templateRenderer;
private final String outputName;
private final String namespace;

// There does not seem to be a way to auto-generate a constructor using our current version of Lombok (1.16.20) that
// Jackson can use to deserialize.
public BakeManifestContext(
@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
) {
this.inputArtifacts = inputArtifacts;
this.expectedArtifacts = expectedArtifacts;
this.overrides = overrides;
this.evaluateOverrideExpressions = evaluateOverrideExpressions;
this.templateRenderer = templateRenderer;
this.outputName = outputName;
this.namespace = namespace;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

package com.netflix.spinnaker.orca.bakery.tasks.manifests;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.spinnaker.kork.artifacts.model.Artifact;
import com.netflix.spinnaker.kork.artifacts.model.ExpectedArtifact;
Expand All @@ -28,6 +27,7 @@
import com.netflix.spinnaker.orca.bakery.api.manifests.helm.HelmBakeManifestRequest;
import com.netflix.spinnaker.orca.pipeline.model.Stage;
import com.netflix.spinnaker.orca.pipeline.util.ArtifactResolver;
import com.netflix.spinnaker.orca.pipeline.util.ContextParameterProcessor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -62,12 +62,15 @@ public long getTimeout() {
@Autowired
ObjectMapper objectMapper;

@Autowired
ContextParameterProcessor contextParameterProcessor;

@Nonnull
@Override
public TaskResult execute(@Nonnull Stage stage) {
Map<String, Object> context = stage.getContext();
BakeManifestContext context = stage.mapTo(BakeManifestContext.class);

List<InputArtifactPair> inputArtifactsObj = objectMapper.convertValue(context.get("inputArtifacts"), new TypeReference<List<InputArtifactPair>>() {});
List<InputArtifactPair> inputArtifactsObj = context.getInputArtifacts();
List<Artifact> inputArtifacts;

if (inputArtifactsObj == null || inputArtifactsObj.isEmpty()) {
Expand All @@ -84,7 +87,7 @@ public TaskResult execute(@Nonnull Stage stage) {
return a;
}).collect(Collectors.toList());

List<ExpectedArtifact> expectedArtifacts = objectMapper.convertValue(context.get("expectedArtifacts"), new TypeReference<List<ExpectedArtifact>>() {});
List<ExpectedArtifact> expectedArtifacts = context.getExpectedArtifacts();

if (expectedArtifacts == null || expectedArtifacts.isEmpty()) {
throw new IllegalArgumentException("At least one expected artifact to baked manifest must be supplied");
Expand All @@ -96,12 +99,22 @@ public TaskResult execute(@Nonnull Stage stage) {

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

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((String) context.get("templateRenderer"));
request.setOutputName((String) context.get("outputName"));
request.setOverrides(objectMapper.convertValue(context.get("overrides"), new TypeReference<Map<String, Object>>() { }));
request.setNamespace((String) context.get("namespace"));
request.setTemplateRenderer(context.getTemplateRenderer());
request.setOutputName(context.getOutputName());
request.setOverrides(overrides);
request.setNamespace(context.getNamespace());
request.setOutputArtifactName(outputArtifactName);

log.info("Requesting {}", request);
Expand All @@ -114,7 +127,7 @@ public TaskResult execute(@Nonnull Stage stage) {
}

@Data
private static class InputArtifactPair {
protected static class InputArtifactPair {
String id;
String account;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright 2019 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.orca.clouddriver.tasks.manifest;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;

import java.util.HashMap;
import java.util.List;

@Getter
public class DeployManifestContext extends HashMap<String, Object> {
private final String source;
private final String manifestArtifactId;
private final String manifestArtifactAccount;
private final Boolean skipExpressionEvaluation;
private final List<String> requiredArtifactIds;

// There does not seem to be a way to auto-generate a constructor using our current version of Lombok (1.16.20) that
// Jackson can use to deserialize.
public DeployManifestContext(
@JsonProperty("source") String source,
@JsonProperty("manifestArtifactId") String manifestArtifactId,
@JsonProperty("manifestArtifactAccount") String manifestArtifactAccount,
@JsonProperty("skipExpressionEvaluation") Boolean skipExpressionEvaluation,
@JsonProperty("requiredArtifactIds") List<String> requiredArtifactIds
){
this.source = source;
this.manifestArtifactId = manifestArtifactId;
this.manifestArtifactAccount = manifestArtifactAccount;
this.skipExpressionEvaluation = skipExpressionEvaluation;
this.requiredArtifactIds = requiredArtifactIds;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,26 +80,29 @@ public TaskResult execute(@Nonnull Stage stage) {
String cloudProvider = getCloudProvider(stage);

List<Artifact> artifacts = artifactResolver.getArtifacts(stage);
Map task = new HashMap(stage.getContext());
String artifactSource = (String) task.get("source");
DeployManifestContext context = stage.mapTo(DeployManifestContext.class);
Map<String, Object> task = new HashMap<>(context);
String artifactSource = context.getSource();
if (StringUtils.isNotEmpty(artifactSource) && artifactSource.equals("artifact")) {
if (task.get("manifestArtifactId") == null) {
String manifestArtifactId = context.getManifestArtifactId();
if (manifestArtifactId == null) {
throw new IllegalArgumentException("No manifest artifact was specified.");
}

if (task.get("manifestArtifactAccount") == null) {
String manifestArtifactAccount = context.getManifestArtifactAccount();
if (manifestArtifactAccount == null) {
throw new IllegalArgumentException("No manifest artifact account was specified.");
}

Artifact manifestArtifact = artifactResolver.getBoundArtifactForId(stage, task.get("manifestArtifactId").toString());
Artifact manifestArtifact = artifactResolver.getBoundArtifactForId(stage, manifestArtifactId);

if (manifestArtifact == null) {
throw new IllegalArgumentException("No artifact could be bound to '" + task.get("manifestArtifactId") + "'");
throw new IllegalArgumentException("No artifact could be bound to '" + manifestArtifactId + "'");
}

log.info("Using {} as the manifest to be deployed", manifestArtifact);

manifestArtifact.setArtifactAccount((String) task.get("manifestArtifactAccount"));
manifestArtifact.setArtifactAccount(manifestArtifactAccount);
Object parsedManifests = retrySupport.retry(() -> {
try {
Response manifestText = oort.fetchArtifact(manifestArtifact);
Expand All @@ -119,14 +122,17 @@ public TaskResult execute(@Nonnull Stage stage) {
Map<String, Object> manifestWrapper = new HashMap<>();
manifestWrapper.put("manifests", manifests);

manifestWrapper = contextParameterProcessor.process(
Boolean skipExpressionEvaluation = context.getSkipExpressionEvaluation();
if (skipExpressionEvaluation == null || !skipExpressionEvaluation) {
manifestWrapper = contextParameterProcessor.process(
manifestWrapper,
contextParameterProcessor.buildExecutionContext(stage, true),
true
);
);

if (manifestWrapper.containsKey("expressionEvaluationSummary")) {
throw new IllegalStateException("Failure evaluating manifest expressions: " + manifestWrapper.get("expressionEvaluationSummary"));
if (manifestWrapper.containsKey("expressionEvaluationSummary")) {
throw new IllegalStateException("Failure evaluating manifest expressions: " + manifestWrapper.get("expressionEvaluationSummary"));
}
}

return manifestWrapper.get("manifests");
Expand All @@ -140,7 +146,7 @@ public TaskResult execute(@Nonnull Stage stage) {
task.put("source", "text");
}

List<String> requiredArtifactIds = (List<String>) task.get("requiredArtifactIds");
List<String> requiredArtifactIds = context.getRequiredArtifactIds();
List<Artifact> requiredArtifacts = new ArrayList<>();
requiredArtifactIds = requiredArtifactIds == null ? new ArrayList<>() : requiredArtifactIds;
for (String id : requiredArtifactIds) {
Expand Down

0 comments on commit 0d54daa

Please sign in to comment.