Java tutorial
// (c) Copyright 2016 Cloudera, 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.cloudera.director.aws.ec2.ebs; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; import com.cloudera.director.aws.common.PropertyResolvers; import com.cloudera.director.spi.v1.model.ConfigurationProperty; import com.cloudera.director.spi.v1.model.Configured; import com.cloudera.director.spi.v1.model.LocalizationContext; import com.cloudera.director.spi.v1.model.util.ChildLocalizationContext; import com.cloudera.director.spi.v1.model.util.SimpleConfiguration; import com.cloudera.director.spi.v1.model.util.SimpleConfigurationPropertyBuilder; import com.google.common.base.Function; import com.google.common.io.Files; import java.io.File; import java.io.IOException; import java.util.Map; import java.util.Objects; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.env.PropertyResolver; /** * A lookup mechanism for getting metadata about EBS volumes. AWS does not provide * a means through the API to discover this metadata. This class looks up metadata * using a built-in list and an override list that the user can easily modify. */ @SuppressWarnings("PMD.UnusedPrivateField") public class EBSMetadata implements Function<String, EBSMetadata.EbsVolumeMetadata> { private static final Logger LOG = LoggerFactory.getLogger(EBSMetadata.class); /** * Contains metadata information for an EBS volume type. */ public static class EbsVolumeMetadata { private final String type; private final int minSizeGiB; private final int maxSizeGiB; public EbsVolumeMetadata(String type, int minSizeGiB, int maxSizeGiB) { this.type = Objects.requireNonNull(type, "type is null"); this.minSizeGiB = minSizeGiB; this.maxSizeGiB = maxSizeGiB; } public String getType() { return type; } public int getMinSizeGiB() { return minSizeGiB; } public int getMaxSizeGiB() { return maxSizeGiB; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; EbsVolumeMetadata that = (EbsVolumeMetadata) o; if (minSizeGiB != that.minSizeGiB) return false; if (maxSizeGiB != that.maxSizeGiB) return false; return type.equals(that.type); } @Override public int hashCode() { int result = type.hashCode(); result = 31 * result + minSizeGiB; result = 31 * result + maxSizeGiB; return result; } } public static class EBSMetadataConfigProperties { /** * EBS metadata configuration properties. */ // Fully qualifying class name due to compiler bug public static enum EBSMetadataConfigurationPropertyToken implements com.cloudera.director.spi.v1.model.ConfigurationPropertyToken { /** * Path for the custom EBS metadata file. Relative paths are based on the * plugin configuration directory. */ CUSTOM_EBS_METADATA_PATH(new SimpleConfigurationPropertyBuilder().configKey("ebsMetadataPath") .name("Custom EBS metadata path") .defaultDescription("The path for the custom ebs metadata. Relative paths are based " + "on the plugin configuration directory.") .build()); /** * The configuration property. */ private final ConfigurationProperty configurationProperty; /** * Creates a configuration property token with the specified parameters. * * @param configurationProperty the configuration property */ private EBSMetadataConfigurationPropertyToken(ConfigurationProperty configurationProperty) { this.configurationProperty = configurationProperty; } @Override public ConfigurationProperty unwrap() { return configurationProperty; } } public static final String DEFAULT_CUSTOM_EBS_METADATA_PATH = "ec2.ebs.ebsmetadata.properties"; private final File configurationDirectory; private String ebsMetadataPath = DEFAULT_CUSTOM_EBS_METADATA_PATH; /** * Creates EBS metadata config properties with the specified parameters. * * @param configuration the configuration * @param configurationDirectory the plugin configuration directory * @param cloudLocalizationContext the parent cloud localization context */ public EBSMetadataConfigProperties(Configured configuration, File configurationDirectory, LocalizationContext cloudLocalizationContext) { this.configurationDirectory = configurationDirectory; LocalizationContext localizationContext = new ChildLocalizationContext(cloudLocalizationContext, "ebsMetadata"); setCustomEbsMetadataPath(configuration.getConfigurationValue( EBSMetadataConfigurationPropertyToken.CUSTOM_EBS_METADATA_PATH, localizationContext)); } public String getCustomEbsMetadataPath() { return ebsMetadataPath; } File getCustomEbsMetadataFile() { return getCustomEbsMetadataFile(ebsMetadataPath); } File getCustomEbsMetadataFile(String ebsMetadataPath) { File ebsMetadataPathFile = new File(ebsMetadataPath); return ebsMetadataPathFile.isAbsolute() ? ebsMetadataPathFile : new File(configurationDirectory, ebsMetadataPath); } public void setCustomEbsMetadataPath(String ebsMetadataPath) { if (ebsMetadataPath != null) { LOG.info("Overriding ebsMetadataPath={} (default {})", ebsMetadataPath, DEFAULT_CUSTOM_EBS_METADATA_PATH); checkArgument(getCustomEbsMetadataFile(ebsMetadataPath).exists(), "Custom EBS metadata path " + ebsMetadataPath + " does not exist"); this.ebsMetadataPath = ebsMetadataPath; } } } public static class EBSMetadataConfig { public static final String BUILT_IN_LOCATION = "classpath:/com/cloudera/director/aws/ec2/ebs/ebsmetadata.properties"; protected EBSMetadataConfigProperties ebsMetadataConfigProperties; public PropertyResolver ebsMetadataResolver() { try { return PropertyResolvers.newMultiResourcePropertyResolver(BUILT_IN_LOCATION, "file:" + ebsMetadataConfigProperties.getCustomEbsMetadataFile().getAbsolutePath()); } catch (IOException e) { throw new IllegalArgumentException("Could not load custom ebs metadata", e); } } /** * Creates EBS metadata config with the specified parameters. * * @param ebsMetadataConfigProperties the config properties */ public EBSMetadataConfig(EBSMetadataConfigProperties ebsMetadataConfigProperties) { this.ebsMetadataConfigProperties = ebsMetadataConfigProperties; } } private final EBSMetadataConfigProperties ebsMetadataConfigProperties; private final PropertyResolver ebsMetadataResolver; /** * Creates EBS metadata with the specified parameters. * * @param configuration the configuration * @param configurationDirectory the plugin configuration directory * @param localizationContext the localization context */ public EBSMetadata(Configured configuration, File configurationDirectory, LocalizationContext localizationContext) { this(new EBSMetadataConfigProperties(configuration, configurationDirectory, localizationContext)); } /** * Creates EBS metadata with the specified parameters. * * @param ebsMetadataConfigProperties the config properties */ public EBSMetadata(EBSMetadataConfigProperties ebsMetadataConfigProperties) { this(ebsMetadataConfigProperties, new EBSMetadataConfig(ebsMetadataConfigProperties).ebsMetadataResolver()); } /** * Creates EBS metadata with the specified parameters. * * @param ebsMetadataConfigProperties the config properties * @param ebsMetadataResolver the ebs metadata resolver */ private EBSMetadata(EBSMetadataConfigProperties ebsMetadataConfigProperties, PropertyResolver ebsMetadataResolver) { this.ebsMetadataConfigProperties = ebsMetadataConfigProperties; this.ebsMetadataResolver = ebsMetadataResolver; } /** * Gets the metadata for an EBS volume type. A custom definition overrides a * built-in definition. * * @param volumeType ebs volume type * @return metadata associated with the volume type * @throws NullPointerException if no metadata could be found for a volume type * @throws IllegalStateException if the metadata for a volume type has invalid format */ @Override public EbsVolumeMetadata apply(String volumeType) { String strEbsMetadata = ebsMetadataResolver.getProperty(volumeType); Objects.requireNonNull(strEbsMetadata, String.format("Could not get metadata for volume type %s", volumeType)); // strEbsMetadata is expected to be in the form "minSize-maxSize" String[] parts = strEbsMetadata.trim().split("-"); checkState(parts.length == 2, String.format("invalid format for %s=%s, expecting " + "exactly 2 parts for the value", volumeType, strEbsMetadata)); int minSizeGiB, maxSizeGiB; try { minSizeGiB = Integer.parseInt(parts[0]); } catch (NumberFormatException ex) { throw new IllegalStateException(String.format("invalid format for %s=%s, %s should be an integer", volumeType, strEbsMetadata, parts[0])); } try { maxSizeGiB = Integer.parseInt(parts[1]); } catch (NumberFormatException ex) { throw new IllegalStateException(String.format("invalid format for %s=%s, %s should be an integer", volumeType, strEbsMetadata, parts[1])); } checkState(minSizeGiB > 0, String.format("invalid format for %s=%s, %d should " + "be a positive integer", volumeType, strEbsMetadata, minSizeGiB)); checkState(maxSizeGiB > 0, String.format("invalid format for %s=%s, %d should " + "be a positive integer", volumeType, strEbsMetadata, maxSizeGiB)); checkState(maxSizeGiB >= minSizeGiB, String.format( "invalid format for %s=%s, maximum size %d should " + "be greater than or equal to minimum size %d", volumeType, strEbsMetadata, maxSizeGiB, minSizeGiB)); return new EbsVolumeMetadata(volumeType, minSizeGiB, maxSizeGiB); } /** * Gets an instance of this class that uses only the given ebs metadata. * * @param metadata map of ebs volume type to it's associated metadata * @param localizationContext the localization context * @return new ebs metadata object */ public static EBSMetadata getDefaultInstance(final Map<String, String> metadata, LocalizationContext localizationContext) { PropertyResolver ebsMetadataResolver = PropertyResolvers.newMapPropertyResolver(metadata); File tempDir = Files.createTempDir(); tempDir.deleteOnExit(); EBSMetadataConfigProperties ebsMetadataConfigProperties = new EBSMetadataConfigProperties( new SimpleConfiguration(), tempDir, localizationContext); return new EBSMetadata(ebsMetadataConfigProperties, ebsMetadataResolver); } }