Skip to content

Commit

Permalink
fix(stage): Resource requests on custom stage | Error: got "map", exp…
Browse files Browse the repository at this point in the history
…ected "string…" (backport #4295) (#4329)

Co-authored-by: armory-abedonik <106548537+armory-abedonik@users.noreply.github.com>
  • Loading branch information
mergify[bot] and armory-abedonik committed Nov 8, 2022
1 parent 1a60144 commit c055dd0
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,31 @@
package com.netflix.spinnaker.orca.clouddriver.pipeline.job

import com.fasterxml.jackson.databind.ObjectMapper
import com.netflix.spinnaker.orca.api.pipeline.graph.TaskNode
import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution
import com.netflix.spinnaker.orca.api.preconfigured.jobs.PreconfiguredJobStageProperties
import com.netflix.spinnaker.orca.clouddriver.exception.PreconfiguredJobNotFoundException
import com.netflix.spinnaker.orca.clouddriver.service.JobService
import com.netflix.spinnaker.orca.clouddriver.tasks.job.DestroyJobTask
import com.netflix.spinnaker.orca.api.pipeline.graph.TaskNode
import io.kubernetes.client.openapi.JSON
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component

import javax.annotation.Nonnull

import java.util.List

@Component
class PreconfiguredJobStage extends RunJobStage {

private JobService jobService
private ObjectMapper objectMapper
private JSON json

@Autowired
PreconfiguredJobStage(DestroyJobTask destroyJobTask, List<RunJobStageDecorator> runJobStageDecorators, Optional<JobService> optionalJobService) {
super(destroyJobTask, runJobStageDecorators)
this.jobService = optionalJobService.orElse(null)
this.objectMapper = new ObjectMapper()
this.json = new JSON()
}

@Override
Expand All @@ -60,11 +61,17 @@ class PreconfiguredJobStage extends RunJobStage {
PreconfiguredJobStageProperties preconfiguredJob,
String application
) {
// `manifest` field defined in `KubernetesPreconfiguredJobProperties` class has
// `io.kubernetes.client.openapi.models.V1Job` type. This type is defined in Kubernetes
// Open API models package. This package contains special JSON serializers e.g
// `io.kubernetes.client.custom.Quantity.QuantityAdapter`. They must be used to get correct JSON format.
String preconfiguredJobJson = json.getGson().toJson(preconfiguredJob)

// without converting this object, assignments to `context[it]` will result in
// references being assigned instead of values which causes the overrides in context
// to override the underlying job. this avoids that problem by giving us a fresh "copy"
// to work wit
Map<String, Object> preconfiguredMap = objectMapper.convertValue(preconfiguredJob, Map.class)
Map<String, Object> preconfiguredMap = objectMapper.readValue(preconfiguredJobJson, Map.class)

// if we don't specify an application for this preconfigured job, assign the current one.
if (preconfiguredMap["cluster"] != null && preconfiguredMap["cluster"].application == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ import com.netflix.spinnaker.orca.api.preconfigured.jobs.PreconfiguredJobStagePa
import com.netflix.spinnaker.orca.clouddriver.service.JobService
import com.netflix.spinnaker.orca.clouddriver.config.KubernetesPreconfiguredJobProperties
import com.netflix.spinnaker.orca.clouddriver.tasks.job.DestroyJobTask
import io.kubernetes.client.custom.Quantity
import io.kubernetes.client.openapi.models.V1Container
import io.kubernetes.client.openapi.models.V1EnvVar
import io.kubernetes.client.openapi.models.V1Job
import io.kubernetes.client.openapi.models.V1ResourceRequirements
import spock.lang.Specification

import static com.netflix.spinnaker.orca.test.model.ExecutionBuilder.stage
Expand Down Expand Up @@ -267,4 +269,44 @@ class PreconfiguredJobStageSpec extends Specification {
def ex = thrown(IllegalArgumentException)
assert ex.getMessage().startsWith("no property undefined on")
}

def "should serialize kubernetes job manifest correctly"() {
given:
def stage = stage {
type = "test"
context = [account: "test"]
}

def requests = new HashMap<String, Quantity>()
requests.put("cpu", Quantity.fromString("100m"))

def limits = new HashMap<String, Quantity>()
limits.put("cpu", Quantity.fromString("100m"))

def resourceRequirements = new V1ResourceRequirements(requests: requests, limits: limits)

def property = new KubernetesPreconfiguredJobProperties(
enabled: true,
label: "test",
type: "test",
cloudProvider: "kubernetes",
parameters: [],
manifest: new V1Job(spec: [template: [spec: [containers: [new V1Container(resources: resourceRequirements)]]]])
)

def jobService = Mock(JobService) {
1 * getPreconfiguredStages() >> {
return [property]
}
}

when:
PreconfiguredJobStage preconfiguredJobStage = new PreconfiguredJobStage(Mock(DestroyJobTask), [], Optional.of(jobService))
preconfiguredJobStage.buildTaskGraph(stage)

then:
// verify that stage manifest has the correct requests and limits
stage.getContext().get("manifest").spec.template.spec.containers[0].resources.requests.cpu == "100m"
stage.getContext().get("manifest").spec.template.spec.containers[0].resources.limits.cpu == "100m"
}
}

0 comments on commit c055dd0

Please sign in to comment.