/* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch licenses this file to you 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 org.elasticsearch.cloud.azure.storage; import com.microsoft.azure.storage.RetryPolicy; import org.elasticsearch.cloud.azure.storage.AzureStorageService.Storage; import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.SettingsException; import org.elasticsearch.common.unit.TimeValue; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; public final class AzureStorageSettings { private static final Setting<TimeValue> TIMEOUT_SETTING = Setting.affixKeySetting(Storage.PREFIX, "timeout", (key) -> Setting.timeSetting(key, Storage.TIMEOUT_SETTING, Setting.Property.NodeScope)); private static final Setting<String> ACCOUNT_SETTING = Setting.affixKeySetting(Storage.PREFIX, "account", (key) -> Setting.simpleString(key, Setting.Property.NodeScope)); private static final Setting<String> KEY_SETTING = Setting.affixKeySetting(Storage.PREFIX, "key", (key) -> Setting.simpleString(key, Setting.Property.NodeScope)); private static final Setting<Boolean> DEFAULT_SETTING = Setting.affixKeySetting(Storage.PREFIX, "default", (key) -> Setting.boolSetting(key, false, Setting.Property.NodeScope)); /** * max_retries: Number of retries in case of Azure errors. Defaults to 3 (RetryPolicy.DEFAULT_CLIENT_RETRY_COUNT). */ private static final Setting<Integer> MAX_RETRIES_SETTING = Setting.affixKeySetting(Storage.PREFIX, "max_retries", (key) -> Setting.intSetting(key, RetryPolicy.DEFAULT_CLIENT_RETRY_COUNT, Setting.Property.NodeScope)); private final String name; private final String account; private final String key; private final TimeValue timeout; private final boolean activeByDefault; private final int maxRetries; public AzureStorageSettings(String name, String account, String key, TimeValue timeout, boolean activeByDefault, int maxRetries) { this.name = name; this.account = account; this.key = key; this.timeout = timeout; this.activeByDefault = activeByDefault; this.maxRetries = maxRetries; } public String getName() { return name; } public String getKey() { return key; } public String getAccount() { return account; } public TimeValue getTimeout() { return timeout; } public boolean isActiveByDefault() { return activeByDefault; } public int getMaxRetries() { return maxRetries; } @Override public String toString() { final StringBuilder sb = new StringBuilder("AzureStorageSettings{"); sb.append("name='").append(name).append('\''); sb.append(", account='").append(account).append('\''); sb.append(", key='").append(key).append('\''); sb.append(", activeByDefault='").append(activeByDefault).append('\''); sb.append(", timeout=").append(timeout); sb.append(", maxRetries=").append(maxRetries); sb.append('}'); return sb.toString(); } /** * Parses settings and read all settings available under cloud.azure.storage.* * @param settings settings to parse * @return A tuple with v1 = primary storage and v2 = secondary storage */ public static Tuple<AzureStorageSettings, Map<String, AzureStorageSettings>> parse(Settings settings) { List<AzureStorageSettings> storageSettings = createStorageSettings(settings); return Tuple.tuple(getPrimary(storageSettings), getSecondaries(storageSettings)); } private static List<AzureStorageSettings> createStorageSettings(Settings settings) { // ignore global timeout which has the same prefix but does not belong to any group Settings groups = Storage.STORAGE_ACCOUNTS.get(settings.filter((k) -> k.equals(Storage.TIMEOUT_SETTING.getKey()) == false)); List<AzureStorageSettings> storageSettings = new ArrayList<>(); for (String groupName : groups.getAsGroups().keySet()) { storageSettings.add( new AzureStorageSettings( groupName, getValue(settings, groupName, ACCOUNT_SETTING), getValue(settings, groupName, KEY_SETTING), getValue(settings, groupName, TIMEOUT_SETTING), getValue(settings, groupName, DEFAULT_SETTING), getValue(settings, groupName, MAX_RETRIES_SETTING)) ); } return storageSettings; } private static <T> T getValue(Settings settings, String groupName, Setting<T> setting) { Setting.AffixKey k = (Setting.AffixKey) setting.getRawKey(); String fullKey = k.toConcreteKey(groupName).toString(); return setting.getConcreteSetting(fullKey).get(settings); } private static AzureStorageSettings getPrimary(List<AzureStorageSettings> settings) { if (settings.isEmpty()) { return null; } else if (settings.size() == 1) { // the only storage settings belong (implicitly) to the default primary storage AzureStorageSettings storage = settings.get(0); return new AzureStorageSettings(storage.getName(), storage.getAccount(), storage.getKey(), storage.getTimeout(), true, storage.getMaxRetries()); } else { AzureStorageSettings primary = null; for (AzureStorageSettings setting : settings) { if (setting.isActiveByDefault()) { if (primary == null) { primary = setting; } else { throw new SettingsException("Multiple default Azure data stores configured: [" + primary.getName() + "] and [" + setting.getName() + "]"); } } } if (primary == null) { throw new SettingsException("No default Azure data store configured"); } return primary; } } private static Map<String, AzureStorageSettings> getSecondaries(List<AzureStorageSettings> settings) { Map<String, AzureStorageSettings> secondaries = new HashMap<>(); // when only one setting is defined, we don't have secondaries if (settings.size() > 1) { for (AzureStorageSettings setting : settings) { if (setting.isActiveByDefault() == false) { secondaries.put(setting.getName(), setting); } } } return Collections.unmodifiableMap(secondaries); } }