Skip to content

Commit

Permalink
feat(runJob): support kubernetes jobs
Browse files Browse the repository at this point in the history
  • Loading branch information
ethanfrogers committed Mar 27, 2019
1 parent 9cb3276 commit 45939d7
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 29 deletions.
1 change: 1 addition & 0 deletions orca-clouddriver/orca-clouddriver.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ dependencies {
compile project(":orca-core")
compile 'com.netflix.spinnaker.moniker:moniker:0.2.0'
compile "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:${spinnaker.version('jackson')}"
compile 'io.kubernetes:client-java:1.0.0-beta1'

testCompile project(":orca-test")
testCompile project(":orca-test-groovy")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@

import java.util.List;

@ConfigurationProperties("job")
@ConfigurationProperties("job.preconfigured")
@Data
public class JobConfigurationProperties {
List<PreconfiguredJobStageProperties> preconfigured;
List<TitusPreconfiguredJobProperties> titus;
List<KubernetesPreconfiguredJobProperties> kubernetes;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2019 Netflix, 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.config;

import com.google.common.collect.ImmutableList;
import io.kubernetes.client.models.V1Job;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Data
@EqualsAndHashCode(callSuper = true)
public class KubernetesPreconfiguredJobProperties extends PreconfiguredJobStageProperties {

private String account;
private String application;
private V1Job manifest;

public List<String> getOverridableFields() {
List<String> overrideableFields = Arrays.asList("account", "manifest", "application");
overrideableFields.addAll(super.getOverridableFields());
return overrideableFields;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,34 @@

package com.netflix.spinnaker.orca.clouddriver.config;

import com.google.common.collect.ImmutableList;
import jdk.nashorn.internal.ir.annotations.Immutable;
import lombok.Data;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;

@Data
public abstract class PreconfiguredJobStageProperties {

public class PreconfiguredJobStageProperties {
private boolean enabled = true;
private String label;
private String description;
private String type;
private List<PreconfiguredJobStageParameter> parameters;
private boolean waitForCompletion = true;
private String cloudProvider;
private String credentials;
private String region;
private String propertyFile;

// Fields are public as job stages use reflection to access these directly from outside the class
public boolean enabled = true;
public String label;
public String description;
public String type;
public List<PreconfiguredJobStageParameter> parameters;
public boolean waitForCompletion = true;
public String cloudProvider;
public String credentials;
public String region;
public String propertyFile;
public Map<String, Object> cluster = new HashMap<>();
public List<String> getOverridableFields() {
return Arrays.asList(
"cloudProvider",
"credentials",
"region",
"propertyFile",
"waitForCompletion"
);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2019 Netflix, 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.config;

import com.google.common.collect.ImmutableList;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.lang.reflect.Array;
import java.util.*;

@Data
@EqualsAndHashCode(callSuper = true)
public class TitusPreconfiguredJobProperties extends PreconfiguredJobStageProperties {

private Map<String, Object> cluster = new HashMap<>();

public List<String> getOverridableFields() {
List<String> overrideableFields = Arrays.asList("cluster");
overrideableFields.addAll(super.getOverridableFields());
return overrideableFields;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ class PreconfiguredJobStage extends RunJobStage {
@Autowired(required=false)
private JobService jobService

def fields = PreconfiguredJobStageProperties.declaredFields.findAll {
!it.synthetic && !['props', 'enabled', 'label', 'description', 'type', 'parameters'].contains(it.name)
}.collect { it.name }

@Override
void taskGraph(Stage stage, TaskNode.Builder builder) {
def preconfiguredJob = jobService.getPreconfiguredStages().find { stage.type == it.type }
Expand All @@ -48,7 +44,7 @@ class PreconfiguredJobStage extends RunJobStage {
}

private Map<String, Object> overrideIfNotSetInContextAndOverrideDefault(Map<String, Object> context, PreconfiguredJobStageProperties preconfiguredJob) {
fields.each {
preconfiguredJob.getOverridableFields().each {
if (context[it] == null || preconfiguredJob[it] != null) {
context[it] = preconfiguredJob[it]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
Expand All @@ -31,10 +32,20 @@ public class JobService {
@Autowired JobConfigurationProperties jobConfigurationProperties;

List<PreconfiguredJobStageProperties> getPreconfiguredStages() {
if(jobConfigurationProperties.getPreconfigured()==null){
if(jobConfigurationProperties.getTitus()==null && jobConfigurationProperties.getKubernetes()==null){
return Collections.EMPTY_LIST;
}
return jobConfigurationProperties.getPreconfigured().stream().filter(it -> it.enabled == true).collect(Collectors.toList());

List<PreconfiguredJobStageProperties> preconfiguredJobStageProperties = new ArrayList<>();
if (jobConfigurationProperties.getTitus() != null && !jobConfigurationProperties.getTitus().isEmpty()) {
preconfiguredJobStageProperties.addAll(jobConfigurationProperties.getTitus());
}

if (jobConfigurationProperties.getKubernetes() != null && !jobConfigurationProperties.getKubernetes().isEmpty()) {
preconfiguredJobStageProperties.addAll(jobConfigurationProperties.getKubernetes());
}

return preconfiguredJobStageProperties;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class KubernetesContainerFinder {
}

containers.forEach { container ->
if (container.imageDescription.fromContext) {
if (container?.imageDescription?.fromContext) {
def image = deploymentDetails.find {
// stageId is used here to match the source of the image to the find image stage specified by the user.
// Previously, this was done by matching the pattern used to the pattern selected in the deploy stage, but
Expand All @@ -83,7 +83,7 @@ class KubernetesContainerFinder {
throw new IllegalStateException("No image found in context for pattern $container.imageDescription.pattern.")
}

if (container.imageDescription.fromTrigger) {
if (container?.imageDescription?.fromTrigger) {
if (stage.execution.type == PIPELINE) {
def trigger = stage.execution.trigger

Expand All @@ -92,12 +92,12 @@ class KubernetesContainerFinder {
}
}

if (!container.imageDescription.tag) {
if (!container?.imageDescription?.tag) {
throw new IllegalStateException("No tag found for image ${container.imageDescription.registry}/${container.imageDescription.repository} in trigger context.")
}
}

if (container.imageDescription.fromArtifact) {
if (container?.imageDescription?.fromArtifact) {
def resolvedArtifact = artifactResolver.getBoundArtifactForId(stage, container.imageDescription.artifactId)
container.imageDescription.uri = resolvedArtifact.reference
}
Expand Down

0 comments on commit 45939d7

Please sign in to comment.