Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2014 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.controllers
import com.fasterxml.jackson.databind.ObjectMapper
import com.google.common.annotations.VisibleForTesting
import com.netflix.spectator.api.Registry
import com.netflix.spinnaker.kork.web.exceptions.NotFoundException
import com.netflix.spinnaker.orca.api.pipeline.graph.StageDefinitionBuilder
import com.netflix.spinnaker.orca.api.pipeline.models.*
import com.netflix.spinnaker.orca.front50.Front50Service
import com.netflix.spinnaker.orca.model.OrchestrationViewModel
import com.netflix.spinnaker.orca.pipeline.CompoundExecutionOperator
import com.netflix.spinnaker.orca.pipeline.ExecutionRunner
import com.netflix.spinnaker.orca.pipeline.StageDefinitionBuilderFactory
import com.netflix.spinnaker.orca.pipeline.persistence.ExecutionNotFoundException
import com.netflix.spinnaker.orca.pipeline.persistence.ExecutionRepository
import com.netflix.spinnaker.orca.pipeline.util.ContextParameterProcessor
import com.netflix.spinnaker.orca.util.ExpressionUtils
import com.netflix.spinnaker.security.AuthenticatedRequest
import groovy.transform.InheritConstructors
import groovy.util.logging.Slf4j
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.http.HttpStatus
import org.springframework.security.access.prepost.PostAuthorize
import org.springframework.security.access.prepost.PostFilter
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.security.access.prepost.PreFilter
import org.springframework.web.bind.annotation.*
import rx.schedulers.Schedulers
import java.nio.charset.Charset
import java.time.Clock
import java.time.ZoneOffset
import java.util.concurrent.TimeUnit
import java.util.stream.Collectors
import static com.netflix.spinnaker.orca.api.pipeline.models.ExecutionType.ORCHESTRATION
import static com.netflix.spinnaker.orca.api.pipeline.models.ExecutionType.PIPELINE
import static com.netflix.spinnaker.orca.pipeline.persistence.ExecutionRepository.ExecutionComparator.*
import static com.netflix.spinnaker.orca.pipeline.persistence.ExecutionRepository.ExecutionComparator
import static com.netflix.spinnaker.orca.pipeline.persistence.ExecutionRepository.ExecutionCriteria
import static java.time.temporal.ChronoUnit.DAYS
@Slf4j
@RestController
class TaskController {
@Autowired(required = false)
Front50Service front50Service
@Autowired
ExecutionRepository executionRepository
@Autowired
ExecutionRunner executionRunner
@Autowired
CompoundExecutionOperator executionOperator
@Autowired
Collection stageBuilders
@Autowired
ContextParameterProcessor contextParameterProcessor
@Autowired
ExpressionUtils expressionUtils
@Autowired
ObjectMapper mapper
@Autowired
Registry registry
@Autowired
StageDefinitionBuilderFactory stageDefinitionBuilderFactory
@Value('${tasks.days-of-execution-history:14}')
int daysOfExecutionHistory
@Value('${tasks.number-of-old-pipeline-executions-to-include:2}')
int numberOfOldPipelineExecutionsToInclude
Clock clock = Clock.systemUTC()
@PreAuthorize("hasPermission(#application, 'APPLICATION', 'READ')")
@RequestMapping(value = "/applications/{application}/tasks", method = RequestMethod.GET)
List list(
@PathVariable String application,
@RequestParam(value = "page", defaultValue = "1") int page,
@RequestParam(value = "limit", defaultValue = "3500") int limit,
@RequestParam(value = "statuses", required = false) String statuses
) {
statuses = statuses ?: ExecutionStatus.values()*.toString().join(",")
def executionCriteria = new ExecutionCriteria()
.setPage(page)
.setPageSize(limit)
.setStatuses(statuses.split(",") as Collection)
.setStartTimeCutoff(
clock
.instant()
.atZone(ZoneOffset.UTC)
.minusDays(daysOfExecutionHistory)
.toInstant()
)
executionRepository.retrieveOrchestrationsForApplication(
application,
executionCriteria,
START_TIME_OR_ID
).collect { convert(it) }
}
@PreAuthorize("@fiatPermissionEvaluator.storeWholePermission()")
@PostFilter("hasPermission(filterObject.application, 'APPLICATION', 'READ')")
@RequestMapping(value = "/tasks", method = RequestMethod.GET)
List list() {
executionRepository.retrieve(ORCHESTRATION).toBlocking().iterator.collect {
convert it
}
}
// @PostAuthorize("hasPermission(returnObject.application, 'APPLICATION', 'READ')")
//
// This endpoint is unsecured because of the create application process, where Deck immediately
// queries this endpoint to check on the status of creating a new application before the
// application permissions have been propagated. Furthermore, given that the ID is a hard-to-guess
// GUID, it's unlikely than an attacker would be able to guess the identifier for any task.
@RequestMapping(value = "/tasks/{id}", method = RequestMethod.GET)
OrchestrationViewModel getTask(@PathVariable String id) {
convert executionRepository.retrieve(ORCHESTRATION, id)
}
PipelineExecution getOrchestration(String id) {
executionRepository.retrieve(ORCHESTRATION, id)
}
@PreAuthorize("hasPermission(this.getOrchestration(#id)?.application, 'APPLICATION', 'WRITE')")
@RequestMapping(value = "/tasks/{id}", method = RequestMethod.DELETE)
void deleteTask(@PathVariable String id) {
executionRepository.retrieve(ORCHESTRATION, id).with {
if (it.status.complete) {
executionRepository.delete(ORCHESTRATION, id)
} else {
log.warn("Not deleting $ORCHESTRATION $id as it is $it.status")
throw new CannotDeleteRunningExecution(ORCHESTRATION, id)
}
}
}
@PreAuthorize("hasPermission(this.getOrchestration(#id)?.application, 'APPLICATION', 'EXECUTE')")
@RequestMapping(value = "/tasks/{id}/cancel", method = RequestMethod.PUT)
@ResponseStatus(HttpStatus.ACCEPTED)
void cancelTask(@PathVariable String id) {
executionOperator.cancel(ORCHESTRATION, id)
}
@PreFilter("hasPermission(this.getOrchestration(filterObject)?.application, 'APPLICATION', 'EXECUTE')")
@RequestMapping(value = "/tasks/cancel", method = RequestMethod.PUT)
@ResponseStatus(HttpStatus.ACCEPTED)
void cancelTasks(@RequestBody List taskIds) {
taskIds.each {
executionOperator.cancel(ORCHESTRATION, it)
}
}
/**
* Retrieves an ad-hoc collection of executions based on a number of user-supplied parameters. Either executionIds or
* pipelineConfigIds must be supplied in order to return any results. If both are supplied, an IllegalArgumentException
* will be thrown.
* @param pipelineConfigIds A comma-separated list of pipeline config ids
* @param executionIds A comma-separated list of execution ids; if specified, limit and statuses parameters will be
* ignored
* @param limit (optional) Number of most recent executions to retrieve per pipeline config; defaults to 1, ignored if
* executionIds is specified
* @param statuses (optional) Execution statuses to filter results by; defaults to all, ignored if executionIds is
* specified
* @param expand (optional) Expands each execution object in the resulting list. If this value is missing,
* it is defaulted to true.
* @return
*/
@PostFilter("hasPermission(filterObject.application, 'APPLICATION', 'READ')")
@RequestMapping(value = "/pipelines", method = RequestMethod.GET)
List listSubsetOfPipelines(
@RequestParam(value = "pipelineConfigIds", required = false) String pipelineConfigIds,
@RequestParam(value = "executionIds", required = false) String executionIds,
@RequestParam(value = "limit", required = false) Integer limit,
@RequestParam(value = "statuses", required = false) String statuses,
@RequestParam(value = "expand", defaultValue = "true") boolean expand) {
statuses = statuses ?: ExecutionStatus.values()*.toString().join(",")
limit = limit ?: 1
ExecutionCriteria executionCriteria = new ExecutionCriteria(
pageSize: limit,
statuses: (statuses.split(",") as Collection)
)
if (!pipelineConfigIds && !executionIds) {
return []
}
if (pipelineConfigIds && executionIds) {
throw new IllegalArgumentException("Only pipelineConfigIds OR executionIds can be specified")
}
if (executionIds) {
List ids = executionIds.split(',')
List executions = rx.Observable.from(ids.collect {
try {
executionRepository.retrieve(PIPELINE, it)
} catch (ExecutionNotFoundException e) {
null
}
}).subscribeOn(Schedulers.io()).toList().toBlocking().single().findAll()
if (!expand) {
unexpandPipelineExecutions(executions)
}
return executions
}
List ids = pipelineConfigIds.split(',')
List allPipelines = rx.Observable.merge(ids.collect {
executionRepository.retrievePipelinesForPipelineConfigId(it, executionCriteria)
}).subscribeOn(Schedulers.io()).toList().toBlocking().single().sort(startTimeOrId)
if (!expand) {
unexpandPipelineExecutions(allPipelines)
}
return filterPipelinesByHistoryCutoff(allPipelines, limit)
}
/**
* Search for pipeline executions using a combination of criteria. The returned list is sorted by
* buildTime (trigger time) in reverse order so that newer executions are first in the list.
*
* @param application Only includes executions that are part of this application. If this value is
* '*', includes executions of all applications.
* @param triggerTypes (optional) Only includes executions that were triggered by a trigger with a
* type that is equal to a type provided in this field. The list of trigger types should be a
* comma-delimited string. If this value is missing, includes executions of all trigger types.
* @param pipelineName (optional) Only includes executions that with this pipeline name.
* @param eventId (optional) Only includes executions that were triggered by a trigger with this
* eventId. This only applies to triggers that return a response message when called.
* @param trigger (optional) Only includes executions that were triggered by a trigger that
* matches the subset of fields provided by this value. This value should be a base64-encoded
* string of a JSON representation of a trigger object. The comparison succeeds if the execution
* trigger contains all the fields of the input trigger, the fields are of the same type, and each
* value of the field "matches". The term "matches" is specific for each field's type:
* - For Strings: A String value in the execution's trigger matches the input trigger's String
* value if the former equals the latter (case-insensitive) OR if the former matches the latter as
* a regular expression.
* - For Maps: A Map value in the execution's trigger matches the input trigger's Map value if the
* former contains all keys of the latter and their values match.
* - For Collections: A Collection value in the execution's trigger matches the input trigger's
* Collection value if the former has a unique element that matches each element of the latter.
* - Every other value is compared using the Java "equals" method (Groovy "==" operator)
* @param triggerTimeStartBoundary (optional) Only includes executions that were built at or after
* the given time, represented as a Unix timestamp in ms (UTC). This value must be >= 0 and <=
* the value of [triggerTimeEndBoundary], if provided. If this value is missing, it is defaulted
* to 0.
* @param triggerTimeEndBoundary (optional) Only includes executions that were built at or before
* the given time, represented as a Unix timestamp in ms (UTC). This value must be <=
* 9223372036854775807 (Long.MAX_VALUE) and >= the value of [triggerTimeStartBoundary], if
* provided. If this value is missing, it is defaulted to 9223372036854775807.
* @param statuses (optional) Only includes executions with a status that is equal to a status
* provided in this field. The list of statuses should be given as a comma-delimited string. If
* this value is missing, includes executions of all statuses. Allowed statuses are: NOT_STARTED,
* RUNNING, PAUSED, SUSPENDED, SUCCEEDED, FAILED_CONTINUE, TERMINAL, CANCELED, REDIRECT, STOPPED,
* SKIPPED, BUFFERED. @see com.netflix.spinnaker.orca.ExecutionStatus for more info.
* @param startIndex (optional) Sets the first item of the resulting list for pagination. The list
* is 0-indexed. This value must be >= 0. If this value is missing, it is defaulted to 0.
* @param size (optional) Sets the size of the resulting list for pagination. This value must be >
* 0. If this value is missing, it is defaulted to 10.
* @param reverse (optional) Reverses the resulting list before it is paginated. If this value is
* missing, it is defaulted to false.
* @param expand (optional) Expands each execution object in the resulting list. If this value is
* missing, it is defaulted to false.
* @return
*/
@PreAuthorize("hasPermission(#application, 'APPLICATION', 'READ')")
@RequestMapping(value = "/applications/{application}/pipelines/search", method = RequestMethod.GET)
List searchForPipelinesByTrigger(
@PathVariable(value = "application") String application,
@RequestParam(value = "triggerTypes", required = false) String triggerTypes,
@RequestParam(value = "pipelineName", required = false) String pipelineName,
@RequestParam(value = "eventId", required = false) String eventId,
@RequestParam(value = "trigger", required = false) String encodedTriggerParams,
@RequestParam(value = "triggerTimeStartBoundary", defaultValue = "0") long triggerTimeStartBoundary,
@RequestParam(value = "triggerTimeEndBoundary", defaultValue = "9223372036854775807" /* Long.MAX_VALUE */) long triggerTimeEndBoundary,
@RequestParam(value = "statuses", required = false) String statuses,
@RequestParam(value = "startIndex", defaultValue = "0") int startIndex,
@RequestParam(value = "size", defaultValue = "10") int size,
@RequestParam(value = "reverse", defaultValue = "false") boolean reverse,
@RequestParam(value = "expand", defaultValue = "false") boolean expand
// TODO(joonlim): May make sense to add a summary boolean so that, when true, this returns a condensed summary rather than complete execution objects.
) {
validateSearchForPipelinesByTriggerParameters(triggerTimeStartBoundary, triggerTimeEndBoundary, startIndex, size)
ExecutionComparator sortType = BUILD_TIME_DESC
if (reverse) {
sortType = BUILD_TIME_ASC
}
// Returned map will be empty if encodedTriggerParams is null
final Map triggerParams = decodeTriggerParams(encodedTriggerParams)
Set triggerTypesAsSet = (triggerTypes && triggerTypes != "*")
? triggerTypes.split(",") as Set
: null // null means all trigger types
// Filter by application (and pipeline name, if that parameter has been given in addition to application name)
List pipelineConfigIds
if (application == "*") {
pipelineConfigIds = getPipelineConfigIdsOfReadableApplications()
} else {
List