Skip to content

Release v1.1.2

Latest

Choose a tag to compare

@github-actions github-actions released this 16 Aug 14:32
4fdb7ab
feat: CDSH-149: Add backward compatibility with 1.27.x. (#47)

Link to the Issue: https://armory.atlassian.net/browse/CDSH-149

**Summary:**

This report pertains to an incident in which a bundled deployment
configuration comprising 20 pipelines, each identifiable by a unique
identifier, exhibited unexpected behavior. Specifically, only 19
pipelines were executed as anticipated, while the user interface
indicated that one pipeline was executed twice.

**Environmental Context:**

* Spinnaker Version: 2.28.4
* Plugin Version: 1.1.0

**Implemented Modifications:**

1. Ensured Compatibility: Verified compatibility with Spinnaker version
2.27.x and above.
2. Dependency Removal: Eliminated plugin dependencies, given the absence
of any remaining local bean dependencies.

```
    private static final List<String> ORCA_BEANS_DEPENDING_ON_PLUGIN = List.of(
            "sqlConfiguration",
            "artifactUtils",
            "sqlOrcaQueueConfiguration",
            "dependentPipelineStarter"
    );
```

3. Removal of Redundant Components: Deleted the subsequent files:

```
orca-run-multiple-pipelines/src/main/kotlin/io/armory/plugin/smp/sql/ConcurrentSqlExecutionRepository.kt
orca-run-multiple-pipelines/src/main/kotlin/io/armory/plugin/smp/sql/MySqlConfiguration.kt
orca-run-multiple-pipelines/src/main/kotlin/io/armory/plugin/smp/sql/jooq.kt
```

Rationale: These files were duplicative versions of corresponding OSS
classes. While minor discrepancies existed:

OSS:

```
storeCorrelationIdInternal(ctx, execution)
```

Plugin:

```
            val executor = Executors.newSingleThreadExecutor()
            if ( execution.type == PIPELINE && execution.trigger.correlationId != null
                && body.contains("\"runMultiplePipelines\"") ) {
                executor.runCatching {
                    storeCorrelationIdInternal(ctx, execution)
                }
                if (!executor.isTerminated) {
                    executor.awaitTermination(1, TimeUnit.SECONDS)
                }
            } else {
                storeCorrelationIdInternal(ctx, execution)
            }
```

Explanation: The functionality remains consistent across both branches.
Hypothesis: These changes aimed to resolve the same issue but were
erroneously applied.

OSS:

```
        val exists = ctx.fetchExists(
          ctx.select()
            .from("correlation_ids")
            .where(field("id").eq(execution.trigger.correlationId))
            .and(executionIdField.eq(execution.id))
        )
        if (!exists) {
          ctx.insertInto(table("correlation_ids"))
            .columns(field("id"), executionIdField)
            .values(execution.trigger.correlationId, execution.id)
            .execute()
        }
```

Plugin:

```
              val exists = AtomicBoolean(
                    ctx.fetchExists(
                        ctx.select()
                            .from("correlation_ids")
                            .where(field("id").eq(execution.trigger.correlationId))
                            .and(executionIdField.eq(execution.id))
                    )
                )

                if (!exists.get()) {
                    ctx.insertInto(table("correlation_ids"))
                        .columns(field("id"), executionIdField)
                        .values(execution.trigger.correlationId, execution.id)
                        .execute()
                }
```

Explanation: The usage of AtomicBoolean in this context lacks
justification.
Hypothesis: These changes aimed to resolve the same issue but were
erroneously applied.

4. Removal of Redundant Components: Deleted the subsequent files:

```
orca-run-multiple-pipelines/src/main/java/io/armory/plugin/smp/execution/MyExecutionLauncher.java
```

Rationale: This file was removed as it duplicated OSS classes, differing
only in a single aspect:

OSS:

```
  public PipelineExecution start(ExecutionType type, Map<String, Object> config) {
    final PipelineExecution execution = parse(type, config);
    final PipelineExecution existingExecution = checkForCorrelatedExecution(execution);

    if (existingExecution != null) {
      return existingExecution;
    }
```

Plugin:

```
    public PipelineExecution start(ExecutionType type, Map<String, Object> config) {
        PipelineExecution execution = parse(type, config);
        PipelineExecution existingExecution = checkForCorrelatedExecution(execution);

        if (existingExecution != null) {
            if (config.containsKey("correlationId") && config.containsKey("parentExecution")
                    && config.containsKey("\"type\":\"runMultiplePipelines\"")) {
                existingExecution = null;
            }
        }

        if (existingExecution != null) {
            return existingExecution;
        }
```

Explanation: The configuration keys `parentExecution` and
`correlationId` are no longer available, these modifications no longer
relevant.

**Issue Reason:**

The initial occurrence of the issue stemmed from the non-thread-safe
nature of the `pipelineExecutions` list. Concurrent modifications from
distinct threads led to the observed behavior. It was fixed
[here](https://github.com/armory-plugins/spinnaker-multiple-pipelines/pull/46).

```
List<PipelineExecution> pipelineExecutions = Collections.synchronizedList(new ArrayList<>());
```

**Tested with:**

* Spinnaker Version: 2.28.4
* Spinnaker Version: 2.30.0