package com.netflix.exhibitor.core.config.azure; import com.microsoft.azure.storage.StorageException; import com.microsoft.azure.storage.blob.BlobProperties; import com.microsoft.azure.storage.blob.CloudBlob; import com.netflix.exhibitor.core.azure.*; import com.netflix.exhibitor.core.config.*; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Date; import java.util.Properties; public class AzureConfigProvider implements ConfigProvider { private final AzureConfigArguments arguments; private final AzureClient azureClient; private final String hostname; private final Properties defaults; public static final String AUTO_GENERATED_NOTE = "Auto-generated by Exhibitor on %s"; public static final int HTTP_FORBIDDEN = 403; public static final int HTTP_NOT_FOUND = 404; /** * @param factory the factory * @param credentials credentials * @param arguments args * @param hostname this VM's hostname * @throws Exception errors */ public AzureConfigProvider(AzureClientFactory factory, AzureCredential credentials, AzureConfigArguments arguments, String hostname) throws Exception { this(factory, credentials, arguments, hostname, new Properties()); } /** * @param factory the factory * @param credentials credentials * @param arguments args * @param hostname this VM's hostname * @param defaults default props * @throws Exception errors */ public AzureConfigProvider(AzureClientFactory factory, AzureCredential credentials, AzureConfigArguments arguments, String hostname, Properties defaults) throws Exception { this.arguments = arguments; this.hostname = hostname; this.defaults = defaults; azureClient = factory.makeNewClient(credentials); } public AzureClient getAzureClient() { return azureClient; } @Override public void start() throws Exception { // NOP } @Override public void close() throws IOException { azureClient.close(); } @Override public PseudoLock newPseudoLock() throws Exception { return new AzurePseudoLock ( azureClient, arguments.getContainer(), arguments.getLockArguments().getPrefix(), arguments.getLockArguments().getTimeoutMs(), arguments.getLockArguments().getPollingMs(), arguments.getLockArguments().getSettlingMs() ); } @Override public LoadedInstanceConfig loadConfig() throws Exception { Date lastModified; Properties properties = new Properties(); CloudBlob configObject = getConfigObject(); if (configObject != null) { lastModified = configObject.getProperties().getLastModified(); ByteArrayOutputStream out = new ByteArrayOutputStream(); configObject.download(out); properties.load(new ByteArrayInputStream(out.toByteArray())); } else { lastModified = new Date(0L); } PropertyBasedInstanceConfig config = new PropertyBasedInstanceConfig(properties, defaults); return new LoadedInstanceConfig(config, lastModified.getTime()); } @Override public LoadedInstanceConfig storeConfig(ConfigCollection config, long compareVersion) throws Exception { { BlobProperties blobProperties = getConfigBlobProperties(); if (blobProperties != null) { Date lastModified = blobProperties.getLastModified(); if (lastModified.getTime() != compareVersion) { return null; // pattern copied from S3ConfigProvider - Azure may support a better way } } } PropertyBasedInstanceConfig propertyBasedInstanceConfig = new PropertyBasedInstanceConfig(config); ByteArrayOutputStream out = new ByteArrayOutputStream(); propertyBasedInstanceConfig.getProperties().store(out, String.format(AUTO_GENERATED_NOTE, hostname)); byte[] bytes = out.toByteArray(); azureClient.putBlob(bytes, arguments.getContainer(), arguments.getBlobName()); BlobProperties blobProperties = azureClient.getBlobProperties(arguments.getContainer(), arguments.getBlobName()); return new LoadedInstanceConfig(propertyBasedInstanceConfig, blobProperties.getLastModified().getTime()); } private BlobProperties getConfigBlobProperties() throws Exception { try { BlobProperties properties = azureClient.getBlobProperties(arguments.getContainer(), arguments.getBlobName()); if (properties.getLength() > 0) { return properties; } } catch (StorageException e) { if (!isNotFoundError(e) && !isForbiddenError(e)) { throw e; } } return null; } private CloudBlob getConfigObject() throws Exception { try { CloudBlob object = azureClient.getBlob(arguments.getContainer(), arguments.getBlobName()); object.downloadAttributes(); if (object.getProperties().getLength() > 0) { return object; } } catch (StorageException e) { if (!isNotFoundError(e) && !isForbiddenError(e)) { throw e; } } return null; } private boolean isForbiddenError(StorageException e) { return ((e.getHttpStatusCode() == HTTP_FORBIDDEN)); } private boolean isNotFoundError(StorageException e) { return (e.getHttpStatusCode() == HTTP_NOT_FOUND); } }