From 204870cc2bcda99167a7691a1c2542971e9b0dc9 Mon Sep 17 00:00:00 2001 From: Cameron Motevasselani Date: Wed, 9 Oct 2019 22:19:30 -0700 Subject: [PATCH 1/4] feat(plugins): use an init container to download plugin resources --- .../config/model/v1/plugins/Manifest.java | 5 +- .../config/model/v1/plugins/Plugin.java | 22 ++-- .../model/v1/plugins/ManifestSpec.groovy | 3 - .../v1/ObjectReplaceTemplatedResource.java | 51 +++++++++ .../core/resource/v1/ObjectResource.java | 30 +++++ .../ObjectReplaceTemplatedResourceSpec.groovy | 54 +++++++++ .../v1/profile/PluginProfileFactory.java | 37 ++++-- .../v1/profile/deck/DeckProfileFactory.java | 41 ++++++- .../spinnaker/v1/service/OrcaService.java | 6 +- .../v2/KubernetesV2DeckService.java | 105 +++++++++++++++++- .../v2/KubernetesV2ServiceTest.groovy | 1 + 11 files changed, 321 insertions(+), 34 deletions(-) create mode 100644 halyard-core/src/main/java/com/netflix/spinnaker/halyard/core/resource/v1/ObjectReplaceTemplatedResource.java create mode 100644 halyard-core/src/main/java/com/netflix/spinnaker/halyard/core/resource/v1/ObjectResource.java create mode 100644 halyard-core/src/test/groovy/com/netflix/spinnaker/halyard/core/resource/v1/ObjectReplaceTemplatedResourceSpec.groovy diff --git a/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Manifest.java b/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Manifest.java index 93434e10dc..38e6a007cd 100644 --- a/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Manifest.java +++ b/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Manifest.java @@ -22,7 +22,6 @@ import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Stream; import lombok.Data; import lombok.Getter; @@ -30,15 +29,15 @@ public class Manifest { public String name; public String manifestVersion; - public List jars; public Map options; + public Map> resources; static final String regex = "^[a-zA-Z0-9]+\\/[\\w-]+$"; static final Pattern pattern = Pattern.compile(regex); public void validate() throws HalException { - if (Stream.of(name, manifestVersion, jars).anyMatch(Objects::isNull)) { + if (name == null || manifestVersion == null) { throw new HalException( new ConfigProblemBuilder( Problem.Severity.FATAL, "Invalid plugin manifest, contains null values") diff --git a/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Plugin.java b/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Plugin.java index 7ccc64922b..565136bccb 100644 --- a/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Plugin.java +++ b/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Plugin.java @@ -27,8 +27,10 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import lombok.AccessLevel; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.Getter; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.Constructor; import org.yaml.snakeyaml.representer.Representer; @@ -36,23 +38,29 @@ @Data @EqualsAndHashCode(callSuper = true) public class Plugin extends Node { - public String name; - public Boolean enabled; - public String manifestLocation; - public Map options = new HashMap<>(); + private String name; + private Boolean enabled; + private String manifestLocation; + private Map options = new HashMap<>(); + + @Getter(AccessLevel.NONE) + private Manifest manifest; @Override public String getNodeName() { return name; } - public Manifest generateManifest() { + public Manifest getManifest() { + if (manifest != null) { + return manifest; + } Representer representer = new Representer(); representer.getPropertyUtils().setSkipMissingProperties(true); Yaml yaml = new Yaml(new Constructor(Manifest.class), representer); InputStream manifestContents = downloadManifest(); - Manifest manifest = yaml.load(manifestContents); + manifest = yaml.load(manifestContents); manifest.validate(); return manifest; } @@ -113,6 +121,6 @@ public static Map merge( } public Map getCombinedOptions() { - return Plugin.merge(generateManifest().getOptions(), options); + return Plugin.merge(getManifest().getOptions(), options); } } diff --git a/halyard-config/src/test/groovy/com/netflix/spinnaker/halyard/config/model/v1/plugins/ManifestSpec.groovy b/halyard-config/src/test/groovy/com/netflix/spinnaker/halyard/config/model/v1/plugins/ManifestSpec.groovy index c6389d273f..e79d86bc08 100644 --- a/halyard-config/src/test/groovy/com/netflix/spinnaker/halyard/config/model/v1/plugins/ManifestSpec.groovy +++ b/halyard-config/src/test/groovy/com/netflix/spinnaker/halyard/config/model/v1/plugins/ManifestSpec.groovy @@ -26,7 +26,6 @@ class ManifestSpec extends Specification { Manifest manifest = new Manifest(); when: - manifest.setJars(jars) manifest.setManifestVersion(manifestVersion) manifest.setName(name) manifest.setOptions(options) @@ -39,7 +38,6 @@ class ManifestSpec extends Specification { name | manifestVersion | jars | options "foo" | "plugins/v1" | Arrays.asList("jar") | null "foo/bar" | null | Arrays.asList("jar") | null - "foo/bar" | "plugins/v1" | null | null } void "plugin manifests pass validation"() { @@ -47,7 +45,6 @@ class ManifestSpec extends Specification { Manifest manifest = new Manifest(); when: - manifest.setJars(Arrays.asList("one", "two")) manifest.setManifestVersion("plugins/v1") manifest.setName("foo/bar") manifest.validate() diff --git a/halyard-core/src/main/java/com/netflix/spinnaker/halyard/core/resource/v1/ObjectReplaceTemplatedResource.java b/halyard-core/src/main/java/com/netflix/spinnaker/halyard/core/resource/v1/ObjectReplaceTemplatedResource.java new file mode 100644 index 0000000000..6441fa268f --- /dev/null +++ b/halyard-core/src/main/java/com/netflix/spinnaker/halyard/core/resource/v1/ObjectReplaceTemplatedResource.java @@ -0,0 +1,51 @@ +/* + * Copyright 2019 Armory, 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.halyard.core.resource.v1; + +import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class ObjectReplaceTemplatedResource extends TemplatedResource { + public static Logger log = LoggerFactory.getLogger(ObjectReplaceTemplatedResource.class); + + protected String formatKey(String key) { + return "'{{%" + key + "%}}'"; + } + + protected String getRegexSafeFormatKey() { + return "(?s).*\\'\\{\\{%.*%\\}\\}\\'.*"; + } + + @Override + public String toString() { + String contents = getContents(); + for (Map.Entry binding : bindings.entrySet()) { + Object value = binding.getValue(); + contents = + contents.replace(formatKey(binding.getKey()), value != null ? value.toString() : ""); + } + if (contents.matches(getRegexSafeFormatKey())) { + log.warn( + "Found part of template that still contains a format key, likely a missing template value for a key, template: " + + contents); + } + return contents; + } +} diff --git a/halyard-core/src/main/java/com/netflix/spinnaker/halyard/core/resource/v1/ObjectResource.java b/halyard-core/src/main/java/com/netflix/spinnaker/halyard/core/resource/v1/ObjectResource.java new file mode 100644 index 0000000000..980c39952b --- /dev/null +++ b/halyard-core/src/main/java/com/netflix/spinnaker/halyard/core/resource/v1/ObjectResource.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019 Armory, 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.halyard.core.resource.v1; + +import lombok.AccessLevel; +import lombok.Getter; + +public class ObjectResource extends ObjectReplaceTemplatedResource { + public ObjectResource(String contents) { + this.contents = contents; + } + + @Getter(AccessLevel.PROTECTED) + private String contents; +} diff --git a/halyard-core/src/test/groovy/com/netflix/spinnaker/halyard/core/resource/v1/ObjectReplaceTemplatedResourceSpec.groovy b/halyard-core/src/test/groovy/com/netflix/spinnaker/halyard/core/resource/v1/ObjectReplaceTemplatedResourceSpec.groovy new file mode 100644 index 0000000000..a830840d5e --- /dev/null +++ b/halyard-core/src/test/groovy/com/netflix/spinnaker/halyard/core/resource/v1/ObjectReplaceTemplatedResourceSpec.groovy @@ -0,0 +1,54 @@ +/* + * Copyright 2019 Armory, 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.halyard.core.resource.v1 + +import spock.lang.Specification + +class ObjectReplaceTemplatedResourceSpec extends Specification { + void "Attempt template with unfilled key"() { + setup: + String template = """'{{%some-unfilled-key%}}'""" + def logMock = Mock(org.slf4j.Logger) + ObjectReplaceTemplatedResource resource = (ObjectReplaceTemplatedResource)(new ObjectResource(template)) + resource.log = logMock + + when: + 1 * logMock.warn(_) >> _ + resource.toString() + + then: + true + } + + void "Attempt template with unfilled key multiline"() { + setup: + String template = """foo +'{{%some-unfilled-key%}}' +bar +""" + def logMock = Mock(org.slf4j.Logger) + ObjectReplaceTemplatedResource resource = (ObjectReplaceTemplatedResource)(new ObjectResource(template)) + resource.log = logMock + + when: + 1 * logMock.warn(_) >> _ + resource.toString() + + then: + true + } +} diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/PluginProfileFactory.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/PluginProfileFactory.java index 3a8b8c2f33..c1c7843e74 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/PluginProfileFactory.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/PluginProfileFactory.java @@ -22,6 +22,7 @@ import com.netflix.spinnaker.halyard.config.model.v1.plugins.Plugin; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerArtifact; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerRuntimeSettings; +import java.nio.file.Paths; import java.util.*; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; @@ -30,11 +31,20 @@ @Slf4j @Component public class PluginProfileFactory extends StringBackedProfileFactory { - @Override - protected void setProfile( - Profile profile, - DeploymentConfiguration deploymentConfiguration, - SpinnakerRuntimeSettings endpoints) { + + public Profile getProfileByName( + String configOutputPath, + String serviceName, + DeploymentConfiguration deploymentConfiguration) { + + String pluginFilename = "plugins.yml"; + String pluginPath = Paths.get(configOutputPath, pluginFilename).toString(); + + String deploymentName = deploymentConfiguration.getName(); + String version = getArtifactService().getArtifactVersion(deploymentName, getArtifact()); + String profileName = serviceName + '-' + pluginFilename; + Profile profile = getBaseProfile(profileName, version, pluginPath); + final Plugins plugins = deploymentConfiguration.getPlugins(); Map pluginsYaml = new HashMap<>(); @@ -44,7 +54,8 @@ protected void setProfile( plugins.getPlugins().stream() .filter(p -> p.getEnabled()) .filter(p -> !p.getManifestLocation().isEmpty()) - .map(p -> composeMetadata(p, p.generateManifest())) + .filter(p -> p.getManifest().getResources().containsKey(serviceName)) + .map(p -> composeMetadata(p, p.getManifest(), serviceName)) .collect(Collectors.toList()); pluginsYaml.put("pluginConfigurations", pluginMetadata); @@ -53,16 +64,26 @@ protected void setProfile( profile.appendContents( yamlToString(deploymentConfiguration.getName(), profile, fullyRenderedYaml)); + return profile; } - private Map composeMetadata(Plugin plugin, Manifest manifest) { + public Map composeMetadata(Plugin plugin, Manifest manifest, String serviceName) { + if (!manifest.getResources().containsKey(serviceName)) { + return null; + } Map metadata = new LinkedHashMap<>(); metadata.put("enabled", plugin.getEnabled()); metadata.put("name", manifest.getName()); - metadata.put("jars", manifest.getJars()); + metadata.put("jars", manifest.getResources().get(serviceName)); return metadata; } + @Override + protected void setProfile( + Profile profile, + DeploymentConfiguration deploymentConfiguration, + SpinnakerRuntimeSettings endpoints) {} + @Override protected String getRawBaseProfile() { return ""; diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/deck/DeckProfileFactory.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/deck/DeckProfileFactory.java index c2804c860c..6d8a3d3006 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/deck/DeckProfileFactory.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/deck/DeckProfileFactory.java @@ -17,6 +17,7 @@ package com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.deck; +import com.google.gson.Gson; import com.netflix.spinnaker.halyard.config.model.v1.canary.Canary; import com.netflix.spinnaker.halyard.config.model.v1.node.DeploymentConfiguration; import com.netflix.spinnaker.halyard.config.model.v1.node.Features; @@ -24,6 +25,7 @@ import com.netflix.spinnaker.halyard.config.model.v1.notifications.GithubStatusNotification; import com.netflix.spinnaker.halyard.config.model.v1.notifications.SlackNotification; import com.netflix.spinnaker.halyard.config.model.v1.notifications.TwilioNotification; +import com.netflix.spinnaker.halyard.config.model.v1.plugins.Plugin; import com.netflix.spinnaker.halyard.config.model.v1.providers.appengine.AppengineProvider; import com.netflix.spinnaker.halyard.config.model.v1.providers.aws.AwsAccount; import com.netflix.spinnaker.halyard.config.model.v1.providers.aws.AwsProvider; @@ -37,16 +39,16 @@ import com.netflix.spinnaker.halyard.config.services.v1.AccountService; import com.netflix.spinnaker.halyard.config.services.v1.VersionsService; import com.netflix.spinnaker.halyard.core.registry.v1.Versions; +import com.netflix.spinnaker.halyard.core.resource.v1.ObjectResource; import com.netflix.spinnaker.halyard.core.resource.v1.StringResource; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerArtifact; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerRuntimeSettings; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.Profile; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.RegistryBackedProfileFactory; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.SpinnakerService.Type; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.nio.file.Paths; +import java.util.*; +import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -72,7 +74,7 @@ protected void setProfile( Profile profile, DeploymentConfiguration deploymentConfiguration, SpinnakerRuntimeSettings endpoints) { - StringResource configTemplate = new StringResource(profile.getBaseContents()); + ObjectResource configTemplate = new ObjectResource(profile.getBaseContents()); UiSecurity uiSecurity = deploymentConfiguration.getSecurity().getUiSecurity(); profile.setUser(ApacheSettings.APACHE_USER); @@ -232,8 +234,35 @@ protected void setProfile( bindings.put("canary.showAllCanaryConfigs", canary.isShowAllConfigsEnabled()); } + // Configure Plugins + List pluginBinding = new ArrayList<>(); + List plugins = deploymentConfiguration.getPlugins().getPlugins(); + Map> pluginMetadata = + plugins.stream() + .filter(p -> p.getEnabled()) + .filter(p -> !p.getManifestLocation().isEmpty()) + .map(p -> p.getManifest()) + .filter(m -> m.getResources().containsKey(SpinnakerArtifact.DECK.getName())) + .collect( + Collectors.toMap( + m -> m.getName(), m -> m.getResources().get(SpinnakerArtifact.DECK.getName()))); + + for (Map.Entry> entry : pluginMetadata.entrySet()) { + for (String location : entry.getValue()) { + Map resource = new HashMap<>(); + resource.put("name", entry.getKey()); + String localFilePath = + "/plugins/" + entry.getKey() + "/" + Paths.get(location).getFileName().toString(); + resource.put("location", localFilePath); + pluginBinding.add(new Gson().toJson(resource)); + } + } + bindings.put("plugins", pluginBinding); + + StringResource objectConfigTemplate = + new StringResource(configTemplate.setBindings(bindings).toString()); profile - .appendContents(configTemplate.setBindings(bindings).toString()) + .appendContents(objectConfigTemplate.setBindings(bindings).toString()) .setRequiredFiles(backupRequiredFiles(uiSecurity, deploymentConfiguration.getName())); } } diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/OrcaService.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/OrcaService.java index aead64d01d..2aa55d9f44 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/OrcaService.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/OrcaService.java @@ -77,11 +77,9 @@ public List getProfiles( profiles.add(profile); // Plugins - String pluginFilename = "plugins.yml"; - String pluginPath = Paths.get(getConfigOutputPath(), pluginFilename).toString(); Profile pluginProfile = - pluginProfileFactory.getProfile( - pluginFilename, pluginPath, deploymentConfiguration, endpoints); + pluginProfileFactory.getProfileByName( + getConfigOutputPath(), getCanonicalName(), deploymentConfiguration); profiles.add(pluginProfile); return profiles; } diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2DeckService.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2DeckService.java index 5d2691a5bd..db1726d5b2 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2DeckService.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2DeckService.java @@ -19,17 +19,22 @@ package com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.distributed.kubernetes.v2; import com.netflix.spinnaker.halyard.config.model.v1.node.DeploymentConfiguration; +import com.netflix.spinnaker.halyard.config.model.v1.node.Plugins; +import com.netflix.spinnaker.halyard.config.model.v1.plugins.Manifest; +import com.netflix.spinnaker.halyard.config.model.v1.providers.kubernetes.KubernetesAccount; +import com.netflix.spinnaker.halyard.deploy.deployment.v1.AccountDeploymentDetails; +import com.netflix.spinnaker.halyard.deploy.services.v1.GenerateService; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerRuntimeSettings; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.Profile; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.deck.DeckDockerProfileFactory; +import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.ConfigSource; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.DeckService; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.ServiceSettings; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.distributed.DistributedService.DeployPriority; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.distributed.kubernetes.KubernetesSharedServiceSettings; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; +import java.util.*; +import java.util.stream.Collectors; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Delegate; @@ -70,6 +75,100 @@ protected Optional customProfileOutputPath(String profileName) { } } + @Override + public List getInitContainers(AccountDeploymentDetails details) { + Plugins plugins = details.getDeploymentConfiguration().getPlugins(); + if (plugins.isEnabled() && plugins.isDownloadingEnabled()) { + List initContainers = + details + .getDeploymentConfiguration() + .getDeploymentEnvironment() + .getInitContainers() + .getOrDefault(getServiceName(), new ArrayList<>()); + initContainers.add(getPluginDownloadingContainer(plugins)); + details + .getDeploymentConfiguration() + .getDeploymentEnvironment() + .getInitContainers() + .put(getServiceName(), initContainers); + } + + return KubernetesV2Service.super.getInitContainers(details); + } + + private Map getPluginDownloadingContainer(Plugins plugins) { + List pluginManifests = + plugins.getPlugins().stream() + .filter(p -> p.getEnabled()) + .filter(p -> !p.getManifestLocation().isEmpty()) + .map(p -> p.getManifest()) + .filter(m -> m.getResources().containsKey(getCanonicalName())) + .distinct() + .collect(Collectors.toList()); + + Map pluginDownloadingContainer = new HashMap(); + pluginDownloadingContainer.put("name", "plugin-downloader"); + pluginDownloadingContainer.put("image", "busybox"); + pluginDownloadingContainer.put("command", getCommand()); + pluginDownloadingContainer.put("args", getPluginDownloadingArgs(pluginManifests)); + pluginDownloadingContainer.put("volumeMounts", getVolumeMounts()); + return pluginDownloadingContainer; + } + + private List getCommand() { + List command = new ArrayList(); + command.add("/bin/sh"); + return command; + } + + private List getPluginDownloadingArgs(List manifests) { + StringBuilder sb = new StringBuilder("cd /opt/spinnaker/plugins/resources && "); + for (Manifest manifest : manifests) { + String manifestsList = String.join(" ", manifest.getResources().get(getCanonicalName())); + sb.append("mkdir -p ").append(manifest.getName()).append(" && "); + sb.append("wget ") + .append(manifestsList) + .append(" -P ") + .append(manifest.getName()) + .append("&& "); + } + sb.append("chown -R www-data:www-data /opt/spinnaker/plugins/resources;"); + + List pluginArgs = new ArrayList(); + pluginArgs.add("-c"); + pluginArgs.add(sb.toString()); + return pluginArgs; + } + + private List getVolumeMounts() { + List volumeMounts = new ArrayList(); + Map initContainerVolumeMount = new HashMap(); + initContainerVolumeMount.put("name", "downloaded-plugin-location"); + initContainerVolumeMount.put("mountPath", "/opt/spinnaker/plugins/resources"); + volumeMounts.add(initContainerVolumeMount); + return volumeMounts; + } + + @Override + public List stageConfig( + KubernetesV2Executor executor, + AccountDeploymentDetails details, + GenerateService.ResolvedConfiguration resolvedConfiguration) { + + List configSources = + KubernetesV2Service.super.stageConfig(executor, details, resolvedConfiguration); + + Plugins plugins = details.getDeploymentConfiguration().getPlugins(); + if (plugins.isEnabled() && plugins.isDownloadingEnabled()) { + configSources.add( + new ConfigSource() + .setId("downloaded-plugin-location") + .setMountPath("/opt/deck/html/plugins") + .setType(ConfigSource.Type.emptyDir)); + } + return configSources; + } + @Override public List getProfiles( DeploymentConfiguration deploymentConfiguration, SpinnakerRuntimeSettings endpoints) { diff --git a/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2ServiceTest.groovy b/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2ServiceTest.groovy index 4b1ee52e46..242aac8aa3 100644 --- a/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2ServiceTest.groovy +++ b/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2ServiceTest.groovy @@ -191,6 +191,7 @@ class KubernetesV2ServiceTest extends Specification { SidecarConfig.SecretVolumeMount svm = new SidecarConfig.SecretVolumeMount(secretName: "sMap", mountPath: "/secretMap") car.getSecretVolumeMounts().add(svm) sidecarConfigs.add(car) + AccountDeploymentDetails details = new AccountDeploymentDetails<>(); when: List volumes = testService.combineVolumes(configSources, settings, sidecarConfigs) From 66f3bf10fdde8e1e30feecee51ddf9057f87471d Mon Sep 17 00:00:00 2001 From: Cameron Motevasselani Date: Wed, 16 Oct 2019 15:40:34 -0700 Subject: [PATCH 2/4] wip --- .../core/resource/v1/ObjectReplaceTemplatedResource.java | 4 ++-- .../halyard/core/resource/v1/ObjectResource.java | 2 +- .../spinnaker/v1/profile/deck/DeckProfileFactory.java | 8 +++++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/halyard-core/src/main/java/com/netflix/spinnaker/halyard/core/resource/v1/ObjectReplaceTemplatedResource.java b/halyard-core/src/main/java/com/netflix/spinnaker/halyard/core/resource/v1/ObjectReplaceTemplatedResource.java index 6441fa268f..fefd64c65f 100644 --- a/halyard-core/src/main/java/com/netflix/spinnaker/halyard/core/resource/v1/ObjectReplaceTemplatedResource.java +++ b/halyard-core/src/main/java/com/netflix/spinnaker/halyard/core/resource/v1/ObjectReplaceTemplatedResource.java @@ -25,11 +25,11 @@ public abstract class ObjectReplaceTemplatedResource extends TemplatedResource { public static Logger log = LoggerFactory.getLogger(ObjectReplaceTemplatedResource.class); - protected String formatKey(String key) { + private String formatKey(String key) { return "'{{%" + key + "%}}'"; } - protected String getRegexSafeFormatKey() { + private String getRegexSafeFormatKey() { return "(?s).*\\'\\{\\{%.*%\\}\\}\\'.*"; } diff --git a/halyard-core/src/main/java/com/netflix/spinnaker/halyard/core/resource/v1/ObjectResource.java b/halyard-core/src/main/java/com/netflix/spinnaker/halyard/core/resource/v1/ObjectResource.java index 980c39952b..1fc5b04b09 100644 --- a/halyard-core/src/main/java/com/netflix/spinnaker/halyard/core/resource/v1/ObjectResource.java +++ b/halyard-core/src/main/java/com/netflix/spinnaker/halyard/core/resource/v1/ObjectResource.java @@ -26,5 +26,5 @@ public ObjectResource(String contents) { } @Getter(AccessLevel.PROTECTED) - private String contents; + private final String contents; } diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/deck/DeckProfileFactory.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/deck/DeckProfileFactory.java index 6d8a3d3006..79b834a422 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/deck/DeckProfileFactory.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/deck/DeckProfileFactory.java @@ -25,6 +25,7 @@ import com.netflix.spinnaker.halyard.config.model.v1.notifications.GithubStatusNotification; import com.netflix.spinnaker.halyard.config.model.v1.notifications.SlackNotification; import com.netflix.spinnaker.halyard.config.model.v1.notifications.TwilioNotification; +import com.netflix.spinnaker.halyard.config.model.v1.plugins.Manifest; import com.netflix.spinnaker.halyard.config.model.v1.plugins.Plugin; import com.netflix.spinnaker.halyard.config.model.v1.providers.appengine.AppengineProvider; import com.netflix.spinnaker.halyard.config.model.v1.providers.aws.AwsAccount; @@ -239,13 +240,14 @@ protected void setProfile( List plugins = deploymentConfiguration.getPlugins().getPlugins(); Map> pluginMetadata = plugins.stream() - .filter(p -> p.getEnabled()) + .filter(Plugin::getEnabled) .filter(p -> !p.getManifestLocation().isEmpty()) - .map(p -> p.getManifest()) + .map(Plugin::getManifest) .filter(m -> m.getResources().containsKey(SpinnakerArtifact.DECK.getName())) .collect( Collectors.toMap( - m -> m.getName(), m -> m.getResources().get(SpinnakerArtifact.DECK.getName()))); + Manifest::getName, + m -> m.getResources().get(SpinnakerArtifact.DECK.getName()))); for (Map.Entry> entry : pluginMetadata.entrySet()) { for (String location : entry.getValue()) { From 072e7d2f0f0fdf96e2c7e741235a03a6b5395074 Mon Sep 17 00:00:00 2001 From: Cameron Motevasselani Date: Mon, 21 Oct 2019 22:40:14 -0700 Subject: [PATCH 3/4] removing unused files, wip --- .../config/model/v1/plugins/Manifest.java | 5 +- .../config/model/v1/plugins/Plugin.java | 14 +-- .../model/v1/plugins/ManifestSpec.groovy | 3 + .../v1/profile/PluginProfileFactory.java | 37 ++---- .../spinnaker/v1/service/OrcaService.java | 6 +- .../v2/KubernetesV2DeckService.java | 105 +----------------- .../v2/KubernetesV2ServiceTest.groovy | 1 - 7 files changed, 24 insertions(+), 147 deletions(-) diff --git a/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Manifest.java b/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Manifest.java index 38e6a007cd..93434e10dc 100644 --- a/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Manifest.java +++ b/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Manifest.java @@ -22,6 +22,7 @@ import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Stream; import lombok.Data; import lombok.Getter; @@ -29,15 +30,15 @@ public class Manifest { public String name; public String manifestVersion; + public List jars; public Map options; - public Map> resources; static final String regex = "^[a-zA-Z0-9]+\\/[\\w-]+$"; static final Pattern pattern = Pattern.compile(regex); public void validate() throws HalException { - if (name == null || manifestVersion == null) { + if (Stream.of(name, manifestVersion, jars).anyMatch(Objects::isNull)) { throw new HalException( new ConfigProblemBuilder( Problem.Severity.FATAL, "Invalid plugin manifest, contains null values") diff --git a/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Plugin.java b/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Plugin.java index 565136bccb..24de3d49bc 100644 --- a/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Plugin.java +++ b/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Plugin.java @@ -27,10 +27,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import lombok.AccessLevel; import lombok.Data; import lombok.EqualsAndHashCode; -import lombok.Getter; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.Constructor; import org.yaml.snakeyaml.representer.Representer; @@ -43,24 +41,18 @@ public class Plugin extends Node { private String manifestLocation; private Map options = new HashMap<>(); - @Getter(AccessLevel.NONE) - private Manifest manifest; - @Override public String getNodeName() { return name; } - public Manifest getManifest() { - if (manifest != null) { - return manifest; - } + public Manifest generateManifest() { Representer representer = new Representer(); representer.getPropertyUtils().setSkipMissingProperties(true); Yaml yaml = new Yaml(new Constructor(Manifest.class), representer); InputStream manifestContents = downloadManifest(); - manifest = yaml.load(manifestContents); + Manifest manifest = yaml.load(manifestContents); manifest.validate(); return manifest; } @@ -121,6 +113,6 @@ public static Map merge( } public Map getCombinedOptions() { - return Plugin.merge(getManifest().getOptions(), options); + return Plugin.merge(generateManifest().getOptions(), getOptions()); } } diff --git a/halyard-config/src/test/groovy/com/netflix/spinnaker/halyard/config/model/v1/plugins/ManifestSpec.groovy b/halyard-config/src/test/groovy/com/netflix/spinnaker/halyard/config/model/v1/plugins/ManifestSpec.groovy index e79d86bc08..c6389d273f 100644 --- a/halyard-config/src/test/groovy/com/netflix/spinnaker/halyard/config/model/v1/plugins/ManifestSpec.groovy +++ b/halyard-config/src/test/groovy/com/netflix/spinnaker/halyard/config/model/v1/plugins/ManifestSpec.groovy @@ -26,6 +26,7 @@ class ManifestSpec extends Specification { Manifest manifest = new Manifest(); when: + manifest.setJars(jars) manifest.setManifestVersion(manifestVersion) manifest.setName(name) manifest.setOptions(options) @@ -38,6 +39,7 @@ class ManifestSpec extends Specification { name | manifestVersion | jars | options "foo" | "plugins/v1" | Arrays.asList("jar") | null "foo/bar" | null | Arrays.asList("jar") | null + "foo/bar" | "plugins/v1" | null | null } void "plugin manifests pass validation"() { @@ -45,6 +47,7 @@ class ManifestSpec extends Specification { Manifest manifest = new Manifest(); when: + manifest.setJars(Arrays.asList("one", "two")) manifest.setManifestVersion("plugins/v1") manifest.setName("foo/bar") manifest.validate() diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/PluginProfileFactory.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/PluginProfileFactory.java index c1c7843e74..3a8b8c2f33 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/PluginProfileFactory.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/PluginProfileFactory.java @@ -22,7 +22,6 @@ import com.netflix.spinnaker.halyard.config.model.v1.plugins.Plugin; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerArtifact; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerRuntimeSettings; -import java.nio.file.Paths; import java.util.*; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; @@ -31,20 +30,11 @@ @Slf4j @Component public class PluginProfileFactory extends StringBackedProfileFactory { - - public Profile getProfileByName( - String configOutputPath, - String serviceName, - DeploymentConfiguration deploymentConfiguration) { - - String pluginFilename = "plugins.yml"; - String pluginPath = Paths.get(configOutputPath, pluginFilename).toString(); - - String deploymentName = deploymentConfiguration.getName(); - String version = getArtifactService().getArtifactVersion(deploymentName, getArtifact()); - String profileName = serviceName + '-' + pluginFilename; - Profile profile = getBaseProfile(profileName, version, pluginPath); - + @Override + protected void setProfile( + Profile profile, + DeploymentConfiguration deploymentConfiguration, + SpinnakerRuntimeSettings endpoints) { final Plugins plugins = deploymentConfiguration.getPlugins(); Map pluginsYaml = new HashMap<>(); @@ -54,8 +44,7 @@ public Profile getProfileByName( plugins.getPlugins().stream() .filter(p -> p.getEnabled()) .filter(p -> !p.getManifestLocation().isEmpty()) - .filter(p -> p.getManifest().getResources().containsKey(serviceName)) - .map(p -> composeMetadata(p, p.getManifest(), serviceName)) + .map(p -> composeMetadata(p, p.generateManifest())) .collect(Collectors.toList()); pluginsYaml.put("pluginConfigurations", pluginMetadata); @@ -64,26 +53,16 @@ public Profile getProfileByName( profile.appendContents( yamlToString(deploymentConfiguration.getName(), profile, fullyRenderedYaml)); - return profile; } - public Map composeMetadata(Plugin plugin, Manifest manifest, String serviceName) { - if (!manifest.getResources().containsKey(serviceName)) { - return null; - } + private Map composeMetadata(Plugin plugin, Manifest manifest) { Map metadata = new LinkedHashMap<>(); metadata.put("enabled", plugin.getEnabled()); metadata.put("name", manifest.getName()); - metadata.put("jars", manifest.getResources().get(serviceName)); + metadata.put("jars", manifest.getJars()); return metadata; } - @Override - protected void setProfile( - Profile profile, - DeploymentConfiguration deploymentConfiguration, - SpinnakerRuntimeSettings endpoints) {} - @Override protected String getRawBaseProfile() { return ""; diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/OrcaService.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/OrcaService.java index 2aa55d9f44..aead64d01d 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/OrcaService.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/OrcaService.java @@ -77,9 +77,11 @@ public List getProfiles( profiles.add(profile); // Plugins + String pluginFilename = "plugins.yml"; + String pluginPath = Paths.get(getConfigOutputPath(), pluginFilename).toString(); Profile pluginProfile = - pluginProfileFactory.getProfileByName( - getConfigOutputPath(), getCanonicalName(), deploymentConfiguration); + pluginProfileFactory.getProfile( + pluginFilename, pluginPath, deploymentConfiguration, endpoints); profiles.add(pluginProfile); return profiles; } diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2DeckService.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2DeckService.java index db1726d5b2..5d2691a5bd 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2DeckService.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2DeckService.java @@ -19,22 +19,17 @@ package com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.distributed.kubernetes.v2; import com.netflix.spinnaker.halyard.config.model.v1.node.DeploymentConfiguration; -import com.netflix.spinnaker.halyard.config.model.v1.node.Plugins; -import com.netflix.spinnaker.halyard.config.model.v1.plugins.Manifest; -import com.netflix.spinnaker.halyard.config.model.v1.providers.kubernetes.KubernetesAccount; -import com.netflix.spinnaker.halyard.deploy.deployment.v1.AccountDeploymentDetails; -import com.netflix.spinnaker.halyard.deploy.services.v1.GenerateService; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.SpinnakerRuntimeSettings; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.Profile; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.deck.DeckDockerProfileFactory; -import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.ConfigSource; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.DeckService; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.ServiceSettings; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.distributed.DistributedService.DeployPriority; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.distributed.kubernetes.KubernetesSharedServiceSettings; import java.nio.file.Paths; -import java.util.*; -import java.util.stream.Collectors; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Delegate; @@ -75,100 +70,6 @@ protected Optional customProfileOutputPath(String profileName) { } } - @Override - public List getInitContainers(AccountDeploymentDetails details) { - Plugins plugins = details.getDeploymentConfiguration().getPlugins(); - if (plugins.isEnabled() && plugins.isDownloadingEnabled()) { - List initContainers = - details - .getDeploymentConfiguration() - .getDeploymentEnvironment() - .getInitContainers() - .getOrDefault(getServiceName(), new ArrayList<>()); - initContainers.add(getPluginDownloadingContainer(plugins)); - details - .getDeploymentConfiguration() - .getDeploymentEnvironment() - .getInitContainers() - .put(getServiceName(), initContainers); - } - - return KubernetesV2Service.super.getInitContainers(details); - } - - private Map getPluginDownloadingContainer(Plugins plugins) { - List pluginManifests = - plugins.getPlugins().stream() - .filter(p -> p.getEnabled()) - .filter(p -> !p.getManifestLocation().isEmpty()) - .map(p -> p.getManifest()) - .filter(m -> m.getResources().containsKey(getCanonicalName())) - .distinct() - .collect(Collectors.toList()); - - Map pluginDownloadingContainer = new HashMap(); - pluginDownloadingContainer.put("name", "plugin-downloader"); - pluginDownloadingContainer.put("image", "busybox"); - pluginDownloadingContainer.put("command", getCommand()); - pluginDownloadingContainer.put("args", getPluginDownloadingArgs(pluginManifests)); - pluginDownloadingContainer.put("volumeMounts", getVolumeMounts()); - return pluginDownloadingContainer; - } - - private List getCommand() { - List command = new ArrayList(); - command.add("/bin/sh"); - return command; - } - - private List getPluginDownloadingArgs(List manifests) { - StringBuilder sb = new StringBuilder("cd /opt/spinnaker/plugins/resources && "); - for (Manifest manifest : manifests) { - String manifestsList = String.join(" ", manifest.getResources().get(getCanonicalName())); - sb.append("mkdir -p ").append(manifest.getName()).append(" && "); - sb.append("wget ") - .append(manifestsList) - .append(" -P ") - .append(manifest.getName()) - .append("&& "); - } - sb.append("chown -R www-data:www-data /opt/spinnaker/plugins/resources;"); - - List pluginArgs = new ArrayList(); - pluginArgs.add("-c"); - pluginArgs.add(sb.toString()); - return pluginArgs; - } - - private List getVolumeMounts() { - List volumeMounts = new ArrayList(); - Map initContainerVolumeMount = new HashMap(); - initContainerVolumeMount.put("name", "downloaded-plugin-location"); - initContainerVolumeMount.put("mountPath", "/opt/spinnaker/plugins/resources"); - volumeMounts.add(initContainerVolumeMount); - return volumeMounts; - } - - @Override - public List stageConfig( - KubernetesV2Executor executor, - AccountDeploymentDetails details, - GenerateService.ResolvedConfiguration resolvedConfiguration) { - - List configSources = - KubernetesV2Service.super.stageConfig(executor, details, resolvedConfiguration); - - Plugins plugins = details.getDeploymentConfiguration().getPlugins(); - if (plugins.isEnabled() && plugins.isDownloadingEnabled()) { - configSources.add( - new ConfigSource() - .setId("downloaded-plugin-location") - .setMountPath("/opt/deck/html/plugins") - .setType(ConfigSource.Type.emptyDir)); - } - return configSources; - } - @Override public List getProfiles( DeploymentConfiguration deploymentConfiguration, SpinnakerRuntimeSettings endpoints) { diff --git a/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2ServiceTest.groovy b/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2ServiceTest.groovy index 2dc2c4c517..46a59e93d2 100644 --- a/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2ServiceTest.groovy +++ b/halyard-deploy/src/test/groovy/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/service/distributed/kubernetes/v2/KubernetesV2ServiceTest.groovy @@ -191,7 +191,6 @@ class KubernetesV2ServiceTest extends Specification { SidecarConfig.SecretVolumeMount svm = new SidecarConfig.SecretVolumeMount(secretName: "sMap", mountPath: "/secretMap") car.getSecretVolumeMounts().add(svm) sidecarConfigs.add(car) - AccountDeploymentDetails details = new AccountDeploymentDetails<>(); when: List volumes = testService.combineVolumes(configSources, settings, sidecarConfigs) From 107a206f06cba96bc795bd4609980d0ef554b2fc Mon Sep 17 00:00:00 2001 From: Cameron Motevasselani Date: Mon, 21 Oct 2019 23:05:12 -0700 Subject: [PATCH 4/4] send plugin configuration via settings.js, no init containers --- .../config/model/v1/plugins/Manifest.java | 3 ++- .../v1/profile/deck/DeckProfileFactory.java | 26 ++++++++++--------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Manifest.java b/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Manifest.java index 93434e10dc..6918db7ea2 100644 --- a/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Manifest.java +++ b/halyard-config/src/main/java/com/netflix/spinnaker/halyard/config/model/v1/plugins/Manifest.java @@ -31,6 +31,7 @@ public class Manifest { public String name; public String manifestVersion; public List jars; + public List deck; public Map options; static final String regex = "^[a-zA-Z0-9]+\\/[\\w-]+$"; @@ -38,7 +39,7 @@ public class Manifest { public void validate() throws HalException { - if (Stream.of(name, manifestVersion, jars).anyMatch(Objects::isNull)) { + if (Stream.of(name, manifestVersion, jars, deck).anyMatch(Objects::isNull)) { throw new HalException( new ConfigProblemBuilder( Problem.Severity.FATAL, "Invalid plugin manifest, contains null values") diff --git a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/deck/DeckProfileFactory.java b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/deck/DeckProfileFactory.java index 79b834a422..e1773545c4 100644 --- a/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/deck/DeckProfileFactory.java +++ b/halyard-deploy/src/main/java/com/netflix/spinnaker/halyard/deploy/spinnaker/v1/profile/deck/DeckProfileFactory.java @@ -47,7 +47,6 @@ import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.Profile; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.profile.RegistryBackedProfileFactory; import com.netflix.spinnaker.halyard.deploy.spinnaker.v1.service.SpinnakerService.Type; -import java.nio.file.Paths; import java.util.*; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; @@ -75,7 +74,11 @@ protected void setProfile( Profile profile, DeploymentConfiguration deploymentConfiguration, SpinnakerRuntimeSettings endpoints) { - ObjectResource configTemplate = new ObjectResource(profile.getBaseContents()); + ObjectResource configTemplate = + new ObjectResource( + profile + .getBaseContents() + .replace("version: version,", "version: version,\n plugins: '{{%plugins%}}',")); UiSecurity uiSecurity = deploymentConfiguration.getSecurity().getUiSecurity(); profile.setUser(ApacheSettings.APACHE_USER); @@ -242,20 +245,19 @@ protected void setProfile( plugins.stream() .filter(Plugin::getEnabled) .filter(p -> !p.getManifestLocation().isEmpty()) - .map(Plugin::getManifest) - .filter(m -> m.getResources().containsKey(SpinnakerArtifact.DECK.getName())) - .collect( - Collectors.toMap( - Manifest::getName, - m -> m.getResources().get(SpinnakerArtifact.DECK.getName()))); - + .map(Plugin::generateManifest) + .collect(Collectors.toMap(Manifest::getName, Manifest::getDeck)); for (Map.Entry> entry : pluginMetadata.entrySet()) { for (String location : entry.getValue()) { Map resource = new HashMap<>(); resource.put("name", entry.getKey()); - String localFilePath = - "/plugins/" + entry.getKey() + "/" + Paths.get(location).getFileName().toString(); - resource.put("location", localFilePath); + resource.put("location", location); + String extension = location.substring(location.lastIndexOf(".")); + if (extension == "css") { + resource.put("type", "css"); + } else { + resource.put("type", "js"); + } pluginBinding.add(new Gson().toJson(resource)); } }