Skip to content

Commit

Permalink
feat(plugins): Add remote extensions field to a plugin info release (#…
Browse files Browse the repository at this point in the history
…917)

* feat(plugins): Add remote extensions field to plugin info

* chore(plugins): Addressing comments
  • Loading branch information
jonsie committed Aug 4, 2020
1 parent eef8de4 commit 5ed028d
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.base.Splitter;
import com.netflix.spinnaker.front50.model.Timestamped;
import com.netflix.spinnaker.front50.model.plugins.remote.RemoteExtension;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -181,6 +182,9 @@ public List<ServiceRequirement> getParsedRequires() {
public boolean supportsService(@Nonnull String service) {
return getParsedRequires().stream().anyMatch(it -> it.getService().equalsIgnoreCase(service));
}

/** Remote extensions associated with this plugin release. */
@Nonnull private List<RemoteExtension> remoteExtensions = new ArrayList<>();
}

@Data
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.netflix.spinnaker.front50.model.plugins.remote;

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.netflix.spinnaker.front50.model.plugins.PluginInfo;
import com.netflix.spinnaker.front50.model.plugins.remote.stage.StageRemoteExtensionConfig;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.URL;

/**
* A Spinnaker plugin's remote extension configuration.
*
* <p>This model is used by Spinnaker to determine which extension points and services require
* remote extension point configuration.
*
* <p>The plugin release {@link PluginInfo.Release#requires} field is used to inform Spinnaker which
* service to use in configuring the extension point {@link #type} and additionally if the remote
* extension is compatible with the running version of the Spinnaker service.
*/
@Data
@NoArgsConstructor
public class RemoteExtension {

/**
* The remote extension type. The remote extension is configured in the service that implements
* this extension type.
*/
@Nonnull private String type;

/** Identifier of the remote extension. Used for tracing. */
@Nonnull private String id;

/**
* Outbound transport configuration for the remote extension point; the protocol to address it
* with and the necessary configuration.
*/
@Nonnull private RemoteExtensionTransport transport = new RemoteExtensionTransport();

/** Configures the remote extension point. */
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
property = "type")
@JsonSubTypes({@JsonSubTypes.Type(value = StageRemoteExtensionConfig.class, name = "stage")})
@Nullable
public RemoteExtensionConfig config;

/** Root remote extension configuration type. */
public interface RemoteExtensionConfig {}

@Data
@NoArgsConstructor
public static class RemoteExtensionTransport {

@Nonnull private Http http = new Http();

@Data
@NoArgsConstructor
public static class Http {

/** URL for remote extension invocation. */
@URL @Nonnull private String url;

/** A placeholder for misc. configuration for the underlying HTTP client. */
@Nonnull private Map<String, Object> config = new HashMap<>();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.netflix.spinnaker.front50.model.plugins.remote.stage;

import com.netflix.spinnaker.front50.model.plugins.remote.RemoteExtension.RemoteExtensionConfig;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nonnull;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class StageRemoteExtensionConfig implements RemoteExtensionConfig {

/** Represents stage type. */
@Nonnull private String type;

/** Label to use on the Spinnaker UI while configuring pipeline stages. */
@Nonnull private String label;

/** Description to use on the Spinnaker UI while configuring pipeline stages. */
@Nonnull private String description;

/** Map of stage parameter names and default values. */
@Nonnull private Map<String, Object> parameters = new HashMap<>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ package com.netflix.spinnaker.front50.model.plugins

import com.netflix.spinnaker.front50.echo.EchoService
import com.netflix.spinnaker.front50.exception.NotFoundException
import com.netflix.spinnaker.front50.model.plugins.remote.RemoteExtension
import com.netflix.spinnaker.front50.model.plugins.remote.stage.StageRemoteExtensionConfig
import com.netflix.spinnaker.front50.plugins.PluginBinaryStorageService
import com.netflix.spinnaker.front50.validator.PluginInfoValidator
import com.netflix.spinnaker.kork.web.exceptions.InvalidRequestException
Expand Down Expand Up @@ -58,14 +60,30 @@ class PluginInfoServiceSpec extends Specification {
0 * repository.create(_, _)
}

def "upsert with a new release for an existing plugin"() {
def "upsert with a new release for an existing plugin, new release contains remote extension configuration"() {
given:
PluginInfo currentPluginInfo = new PluginInfo(id: "foo.bar")
currentPluginInfo.releases.add(new PluginInfo.Release(version: "1.0.0"))

and:
PluginInfo newPluginInfo = new PluginInfo(id: "foo.bar")
newPluginInfo.releases.add(new PluginInfo.Release(version: "2.0.0"))
newPluginInfo.releases.get(0).remoteExtensions.add(
new RemoteExtension(
type: "stage",
id: "netflix.remote.remoteWait",
transport: new RemoteExtension.RemoteExtensionTransport(
http: new RemoteExtension.RemoteExtensionTransport.Http(
url: "http://example.com"
)
),
config: new StageRemoteExtensionConfig(
type: "remoteWait",
label: "Wait on a remote service",
description: "A stage that waits on a remote service",
parameters: ["waitTime": 30, "message": "Done"]
)
))

when:
PluginInfo persistedPluginInfo = subject.upsert(newPluginInfo)
Expand Down

0 comments on commit 5ed028d

Please sign in to comment.