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

Support fetching configuration from AWS parameter store #6

Open
sherriff opened this issue May 11, 2017 · 1 comment
Open

Support fetching configuration from AWS parameter store #6

sherriff opened this issue May 11, 2017 · 1 comment

Comments

@sherriff
Copy link
Contributor

DownloadUtil.java currently supports fetching files from http and s3.
Adding support for AWS parameter store looks interesting.

Suggest using NamedPropertiesStore.java over DownLoadItem, but it might be a good idea to create an interface or extend NamedPropertiesStore to support

  1. "how to make the properties available": i.e. write to file or send as system properties: java -Dtest="true" -jar myApplication.jar
  2. Make NamedPropertiesStore hold metadata required to fetch properties from AWS parameter store.

Impl notes:
use describeParameters to fetch list of all keys and use this list of keys as input to getParameters. It is necessay to fetch all keys and filter client side due to some bugs.

https://aws.amazon.com/ec2/systems-manager/parameter-store/
https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-ssm

@sindremehus
Copy link
Contributor

Code for downloading parameters from SSM:

package no.embriq.aws.util.ssm;

import com.amazonaws.regions.Regions;
import com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagement;
import com.amazonaws.services.simplesystemsmanagement.AWSSimpleSystemsManagementClientBuilder;
import com.amazonaws.services.simplesystemsmanagement.model.DescribeParametersRequest;
import com.amazonaws.services.simplesystemsmanagement.model.DescribeParametersResult;
import com.amazonaws.services.simplesystemsmanagement.model.GetParametersRequest;
import com.amazonaws.services.simplesystemsmanagement.model.Parameter;
import com.amazonaws.services.simplesystemsmanagement.model.ParameterMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Looks up parameters from the <a href="http://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-paramstore.html">Amazon System Manager Parameter Store</a>.
 *
 * @author Sindre Mehus
 */
public class ParameterStore {

    private static final Logger LOG = LoggerFactory.getLogger(ParameterStore.class);
    private static final int LIMIT_DESCRIBE_PARAMS = 50;
    private static final int LIMIT_GET_PARAMS = 10;

    private final AWSSimpleSystemsManagement ssm;

    public ParameterStore(Regions region) {
        ssm = AWSSimpleSystemsManagementClientBuilder.standard().withRegion(region).build();
    }

    /**
     * Returns parameters from the AWS SSM Parameter Store.
     *
     * @param prefixes Only return parameters with the given parameter name prefixes (e.g., "elwinadapter-"). If a parameter
     *                 is present with more than one prefix, the latter prefix takes presendence.
     * @return The parameters as a (key, value) map.
     */
    public Map<String, String> getParameters(String... prefixes) {
        List<String> allParameterNames = getAllParameterNames();

        Map<String, String> result = new LinkedHashMap<>();
        for (String prefix : prefixes) {
            result.putAll(getParametersByName(getParameterNamesByPrefix(allParameterNames, prefix), prefix));
        }

        if (LOG.isDebugEnabled()) {
            LOG.debug("Found parameters: {}", result.keySet().stream().collect(Collectors.joining(", ")));
        }
        return result;
    }

    private List<String> getAllParameterNames() {
        List<ParameterMetadata> parameterMetadata = new ArrayList<>();
        String nextToken = null;

        do {
            DescribeParametersResult result = ssm.describeParameters(new DescribeParametersRequest().withNextToken(nextToken).withMaxResults(LIMIT_DESCRIBE_PARAMS));
            nextToken = result.getNextToken();
            parameterMetadata.addAll(result.getParameters());
        } while (nextToken != null);

        return parameterMetadata.stream()
                                .map(ParameterMetadata::getName)
                                .collect(Collectors.toList());

    }

    private List<String> getParameterNamesByPrefix(List<String> parameterNames, String prefix) {
        return parameterNames.stream()
                             .filter(name -> name.startsWith(prefix))
                             .collect(Collectors.toList());
    }

    private Map<String, String> getParametersByName(List<String> parameterNames, String prefix) {
        if (parameterNames.isEmpty()) {
            return Collections.emptyMap();
        }

        Map<String, String> result = new LinkedHashMap<>();
        partitionList(parameterNames, LIMIT_GET_PARAMS).forEach(paramNames -> result.putAll(getParameterValues(paramNames, prefix)));

        return result;
    }

    private Map<String, String> getParameterValues(List<String> parameterNames, String prefix) {
        List<Parameter> parameters = ssm.getParameters(new GetParametersRequest().withWithDecryption(true).withNames(parameterNames)).getParameters();
        return parameters.stream().collect(Collectors.toMap(parameter -> parameter.getName().replaceFirst("^" + prefix, ""),
                                                            Parameter::getValue));
    }

    private List<List<String>> partitionList(List<String> list, int size) {
        List<List<String>> partitions = new ArrayList<>();
        for (int i = 0; i < list.size(); i += size) {
            partitions.add(list.subList(i, Math.min(list.size(), i + size)));
        }
        return partitions;
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants