/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.apache.brooklyn.core.location.cloud.names;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.objs.HasShortName;
import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
import org.apache.brooklyn.util.core.config.ConfigBag;
import org.apache.brooklyn.util.text.Identifiers;
import org.apache.brooklyn.util.text.Strings;
import com.google.common.annotations.Beta;
import com.google.common.base.CharMatcher;
/**
* Implements <b>most</b> of {@link CloudMachineNamer},
* leaving just one method -- {@link #generateNewIdOfLength(int)} --
* for subclasses to provide.
* <p>
* {@link CloudLocationConfig#VM_NAME_MAX_LENGTH} is used to find the VM length,
* unless {@link #getCustomMaxNameLength(ConfigBag)} is overridden or
* {@link #setDefaultMachineNameMaxLength(int)} invoked on the instance supplied.
*/
public abstract class AbstractCloudMachineNamer implements CloudMachineNamer {
int defaultMachineNameMaxLength = CloudLocationConfig.VM_NAME_MAX_LENGTH.getDefaultValue();
int defaultMachineNameSaltLength = CloudLocationConfig.VM_NAME_SALT_LENGTH.getDefaultValue();
protected String separator = "-";
public String generateNewMachineUniqueName(ConfigBag setup) {
return generateNewIdReservingLength(setup, 0);
}
public String generateNewMachineUniqueNameFromGroupId(ConfigBag setup, String groupId) {
int availSaltLength = getMaxNameLength(setup) - (groupId.length() + separator.length());
int requestedSaltLength = getLengthForMachineUniqueNameSalt(setup, false);
if (availSaltLength <= 0 || requestedSaltLength <= 0) {
return groupId;
}
return sanitize(groupId + separator + Identifiers.makeRandomId(Math.min(requestedSaltLength, availSaltLength))).toLowerCase();
}
public String generateNewGroupId(ConfigBag setup) {
return sanitize(generateNewIdReservingLength(setup, getLengthForMachineUniqueNameSalt(setup, true))).toLowerCase();
}
protected String generateNewIdReservingLength(ConfigBag setup, int lengthToReserve) {
int len = getMaxNameLength(setup);
// decrement by e.g. 9 chars because jclouds adds that (dash plus 8 for hex id)
len -= lengthToReserve;
if (len<=0) return "";
return Strings.maxlen(generateNewIdOfLength(setup, len), len);
}
/** Method for subclasses to provide to construct the context-specific part of an identifier,
* for use in {@link #generateNewGroupId()} and {@link #generateNewMachineUniqueName()}.
*
* @param maxLengthHint an indication of the maximum length permitted for the ID generated,
* supplied for implementations which wish to use this information to decide what to truncate.
* (This class will truncate any return values longer than this.)
*/
protected abstract String generateNewIdOfLength(ConfigBag setup, int maxLengthHint);
/** Returns the max length of a VM name for the cloud specified in setup;
* this value is typically decremented by 9 to make room for jclouds labels;
* delegates to {@link #getCustomMaxNameLength()} when
* {@link CloudLocationConfig#VM_NAME_MAX_LENGTH} is not set */
public int getMaxNameLength(ConfigBag setup) {
if (setup.containsKey(CloudLocationConfig.VM_NAME_MAX_LENGTH)) {
// if a length is set explicitly, use that (but intercept default behaviour)
return setup.get(CloudLocationConfig.VM_NAME_MAX_LENGTH);
}
Integer custom = getCustomMaxNameLength(setup);
if (custom!=null) return custom;
// return the default
return defaultMachineNameMaxLength;
}
// sometimes we create salt string, sometimes jclouds does
public int getLengthForMachineUniqueNameSalt(ConfigBag setup, boolean includeSeparator) {
int saltLen;
if (setup.containsKey(CloudLocationConfig.VM_NAME_SALT_LENGTH)) {
saltLen = setup.get(CloudLocationConfig.VM_NAME_SALT_LENGTH);
} else {
// default value comes from key, but custom default can be set
saltLen = defaultMachineNameSaltLength;
}
if (saltLen>0 && includeSeparator)
saltLen += separator.length();
return saltLen;
}
public AbstractCloudMachineNamer setDefaultMachineNameMaxLength(int defaultMaxLength) {
this.defaultMachineNameMaxLength = defaultMaxLength;
return this;
}
/** Number of chars to use or reserve for the machine identifier when constructing a group identifier;
* jclouds for instance uses "-" plus 8 */
public AbstractCloudMachineNamer setDefaultMachineNameSeparatorAndSaltLength(String separator, int defaultMachineUniqueNameSaltLength) {
this.separator = separator;
this.defaultMachineNameSaltLength = defaultMachineUniqueNameSaltLength;
return this;
}
/** Method for overriding to provide custom logic when an explicit config key is not set for the machine length. */
public Integer getCustomMaxNameLength(ConfigBag setup) {
return null;
}
protected static String shortName(Object x) {
if (x instanceof HasShortName) {
return ((HasShortName)x).getShortName();
}
if (x instanceof Entity) {
return ((Entity)x).getDisplayName();
}
return x.toString();
}
@Beta //probably won't live here long-term
public static String sanitize(String s) {
return CharMatcher.inRange('A', 'Z')
.or(CharMatcher.inRange('a', 'z'))
.or(CharMatcher.inRange('0', '9'))
.negate()
.trimAndCollapseFrom(s, '-');
}
}