Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(versions): Use thread safe yaml parser #1644

Merged
merged 6 commits into from
Apr 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.parser.ParserException;
Expand All @@ -64,10 +65,14 @@ public class HalconfigParser {

@Autowired HalconfigDirectoryStructure halconfigDirectoryStructure;

@Autowired Yaml yamlParser;
@Autowired ApplicationContext applicationContext;

private boolean useBackup = false;

private Yaml getYamlParser() {
return applicationContext.getBean(Yaml.class);
}

/**
* Parse Halyard's config.
*
Expand All @@ -76,7 +81,7 @@ public class HalconfigParser {
* @see Halconfig
*/
Halconfig parseHalconfig(InputStream is) throws IllegalArgumentException {
Object obj = yamlParser.load(is);
Object obj = getYamlParser().load(is);
return objectMapper.convertValue(obj, Halconfig.class);
}

Expand Down Expand Up @@ -232,7 +237,7 @@ private void saveConfigTo(Path path) {
AtomicFileWriter writer = null;
try {
writer = new AtomicFileWriter(path);
writer.write(yamlParser.dump(objectMapper.convertValue(local, Map.class)));
writer.write(getYamlParser().dump(objectMapper.convertValue(local, Map.class)));
writer.commit();
} catch (IOException e) {
throw new HalException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
import java.util.Optional;
import java.util.concurrent.Executors;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
import org.springframework.stereotype.Component;
Expand Down Expand Up @@ -94,6 +96,8 @@ String spinnakerStagingDependencyPath(
}

@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) // snake yaml is not thread safe
// (https://bitbucket.org/asomov/snakeyaml/wiki/Documentation#markdown-header-threading)
Yaml yamlParser() {
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,12 @@
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.yaml.snakeyaml.Yaml;
import retrofit.RetrofitError;

@Component
public class VersionsService {
@Autowired ProfileRegistry profileRegistry;

@Autowired Yaml yamlParser;

@Autowired RelaxedObjectMapper relaxedObjectMapper;

private static ExpiringConcurrentMap<String, String> concurrentMap =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.netflix.spinnaker.halyard.config.config.v1

import com.netflix.spinnaker.halyard.config.model.v1.node.Halconfig
import org.springframework.context.ApplicationContext
import org.yaml.snakeyaml.Yaml
import org.yaml.snakeyaml.constructor.SafeConstructor
import spock.lang.Specification
Expand All @@ -31,8 +32,10 @@ class HalconfigParserSpec extends Specification {
HalconfigParser parser

void setup() {
ApplicationContext applicationContext = Stub(ApplicationContext.class)
applicationContext.getBean(Yaml.class) >> new Yaml(new SafeConstructor())
parser = new HalconfigParser()
parser.yamlParser = new Yaml(new SafeConstructor())
parser.applicationContext = applicationContext
parser.objectMapper = new StrictObjectMapper()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import com.netflix.spinnaker.halyard.config.config.v1.HalconfigDirectoryStructur
import com.netflix.spinnaker.halyard.config.config.v1.HalconfigParser
import com.netflix.spinnaker.halyard.config.config.v1.StrictObjectMapper
import com.netflix.spinnaker.halyard.config.model.v1.node.Halconfig
import org.springframework.context.ApplicationContext
import org.yaml.snakeyaml.Yaml
import org.yaml.snakeyaml.constructor.SafeConstructor
import spock.lang.Specification
Expand All @@ -29,8 +30,10 @@ import java.nio.charset.StandardCharsets
class HalconfigParserMocker extends Specification {
HalconfigParser mockHalconfigParser(String config) {
def parserStub = new HalconfigParser()
ApplicationContext applicationContext = Stub(ApplicationContext.class)
applicationContext.getBean(Yaml.class) >> new Yaml(new SafeConstructor())
parserStub.objectMapper = new StrictObjectMapper()
parserStub.yamlParser = new Yaml(new SafeConstructor())
parserStub.applicationContext = applicationContext
parserStub.halconfigDirectoryStructure = new HalconfigDirectoryStructure();

def stream = new ByteArrayInputStream(config.getBytes(StandardCharsets.UTF_8))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.yaml.snakeyaml.Yaml;
Expand All @@ -49,7 +50,11 @@ public class GoogleProfileReader implements ProfileReader {

@Autowired ObjectMapper relaxedObjectMapper;

@Autowired Yaml yamlParser;
@Autowired ApplicationContext applicationContext;

private Yaml getYamlParser() {
return applicationContext.getBean(Yaml.class);
}

@Bean
public Storage applicationDefaultGoogleStorage() {
Expand All @@ -71,12 +76,12 @@ public BillOfMaterials readBom(String version) throws IOException {
String bomName = bomPath(version);

return relaxedObjectMapper.convertValue(
yamlParser.load(getContents(bomName)), BillOfMaterials.class);
getYamlParser().load(getContents(bomName)), BillOfMaterials.class);
}

public Versions readVersions() throws IOException {
return relaxedObjectMapper.convertValue(
yamlParser.load(getContents("versions.yml")), Versions.class);
getYamlParser().load(getContents("versions.yml")), Versions.class);
}

public InputStream readArchiveProfile(String artifactName, String version, String profileName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.yaml.snakeyaml.Yaml;

Expand All @@ -45,10 +46,14 @@ public class LocalDiskProfileReader implements ProfileReader {

@Autowired ObjectMapper relaxedObjectMapper;

@Autowired Yaml yamlParser;
@Autowired ApplicationContext applicationContext;

private static final String HALCONFIG_DIR = "halconfig";

private Yaml getYamlParser() {
return applicationContext.getBean(Yaml.class);
}

@Override
public InputStream readProfile(String artifactName, String version, String profileName)
throws IOException {
Expand All @@ -72,7 +77,7 @@ public BillOfMaterials readBom(String version) throws IOException {
String versionName = Versions.fromLocal(version);
String bomName = bomPath(versionName);
return relaxedObjectMapper.convertValue(
yamlParser.load(getContents(bomName)), BillOfMaterials.class);
getYamlParser().load(getContents(bomName)), BillOfMaterials.class);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.yaml.snakeyaml.Yaml;

@Component
@Slf4j
Expand All @@ -37,8 +36,6 @@ public class ProfileRegistry {

@Autowired LocalDiskProfileReader localDiskProfileReader;

@Autowired Yaml yamlParser;

@Autowired ObjectMapper relaxedObjectMapper;

public InputStream readProfile(String artifactName, String version, String profileName)
Expand Down