http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java b/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java deleted file mode 100644 index 73766c2..0000000 --- a/core/src/main/java/brooklyn/location/basic/FixedListMachineProvisioningLocation.java +++ /dev/null @@ -1,474 +0,0 @@ -/* - * 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 brooklyn.location.basic; - -import static brooklyn.util.GroovyJavaMethods.truth; - -import java.io.Closeable; -import java.io.File; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.brooklyn.api.management.LocationManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Function; -import com.google.common.base.Objects; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.google.common.reflect.TypeToken; - -import brooklyn.config.ConfigKey; -import brooklyn.entity.basic.ConfigKeys; -import brooklyn.location.Location; -import brooklyn.location.LocationSpec; -import brooklyn.location.MachineLocation; -import brooklyn.location.MachineLocationCustomizer; -import brooklyn.location.MachineProvisioningLocation; -import brooklyn.location.NoMachinesAvailableException; -import brooklyn.location.cloud.CloudLocationConfig; -import brooklyn.util.collections.CollectionFunctionals; -import brooklyn.util.collections.MutableMap; -import brooklyn.util.collections.MutableSet; -import brooklyn.util.config.ConfigBag; -import brooklyn.util.flags.SetFromFlag; -import brooklyn.util.stream.Streams; -import brooklyn.util.text.WildcardGlobs; -import brooklyn.util.text.WildcardGlobs.PhraseTreatment; - -/** - * A provisioner of {@link MachineLocation}s which takes a list of machines it can connect to. - * The collection of initial machines should be supplied in the 'machines' flag in the constructor, - * for example a list of machines which can be SSH'd to. - * - * This can be extended to have a mechanism to make more machines to be available - * (override provisionMore and canProvisionMore). - */ -public class FixedListMachineProvisioningLocation<T extends MachineLocation> extends AbstractLocation -implements MachineProvisioningLocation<T>, Closeable { - - // TODO Synchronization looks very wrong for accessing machines/inUse - // e.g. removeChild doesn't synchronize when doing machines.remove(...), - // and getMachines() returns the real sets risking - // ConcurrentModificationException in the caller if it iterates over them etc. - - private static final Logger log = LoggerFactory.getLogger(FixedListMachineProvisioningLocation.class); - - public static final ConfigKey<Function<Iterable<? extends MachineLocation>, MachineLocation>> MACHINE_CHOOSER = - ConfigKeys.newConfigKey( - new TypeToken<Function<Iterable<? extends MachineLocation>, MachineLocation>>() {}, - "byon.machineChooser", - "For choosing which of the possible machines is chosen and returned by obtain()", - CollectionFunctionals.<MachineLocation>firstElement()); - - public static final ConfigKey<Collection<MachineLocationCustomizer>> MACHINE_LOCATION_CUSTOMIZERS = CloudLocationConfig.MACHINE_LOCATION_CUSTOMIZERS; - - private final Object lock = new Object(); - - @SetFromFlag - protected Set<T> machines; - - @SetFromFlag - protected Set<T> inUse; - - @SetFromFlag - protected Set<T> pendingRemoval; - - @SetFromFlag - protected Map<T, Map<String, Object>> origConfigs; - - public FixedListMachineProvisioningLocation() { - this(Maps.newLinkedHashMap()); - } - public FixedListMachineProvisioningLocation(Map properties) { - super(properties); - - if (isLegacyConstruction()) { - init(); - } - } - - @Override - public void init() { - super.init(); - - Set<T> machinesCopy = MutableSet.of(); - for (T location: machines) { - if (location==null) { - log.warn(""+this+" initialized with null location, removing (may be due to rebind with reference to an unmanaged location)"); - } else { - Location parent = location.getParent(); - if (parent == null) { - addChild(location); - } - machinesCopy.add(location); - } - } - if (!machinesCopy.equals(machines)) { - machines = machinesCopy; - } - } - - @Override - public String toVerboseString() { - return Objects.toStringHelper(this).omitNullValues() - .add("id", getId()).add("name", getDisplayName()) - .add("machinesAvailable", getAvailable()).add("machinesInUse", getInUse()) - .toString(); - } - - @Override - public AbstractLocation configure(Map<?,?> properties) { - if (machines == null) machines = Sets.newLinkedHashSet(); - if (inUse == null) inUse = Sets.newLinkedHashSet(); - if (pendingRemoval == null) pendingRemoval = Sets.newLinkedHashSet(); - if (origConfigs == null) origConfigs = Maps.newLinkedHashMap(); - return super.configure(properties); - } - - @SuppressWarnings("unchecked") - public FixedListMachineProvisioningLocation<T> newSubLocation(Map<?,?> newFlags) { - // TODO shouldn't have to copy config bag as it should be inherited (but currently it is not used inherited everywhere; just most places) - return getManagementContext().getLocationManager().createLocation(LocationSpec.create(getClass()) - .parent(this) - .configure(config().getLocalBag().getAllConfig()) // FIXME Should this just be inherited? - .configure(newFlags)); - } - - @Override - public void close() { - for (T machine : machines) { - if (machine instanceof Closeable) Streams.closeQuietly((Closeable)machine); - } - } - - public void addMachine(T machine) { - synchronized (lock) { - if (machines.contains(machine)) { - throw new IllegalArgumentException("Cannot add "+machine+" to "+toString()+", because already contained"); - } - - Location existingParent = ((Location)machine).getParent(); - if (existingParent == null) { - addChild(machine); - } - - machines.add(machine); - } - } - - public void removeMachine(T machine) { - synchronized (lock) { - if (inUse.contains(machine)) { - pendingRemoval.add(machine); - } else { - machines.remove(machine); - pendingRemoval.remove(machine); - if (this.equals(machine.getParent())) { - removeChild((Location)machine); - } - } - } - } - - protected Set<T> getMachines() { - return machines; - } - - public Set<T> getAvailable() { - Set<T> a = Sets.newLinkedHashSet(machines); - a.removeAll(inUse); - return a; - } - - public Set<T> getInUse() { - return Sets.newLinkedHashSet(inUse); - } - - public Set<T> getAllMachines() { - return ImmutableSet.copyOf(machines); - } - - @Override - public void addChild(Location child) { - super.addChild(child); - machines.add((T)child); - } - - @Override - public boolean removeChild(Location child) { - if (inUse.contains(child)) { - throw new IllegalStateException("Child location "+child+" is in use; cannot remove from "+this); - } - machines.remove(child); - return super.removeChild(child); - } - - protected boolean canProvisionMore() { - return false; - } - - protected void provisionMore(int size) { - provisionMore(size, ImmutableMap.of()); - } - - protected void provisionMore(int size, Map<?,?> flags) { - throw new IllegalStateException("more not permitted"); - } - - public T obtain() throws NoMachinesAvailableException { - return obtain(Maps.<String,Object>newLinkedHashMap()); - } - - @Override - public T obtain(Map<?,?> flags) throws NoMachinesAvailableException { - T machine; - T desiredMachine = (T) flags.get("desiredMachine"); - ConfigBag allflags = ConfigBag.newInstanceExtending(config().getBag()).putAll(flags); - Function<Iterable<? extends MachineLocation>, MachineLocation> chooser = allflags.get(MACHINE_CHOOSER); - - synchronized (lock) { - Set<T> a = getAvailable(); - if (a.isEmpty()) { - if (canProvisionMore()) { - provisionMore(1, allflags.getAllConfig()); - a = getAvailable(); - } - if (a.isEmpty()) - throw new NoMachinesAvailableException("No machines available in "+toString()); - } - if (desiredMachine != null) { - if (a.contains(desiredMachine)) { - machine = desiredMachine; - } else { - throw new IllegalStateException("Desired machine "+desiredMachine+" not available in "+toString()+"; "+ - (inUse.contains(desiredMachine) ? "machine in use" : "machine unknown")); - } - } else { - machine = (T) chooser.apply(a); - if (!a.contains(machine)) { - throw new IllegalStateException("Machine chooser attempted to choose '"+machine+"' from outside the available set, in "+this); - } - } - inUse.add(machine); - updateMachineConfig(machine, flags); - } - - for (MachineLocationCustomizer customizer : getMachineCustomizers(allflags)) { - customizer.customize(machine); - } - - return machine; - } - - @Override - public void release(T machine) { - ConfigBag machineConfig = ((ConfigurationSupportInternal)machine.config()).getBag(); - for (MachineLocationCustomizer customizer : getMachineCustomizers(machineConfig)) { - customizer.preRelease(machine); - } - - synchronized (lock) { - if (inUse.contains(machine) == false) - throw new IllegalStateException("Request to release machine "+machine+", but this machine is not currently allocated"); - restoreMachineConfig(machine); - inUse.remove(machine); - - if (pendingRemoval.contains(machine)) { - removeMachine(machine); - } - } - } - - @Override - public Map<String,Object> getProvisioningFlags(Collection<String> tags) { - return Maps.<String,Object>newLinkedHashMap(); - } - - protected void updateMachineConfig(T machine, Map<?, ?> flags) { - if (origConfigs == null) { - // For backwards compatibility, where peristed state did not have this. - origConfigs = Maps.newLinkedHashMap(); - } - Map<String, Object> strFlags = ConfigBag.newInstance(flags).getAllConfig(); - Map<String, Object> origConfig = ((ConfigurationSupportInternal)machine.config()).getLocalBag().getAllConfig(); - origConfigs.put(machine, origConfig); - requestPersist(); - - ((ConfigurationSupportInternal)machine.config()).addToLocalBag(strFlags); - } - - protected void restoreMachineConfig(MachineLocation machine) { - if (origConfigs == null) { - // For backwards compatibility, where peristed state did not have this. - origConfigs = Maps.newLinkedHashMap(); - } - Map<String, Object> origConfig = origConfigs.remove(machine); - if (origConfig == null) return; - requestPersist(); - - Set<String> currentKeys = ((ConfigurationSupportInternal)machine.config()).getLocalBag().getAllConfig().keySet(); - Set<String> newKeys = Sets.difference(currentKeys, origConfig.entrySet()); - for (String key : newKeys) { - ((ConfigurationSupportInternal)machine.config()).removeFromLocalBag(key); - } - ((ConfigurationSupportInternal)machine.config()).addToLocalBag(origConfig); - } - - @SuppressWarnings("unchecked") - private <K> K getConfigPreferringOverridden(ConfigKey<K> key, Map<?,?> overrides) { - K result = (K) overrides.get(key); - if (result == null) result = (K) overrides.get(key.getName()); - if (result == null) result = getConfig(key); - return result; - } - - protected Collection<MachineLocationCustomizer> getMachineCustomizers(ConfigBag setup) { - Collection<MachineLocationCustomizer> customizers = setup.get(MACHINE_LOCATION_CUSTOMIZERS); - return (customizers == null ? ImmutableList.<MachineLocationCustomizer>of() : customizers); - } - - /** - * Facilitates fluent/programmatic style for constructing a fixed pool of machines. - * <pre> - * {@code - * new FixedListMachineProvisioningLocation.Builder() - * .user("alex") - * .keyFile("/Users/alex/.ssh/id_rsa") - * .addAddress("10.0.0.1") - * .addAddress("10.0.0.2") - * .addAddress("10.0.0.3") - * .addAddressMultipleTimes("[email protected]", 5) - * .build(); - * } - * </pre> - */ - public static class Builder { - LocationManager lm; - String user; - String privateKeyPassphrase; - String privateKeyFile; - String privateKeyData; - File localTempDir; - List machines = Lists.newArrayList(); - - public Builder(LocationManager lm) { - this.lm = lm; - } - public Builder user(String user) { - this.user = user; - return this; - } - public Builder keyPassphrase(String keyPassphrase) { - this.privateKeyPassphrase = keyPassphrase; - return this; - } - public Builder keyFile(String keyFile) { - this.privateKeyFile = keyFile; - return this; - } - public Builder keyData(String keyData) { - this.privateKeyData = keyData; - return this; - } - public Builder localTempDir(File val) { - this.localTempDir = val; - return this; - } - /** adds the locations; user and keyfile set in the builder are _not_ applied to the machine - * (use add(String address) for that) - */ - public Builder add(SshMachineLocation location) { - machines.add(location); - return this; - } - public Builder addAddress(String address) { - return addAddresses(address); - } - public Builder addAddressMultipleTimes(String address, int n) { - for (int i=0; i<n; i++) - addAddresses(address); - return this; - } - public Builder addAddresses(String address1, String ...others) { - List<String> addrs = new ArrayList<String>(); - addrs.addAll(WildcardGlobs.getGlobsAfterBraceExpansion("{"+address1+"}", - true /* numeric */, /* no quote support though */ PhraseTreatment.NOT_A_SPECIAL_CHAR, PhraseTreatment.NOT_A_SPECIAL_CHAR)); - for (String address: others) - addrs.addAll(WildcardGlobs.getGlobsAfterBraceExpansion("{"+address+"}", - true /* numeric */, /* no quote support though */ PhraseTreatment.NOT_A_SPECIAL_CHAR, PhraseTreatment.NOT_A_SPECIAL_CHAR)); - for (String addr: addrs) - add(createMachine(addr)); - return this; - } - protected SshMachineLocation createMachine(String addr) { - if (lm==null) - return new SshMachineLocation(makeConfig(addr)); - else - return lm.createLocation(makeConfig(addr), SshMachineLocation.class); - } - private Map makeConfig(String address) { - String user = this.user; - if (address.contains("@")) { - user = address.substring(0, address.indexOf("@")); - address = address.substring(address.indexOf("@")+1); - } - Map config = MutableMap.of("address", address); - if (truth(user)) { - config.put("user", user); - config.put("sshconfig.user", user); - } - if (truth(privateKeyPassphrase)) config.put("sshconfig.privateKeyPassphrase", privateKeyPassphrase); - if (truth(privateKeyFile)) config.put("sshconfig.privateKeyFile", privateKeyFile); - if (truth(privateKeyData)) config.put("sshconfig.privateKey", privateKeyData); - if (truth(localTempDir)) config.put("localTempDir", localTempDir); - return config; - } - @SuppressWarnings("unchecked") - public FixedListMachineProvisioningLocation<SshMachineLocation> build() { - if (lm==null) - return new FixedListMachineProvisioningLocation<SshMachineLocation>(MutableMap.builder() - .putIfNotNull("machines", machines) - .putIfNotNull("user", user) - .putIfNotNull("privateKeyPassphrase", privateKeyPassphrase) - .putIfNotNull("privateKeyFile", privateKeyFile) - .putIfNotNull("privateKeyData", privateKeyData) - .putIfNotNull("localTempDir", localTempDir) - .build()); - else - return lm.createLocation(MutableMap.builder() - .putIfNotNull("machines", machines) - .putIfNotNull("user", user) - .putIfNotNull("privateKeyPassphrase", privateKeyPassphrase) - .putIfNotNull("privateKeyFile", privateKeyFile) - .putIfNotNull("privateKeyData", privateKeyData) - .putIfNotNull("localTempDir", localTempDir) - .build(), - FixedListMachineProvisioningLocation.class); - } - } -}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/location/basic/HasSubnetHostname.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/location/basic/HasSubnetHostname.java b/core/src/main/java/brooklyn/location/basic/HasSubnetHostname.java deleted file mode 100644 index 1ad8f1b..0000000 --- a/core/src/main/java/brooklyn/location/basic/HasSubnetHostname.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 brooklyn.location.basic; - -import com.google.common.annotations.Beta; - -@Beta -public interface HasSubnetHostname { - - /** returns a hostname for use internally within a subnet / VPC */ - @Beta - String getSubnetHostname(); - - /** returns an IP for use internally within a subnet / VPC */ - String getSubnetIp(); -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/location/basic/HostLocationResolver.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/location/basic/HostLocationResolver.java b/core/src/main/java/brooklyn/location/basic/HostLocationResolver.java deleted file mode 100644 index 2bb5b4b..0000000 --- a/core/src/main/java/brooklyn/location/basic/HostLocationResolver.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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 brooklyn.location.basic; - -import java.util.Map; - -import brooklyn.location.Location; -import brooklyn.location.LocationRegistry; -import brooklyn.location.LocationSpec; -import brooklyn.location.basic.AbstractLocationResolver.SpecParser.ParsedSpec; -import brooklyn.util.config.ConfigBag; -import brooklyn.util.exceptions.Exceptions; -import brooklyn.util.guava.Maybe; -import brooklyn.util.guava.Maybe.Absent; -import brooklyn.util.text.KeyValueParser; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; - -public class HostLocationResolver extends AbstractLocationResolver { - - private static final String HOST = "host"; - - @SuppressWarnings("rawtypes") - @Override - public Location newLocationFromString(Map locationFlags, String spec, LocationRegistry registry) { - // Extract args from spec - ParsedSpec parsedSpec = specParser.parse(spec); - Map<String, String> argsMap = parsedSpec.argsMap; - if (argsMap.isEmpty()) { - throw new IllegalArgumentException("Invalid host spec (no host supplied): "+spec); - } else if (argsMap.size() == 1 && Iterables.get(argsMap.values(), 0) == null) { - // only given ip or hostname - argsMap = ImmutableMap.of("hosts", Iterables.get(argsMap.keySet(), 0)); - } else if (!(argsMap.containsKey("host") || argsMap.containsKey("hosts"))) { - throw new IllegalArgumentException("Invalid host spec (no host supplied): "+spec); - } - - // Find generic applicable properties - Map globalProperties = registry.getProperties(); - String namedLocation = (String) locationFlags.get(LocationInternal.NAMED_SPEC_NAME.getName()); - Map<String, Object> filteredProperties = new LocationPropertiesFromBrooklynProperties().getLocationProperties(null, namedLocation, globalProperties); - ConfigBag flags = ConfigBag.newInstance(locationFlags).putIfAbsent(filteredProperties); - flags.remove(LocationInternal.NAMED_SPEC_NAME); - - // Generate target spec - String target = "byon("+KeyValueParser.toLine(argsMap)+")"; - Maybe<Location> testResolve = managementContext.getLocationRegistry().resolve(target, false, null); - if (!testResolve.isPresent()) { - throw new IllegalArgumentException("Invalid target location '" + target + "' for location '"+HOST+"': "+ - Exceptions.collapseText( ((Absent<?>)testResolve).getException() ), ((Absent<?>)testResolve).getException()); - } - - return managementContext.getLocationManager().createLocation(LocationSpec.create(SingleMachineProvisioningLocation.class) - .configure("location", target) - .configure("locationFlags", flags.getAllConfig()) - .configure(LocationConfigUtils.finalAndOriginalSpecs(spec, locationFlags, globalProperties, namedLocation))); - } - - @Override - public String getPrefix() { - return HOST; - } - - @Override - protected Class<? extends Location> getLocationType() { - return SingleMachineProvisioningLocation.class; - } - - @Override - protected SpecParser getSpecParser() { - return new SpecParser(getPrefix()).setExampleUsage("\"host(1.1.1.1)\" or \"host(host=1.1.1.1,name=myname)\""); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/location/basic/LocalhostLocationResolver.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/location/basic/LocalhostLocationResolver.java b/core/src/main/java/brooklyn/location/basic/LocalhostLocationResolver.java deleted file mode 100644 index 6451ed1..0000000 --- a/core/src/main/java/brooklyn/location/basic/LocalhostLocationResolver.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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 brooklyn.location.basic; - -import java.util.Map; - -import brooklyn.location.Location; -import brooklyn.location.LocationResolver.EnableableLocationResolver; -import brooklyn.util.config.ConfigBag; - -/** - * Examples of valid specs: - * <ul> - * <li>localhost - * <li>localhost() - * <li>localhost(name=abc) - * <li>localhost(name="abc") - * </ul> - * - * @author alex, aled - */ -public class LocalhostLocationResolver extends AbstractLocationResolver implements EnableableLocationResolver { - - public static final String LOCALHOST = "localhost"; - - @Override - public String getPrefix() { - return LOCALHOST; - } - - @Override - public boolean isEnabled() { - return LocationConfigUtils.isEnabled(managementContext, "brooklyn.location.localhost"); - } - - @Override - protected Class<? extends Location> getLocationType() { - return LocalhostMachineProvisioningLocation.class; - } - - @Override - protected SpecParser getSpecParser() { - return new AbstractLocationResolver.SpecParser(getPrefix()).setExampleUsage("\"localhost\" or \"localhost(displayName=abc)\""); - } - - @Override - protected Map<String, Object> getFilteredLocationProperties(String provider, String namedLocation, Map<String, ?> globalProperties) { - return new LocalhostPropertiesFromBrooklynProperties().getLocationProperties("localhost", namedLocation, globalProperties); - } - - @Override - protected ConfigBag extractConfig(Map<?,?> locationFlags, String spec, brooklyn.location.LocationRegistry registry) { - ConfigBag config = super.extractConfig(locationFlags, spec, registry); - config.putAsStringKeyIfAbsent("name", "localhost"); - return config; - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/location/basic/LocalhostMachineProvisioningLocation.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/location/basic/LocalhostMachineProvisioningLocation.java b/core/src/main/java/brooklyn/location/basic/LocalhostMachineProvisioningLocation.java deleted file mode 100644 index 64f31f9..0000000 --- a/core/src/main/java/brooklyn/location/basic/LocalhostMachineProvisioningLocation.java +++ /dev/null @@ -1,346 +0,0 @@ -/* - * 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 brooklyn.location.basic; - -import static brooklyn.util.GroovyJavaMethods.elvis; -import static brooklyn.util.GroovyJavaMethods.truth; - -import java.io.File; -import java.net.InetAddress; -import java.util.Arrays; -import java.util.Map; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import brooklyn.config.ConfigKey; -import brooklyn.config.ConfigKey.HasConfigKey; -import brooklyn.entity.basic.BrooklynConfigKeys; -import brooklyn.entity.basic.ConfigKeys; -import brooklyn.entity.rebind.persister.FileBasedObjectStore; -import brooklyn.entity.rebind.persister.LocationWithObjectStore; -import brooklyn.entity.rebind.persister.PersistenceObjectStore; -import brooklyn.location.AddressableLocation; -import brooklyn.location.LocationSpec; -import brooklyn.location.OsDetails; -import brooklyn.location.PortRange; -import brooklyn.location.geo.HostGeoInfo; -import brooklyn.util.BrooklynNetworkUtils; -import brooklyn.util.collections.MutableMap; -import brooklyn.util.flags.SetFromFlag; -import brooklyn.util.internal.ssh.process.ProcessTool; -import brooklyn.util.mutex.MutexSupport; -import brooklyn.util.mutex.WithMutexes; -import brooklyn.util.net.Networking; -import brooklyn.util.os.Os; -import brooklyn.util.ssh.BashCommands; -import brooklyn.util.time.Duration; -import brooklyn.util.time.Time; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - -/** - * An implementation of {@link brooklyn.location.MachineProvisioningLocation} that can provision a {@link SshMachineLocation} for the - * local host. - * - * By default you can only obtain a single SshMachineLocation for the localhost. Optionally, you can "overload" - * and choose to allow localhost to be provisioned multiple times, which may be useful in some testing scenarios. - */ -public class LocalhostMachineProvisioningLocation extends FixedListMachineProvisioningLocation<SshMachineLocation> implements AddressableLocation, LocationWithObjectStore { - - public static final Logger LOG = LoggerFactory.getLogger(LocalhostMachineProvisioningLocation.class); - - public static final ConfigKey<Boolean> SKIP_ON_BOX_BASE_DIR_RESOLUTION = ConfigKeys.newConfigKeyWithDefault( - BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, - true); - - @SetFromFlag("count") - int initialCount; - - @SetFromFlag - Boolean canProvisionMore; - - @SetFromFlag - InetAddress address; - - private static Set<Integer> portsInUse = Sets.newLinkedHashSet(); - - private static HostGeoInfo cachedHostGeoInfo; - - @VisibleForTesting - public static void clearStaticData() { - portsInUse.clear(); - cachedHostGeoInfo = null; - } - - /** - * Construct a new instance. - * - * The constructor recognises the following properties: - * <ul> - * <li>count - number of localhost machines to make available - * </ul> - */ - public LocalhostMachineProvisioningLocation() { - this(Maps.newLinkedHashMap()); - } - /** - * @param properties the properties of the new instance. - * @deprecated since 0.6 - * @see #LocalhostMachineProvisioningLocation() - */ - public LocalhostMachineProvisioningLocation(Map properties) { - super(properties); - } - public LocalhostMachineProvisioningLocation(String name) { - this(name, 0); - } - public LocalhostMachineProvisioningLocation(String name, int count) { - this(MutableMap.of("name", name, "count", count)); - } - - public static LocationSpec<LocalhostMachineProvisioningLocation> spec() { - return LocationSpec.create(LocalhostMachineProvisioningLocation.class); - } - - public LocalhostMachineProvisioningLocation configure(Map<?,?> flags) { - super.configure(flags); - - if (!truth(getDisplayName())) { setDisplayName("localhost"); } - if (!truth(address)) address = getLocalhostInetAddress(); - // TODO should try to confirm this machine is accessible on the given address ... but there's no - // immediate convenience in java so early-trapping of that particular error is deferred - - if (canProvisionMore==null) { - if (initialCount>0) canProvisionMore = false; - else canProvisionMore = true; - } - if (getHostGeoInfo()==null) { - if (cachedHostGeoInfo==null) - cachedHostGeoInfo = HostGeoInfo.fromLocation(this); - setHostGeoInfo(cachedHostGeoInfo); - } - if (initialCount > getMachines().size()) { - provisionMore(initialCount - getMachines().size()); - } - - if (getConfig(BrooklynConfigKeys.ONBOX_BASE_DIR)==null && (getManagementContext()==null || getManagementContext().getConfig().getConfig(BrooklynConfigKeys.ONBOX_BASE_DIR)==null)) { - setConfig(BrooklynConfigKeys.ONBOX_BASE_DIR, "/tmp/brooklyn-"+Os.user()); - } - - return this; - } - - public static InetAddress getLocalhostInetAddress() { - return BrooklynNetworkUtils.getLocalhostInetAddress(); - } - - @Override - public InetAddress getAddress() { - return address; - } - - @Override - public boolean canProvisionMore() { - return canProvisionMore; - } - - @Override - protected void provisionMore(int size, Map<?,?> flags) { - for (int i=0; i<size; i++) { - Map<Object,Object> flags2 = MutableMap.<Object,Object>builder() - .putAll(flags) - .put("address", elvis(address, Networking.getLocalHost())) - .put("mutexSupport", LocalhostMachine.mutexSupport) - .build(); - - // copy inherited keys for ssh; - // shouldn't be necessary but not sure that all contexts traverse the hierarchy - // NOTE: changed Nov 2013 to copy only those ssh config keys actually set, rather than all of them - // TODO should take the plunge and try removing this altogether! - // (or alternatively switch to copying all ancestor keys) - for (HasConfigKey<?> k: SshMachineLocation.ALL_SSH_CONFIG_KEYS) { - if (config().getRaw(k).isPresent()) - flags2.put(k, getConfig(k)); - } - - if (isManaged()) { - addChild(LocationSpec.create(LocalhostMachine.class).configure(flags2)); - } else { - addChild(new LocalhostMachine(flags2)); // TODO legacy way - } - } - } - - public static synchronized boolean obtainSpecificPort(InetAddress localAddress, int portNumber) { - if (portsInUse.contains(portNumber)) { - return false; - } else { - //see if it is available? - if (!checkPortAvailable(localAddress, portNumber)) { - return false; - } - portsInUse.add(portNumber); - return true; - } - } - /** checks the actual availability of the port on localhost, ie by binding to it; cf {@link Networking#isPortAvailable(int)} */ - public static boolean checkPortAvailable(InetAddress localAddress, int portNumber) { - if (portNumber<1024) { - if (LOG.isDebugEnabled()) LOG.debug("Skipping system availability check for privileged localhost port "+portNumber); - return true; - } - return Networking.isPortAvailable(localAddress, portNumber); - } - public static int obtainPort(PortRange range) { - return obtainPort(getLocalhostInetAddress(), range); - } - public static int obtainPort(InetAddress localAddress, PortRange range) { - for (int p: range) - if (obtainSpecificPort(localAddress, p)) return p; - if (LOG.isDebugEnabled()) LOG.debug("unable to find port in {} on {}; returning -1", range, localAddress); - return -1; - } - - public static synchronized void releasePort(InetAddress localAddress, int portNumber) { - portsInUse.remove((Object) portNumber); - } - - public void release(SshMachineLocation machine) { - LocalhostMachine localMachine = (LocalhostMachine) machine; - Set<Integer> portsObtained = Sets.newLinkedHashSet(); - synchronized (localMachine.portsObtained) { - portsObtained.addAll(localMachine.portsObtained); - } - - super.release(machine); - - for (int p: portsObtained) - releasePort(null, p); - } - - public static class LocalhostMachine extends SshMachineLocation implements HasSubnetHostname { - // declaring this here (as well as on LocalhostMachineProvisioningLocation) because: - // 1. machine.getConfig(key) will not inherit default value of machine.getParent()'s key - // 2. things might instantiate a `LocalhostMachine` without going through LocalhostMachineProvisioningLocation - // so not sufficient for LocalhostMachineProvisioningLocation to just push its config value into - // the LocalhostMachine instance. - public static final ConfigKey<Boolean> SKIP_ON_BOX_BASE_DIR_RESOLUTION = ConfigKeys.newConfigKeyWithDefault( - BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, - true); - - private static final WithMutexes mutexSupport = new MutexSupport(); - - private final Set<Integer> portsObtained = Sets.newLinkedHashSet(); - - public LocalhostMachine() { - super(); - } - /** @deprecated since 0.6.0 use no-arg constructor (and spec) then configure */ - public LocalhostMachine(Map properties) { - super(MutableMap.builder().putAll(properties).put("mutexSupport", mutexSupport).build()); - } - - @Override - protected WithMutexes getMutexSupport() { - return mutexSupport; - } - - public boolean obtainSpecificPort(int portNumber) { - if (!isSudoAllowed() && portNumber <= 1024) - return false; - return LocalhostMachineProvisioningLocation.obtainSpecificPort(getAddress(), portNumber); - } - - public int obtainPort(PortRange range) { - int r = LocalhostMachineProvisioningLocation.obtainPort(getAddress(), range); - synchronized (portsObtained) { - if (r>0) portsObtained.add(r); - } - LOG.debug("localhost.obtainPort("+range+"), returning "+r); - return r; - } - - @Override - public void releasePort(int portNumber) { - synchronized (portsObtained) { - portsObtained.remove((Object)portNumber); - } - LocalhostMachineProvisioningLocation.releasePort(getAddress(), portNumber); - } - - @Override - public OsDetails getOsDetails() { - return BasicOsDetails.Factory.newLocalhostInstance(); - } - - @Override - public LocalhostMachine configure(Map<?,?> properties) { - if (address==null || !properties.containsKey("address")) - address = Networking.getLocalHost(); - super.configure(properties); - return this; - } - @Override - public String getSubnetHostname() { - return Networking.getLocalHost().getHostName(); - } - @Override - public String getSubnetIp() { - return Networking.getLocalHost().getHostAddress(); - } - } - - private static class SudoChecker { - static volatile long lastSudoCheckTime = -1; - static boolean lastSudoResult = false; - public static boolean isSudoAllowed() { - if (Time.hasElapsedSince(lastSudoCheckTime, Duration.FIVE_MINUTES)) - checkIfNeeded(); - return lastSudoResult; - } - private static synchronized void checkIfNeeded() { - if (Time.hasElapsedSince(lastSudoCheckTime, Duration.FIVE_MINUTES)) { - try { - lastSudoResult = new ProcessTool().execCommands(MutableMap.<String,Object>of(), Arrays.asList( - BashCommands.sudo("date"))) == 0; - } catch (Exception e) { - lastSudoResult = false; - LOG.debug("Error checking sudo at localhost: "+e, e); - } - lastSudoCheckTime = System.currentTimeMillis(); - } - } - } - - public static boolean isSudoAllowed() { - return SudoChecker.isSudoAllowed(); - } - - @Override - public PersistenceObjectStore newPersistenceObjectStore(String container) { - File basedir = new File(container); - if (basedir.isFile()) throw new IllegalArgumentException("Destination directory must not be a file"); - return new FileBasedObjectStore(basedir); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/location/basic/LocalhostPropertiesFromBrooklynProperties.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/location/basic/LocalhostPropertiesFromBrooklynProperties.java b/core/src/main/java/brooklyn/location/basic/LocalhostPropertiesFromBrooklynProperties.java deleted file mode 100644 index c76fe96..0000000 --- a/core/src/main/java/brooklyn/location/basic/LocalhostPropertiesFromBrooklynProperties.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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 brooklyn.location.basic; - -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import brooklyn.util.config.ConfigBag; - -import com.google.common.base.Strings; - -/** - * @author aledsage - **/ -public class LocalhostPropertiesFromBrooklynProperties extends LocationPropertiesFromBrooklynProperties { - - // TODO Once delete support for deprecated "location.localhost.*" then can get rid of this class, and use - // LocationPropertiesFromBrooklynProperties directly - - @SuppressWarnings("unused") - private static final Logger LOG = LoggerFactory.getLogger(LocalhostPropertiesFromBrooklynProperties.class); - - @Override - public Map<String, Object> getLocationProperties(String provider, String namedLocation, Map<String, ?> properties) { - if (Strings.isNullOrEmpty(namedLocation) && Strings.isNullOrEmpty(provider)) { - throw new IllegalArgumentException("Neither cloud provider/API nor location name have been specified correctly"); - } - - ConfigBag result = ConfigBag.newInstance(); - - result.putAll(transformDeprecated(getGenericLocationSingleWordProperties(properties))); - result.putAll(transformDeprecated(getMatchingSingleWordProperties("brooklyn.location.", properties))); - result.putAll(transformDeprecated(getMatchingProperties("brooklyn.location.localhost.", "brooklyn.localhost.", properties))); - if (!Strings.isNullOrEmpty(namedLocation)) result.putAll(transformDeprecated(getNamedLocationProperties(namedLocation, properties))); - setLocalTempDir(properties, result); - - return result.getAllConfigRaw(); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/location/basic/LocationConfigKeys.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/location/basic/LocationConfigKeys.java b/core/src/main/java/brooklyn/location/basic/LocationConfigKeys.java deleted file mode 100644 index 2d341b8..0000000 --- a/core/src/main/java/brooklyn/location/basic/LocationConfigKeys.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 brooklyn.location.basic; - -import java.io.File; -import java.util.Set; - -import brooklyn.config.ConfigKey; -import brooklyn.entity.basic.ConfigKeys; -import brooklyn.event.basic.BasicConfigKey; -import brooklyn.util.os.Os; - -import com.google.common.base.CaseFormat; -import com.google.common.reflect.TypeToken; - -public class LocationConfigKeys { - - public static final ConfigKey<String> LOCATION_ID = ConfigKeys.newStringConfigKey("id"); - public static final ConfigKey<String> DISPLAY_NAME = ConfigKeys.newStringConfigKey("displayName"); - public static final ConfigKey<Boolean> ENABLED = ConfigKeys.newBooleanConfigKey("enabled", "Whether the location is enabled for listing and use " - + "(only supported for selected locations)", true); - - public static final ConfigKey<String> ACCESS_IDENTITY = ConfigKeys.newStringConfigKey("identity"); - public static final ConfigKey<String> ACCESS_CREDENTIAL = ConfigKeys.newStringConfigKey("credential"); - - public static final ConfigKey<Double> LATITUDE = new BasicConfigKey<Double>(Double.class, "latitude"); - public static final ConfigKey<Double> LONGITUDE = new BasicConfigKey<Double>(Double.class, "longitude"); - - public static final ConfigKey<String> CLOUD_PROVIDER = ConfigKeys.newStringConfigKey("provider"); - public static final ConfigKey<String> CLOUD_ENDPOINT = ConfigKeys.newStringConfigKey("endpoint"); - public static final ConfigKey<String> CLOUD_REGION_ID = ConfigKeys.newStringConfigKey("region"); - public static final ConfigKey<String> CLOUD_AVAILABILITY_ZONE_ID = ConfigKeys.newStringConfigKey("availabilityZone"); - - @SuppressWarnings("serial") - public static final ConfigKey<Set<String>> ISO_3166 = ConfigKeys.newConfigKey(new TypeToken<Set<String>>() {}, "iso3166", "ISO-3166 or ISO-3166-2 location codes"); - - public static final ConfigKey<String> USER = ConfigKeys.newStringConfigKey("user", - "user account for normal access to the remote machine, defaulting to local user", System.getProperty("user.name")); - - public static final ConfigKey<String> PASSWORD = ConfigKeys.newStringConfigKey("password", "password to use for ssh; note some images do not allow password-based ssh access"); - public static final ConfigKey<String> PUBLIC_KEY_FILE = ConfigKeys.newStringConfigKey("publicKeyFile", "ssh public key file to use; if blank will infer from privateKeyFile by appending \".pub\""); - public static final ConfigKey<String> PUBLIC_KEY_DATA = ConfigKeys.newStringConfigKey("publicKeyData", "ssh public key string to use (takes precedence over publicKeyFile)"); - public static final ConfigKey<String> PRIVATE_KEY_FILE = ConfigKeys.newStringConfigKey("privateKeyFile", "a '" + File.pathSeparator + "' separated list of ssh private key files; uses first in list that can be read", - Os.fromHome(".ssh/id_rsa") + File.pathSeparator + Os.fromHome(".ssh/id_dsa")); - public static final ConfigKey<String> PRIVATE_KEY_DATA = ConfigKeys.newStringConfigKey("privateKeyData", "ssh private key string to use (takes precedence over privateKeyFile)"); - public static final ConfigKey<String> PRIVATE_KEY_PASSPHRASE = ConfigKeys.newStringConfigKey("privateKeyPassphrase"); - - /** @deprecated since 0.6.0; included here so it gets picked up in auto-detect routines */ @Deprecated - public static final ConfigKey<String> LEGACY_PUBLIC_KEY_FILE = ConfigKeys.convert(PUBLIC_KEY_FILE, CaseFormat.LOWER_CAMEL, CaseFormat.LOWER_HYPHEN); - /** @deprecated since 0.6.0; included here so it gets picked up in auto-detect routines */ @Deprecated - public static final ConfigKey<String> LEGACY_PUBLIC_KEY_DATA = ConfigKeys.convert(PUBLIC_KEY_DATA, CaseFormat.LOWER_CAMEL, CaseFormat.LOWER_HYPHEN); - /** @deprecated since 0.6.0; included here so it gets picked up in auto-detect routines */ @Deprecated - public static final ConfigKey<String> LEGACY_PRIVATE_KEY_FILE = ConfigKeys.convert(PRIVATE_KEY_FILE, CaseFormat.LOWER_CAMEL, CaseFormat.LOWER_HYPHEN); - /** @deprecated since 0.6.0; included here so it gets picked up in auto-detect routines */ @Deprecated - public static final ConfigKey<String> LEGACY_PRIVATE_KEY_DATA = ConfigKeys.convert(PRIVATE_KEY_DATA, CaseFormat.LOWER_CAMEL, CaseFormat.LOWER_HYPHEN); - /** @deprecated since 0.6.0; included here so it gets picked up in auto-detect routines */ @Deprecated - public static final ConfigKey<String> LEGACY_PRIVATE_KEY_PASSPHRASE = ConfigKeys.convert(PRIVATE_KEY_PASSPHRASE, CaseFormat.LOWER_CAMEL, CaseFormat.LOWER_HYPHEN); - - public static final ConfigKey<Object> CALLER_CONTEXT = new BasicConfigKey<Object>(Object.class, "callerContext", - "An object whose toString is used for logging, to indicate wherefore a VM is being created"); - public static final ConfigKey<String> CLOUD_MACHINE_NAMER_CLASS = ConfigKeys.newStringConfigKey("cloudMachineNamer", "fully qualified class name of a class that extends CloudMachineNamer and has a single-parameter constructor that takes a ConfigBag"); - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/location/basic/LocationConfigUtils.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/location/basic/LocationConfigUtils.java b/core/src/main/java/brooklyn/location/basic/LocationConfigUtils.java deleted file mode 100644 index 9949947..0000000 --- a/core/src/main/java/brooklyn/location/basic/LocationConfigUtils.java +++ /dev/null @@ -1,559 +0,0 @@ -/* - * 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 brooklyn.location.basic; - -import static brooklyn.util.JavaGroovyEquivalents.groovyTruth; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.security.KeyPair; -import java.security.PublicKey; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.brooklyn.api.management.ManagementContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import brooklyn.config.ConfigKey; -import brooklyn.entity.basic.ConfigKeys; -import brooklyn.internal.BrooklynFeatureEnablement; -import brooklyn.location.cloud.CloudLocationConfig; -import brooklyn.util.ResourceUtils; -import brooklyn.util.collections.MutableMap; -import brooklyn.util.collections.MutableSet; -import brooklyn.util.config.ConfigBag; -import brooklyn.util.crypto.AuthorizedKeysParser; -import brooklyn.util.crypto.SecureKeys; -import brooklyn.util.crypto.SecureKeys.PassphraseProblem; -import brooklyn.util.exceptions.Exceptions; -import brooklyn.util.os.Os; -import brooklyn.util.text.StringFunctions; -import brooklyn.util.text.Strings; - -import com.google.common.annotations.Beta; -import com.google.common.base.Objects; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; - -public class LocationConfigUtils { - - private static final Logger log = LoggerFactory.getLogger(LocationConfigUtils.class); - - /** Creates an instance of {@link OsCredential} by inspecting {@link LocationConfigKeys#PASSWORD}; - * {@link LocationConfigKeys#PRIVATE_KEY_DATA} and {@link LocationConfigKeys#PRIVATE_KEY_FILE}; - * {@link LocationConfigKeys#PRIVATE_KEY_PASSPHRASE} if needed, and - * {@link LocationConfigKeys#PRIVATE_KEY_DATA} and {@link LocationConfigKeys#PRIVATE_KEY_FILE} - * (defaulting to the private key file + ".pub"). - **/ - public static OsCredential getOsCredential(ConfigBag config) { - return OsCredential.newInstance(config); - } - - /** Convenience class for holding private/public keys and passwords, inferring from config keys. - * See {@link LocationConfigUtils#getOsCredential(ConfigBag)}. */ - @Beta // would be nice to replace with a builder pattern - public static class OsCredential { - private final ConfigBag config; - private boolean preferPassword = false; - private boolean tryDefaultKeys = true; - private boolean requirePublicKey = true; - private boolean doKeyValidation = BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_VALIDATE_LOCATION_SSH_KEYS); - private boolean warnOnErrors = true; - private boolean throwOnErrors = false; - - private boolean dirty = true;; - - private String privateKeyData; - private String publicKeyData; - private String password; - - private OsCredential(ConfigBag config) { - this.config = config; - } - - /** throws if there are any problems */ - public OsCredential checkNotEmpty() { - checkNoErrors(); - - if (!hasKey() && !hasPassword()) { - if (warningMessages.size()>0) - throw new IllegalStateException("Could not find credentials: "+warningMessages); - else - throw new IllegalStateException("Could not find credentials"); - } - return this; - } - - /** throws if there were errors resolving (e.g. explicit keys, none of which were found/valid, or public key required and not found) - * @return */ - public OsCredential checkNoErrors() { - throwOnErrors(true); - dirty(); - infer(); - return this; - } - - public OsCredential logAnyWarnings() { - if (!warningMessages.isEmpty()) - log.warn("When reading credentials: "+warningMessages); - return this; - } - - public Set<String> getWarningMessages() { - return warningMessages; - } - - /** returns either the key or password or null; if both a key and a password this prefers the key unless otherwise set - * via {@link #preferPassword()} */ - public synchronized String getPreferredCredential() { - infer(); - - if (isUsingPassword()) return password; - if (hasKey()) return privateKeyData; - return null; - } - - /** if there is no credential (ignores public key) */ - public boolean isEmpty() { - return !hasKey() && !hasPassword(); - } - public boolean hasKey() { - infer(); - // key has stricter non-blank check than password - return Strings.isNonBlank(privateKeyData); - } - public boolean hasPassword() { - infer(); - // blank, even empty passwords are allowed - return password!=null; - } - /** if a password is available, and either this is preferred over a key or there is no key */ - public boolean isUsingPassword() { - return hasPassword() && (!hasKey() || preferPassword); - } - - public String getPrivateKeyData() { - infer(); - return privateKeyData; - } - public String getPublicKeyData() { - infer(); - return publicKeyData; - } - public String getPassword() { - infer(); - return password; - } - - /** if both key and password supplied, prefer the key; the default */ - public OsCredential preferKey() { preferPassword = false; return dirty(); } - /** if both key and password supplied, prefer the password; see {@link #preferKey()} */ - public OsCredential preferPassword() { preferPassword = true; return dirty(); } - - /** if false, do not mind if there is no public key corresponding to any private key; - * defaults to true; only applies if a private key is set */ - public OsCredential requirePublicKey(boolean requirePublicKey) { - this.requirePublicKey = requirePublicKey; - return dirty(); - } - /** whether to check the private/public keys and passphrase are coherent; default true */ - public OsCredential doKeyValidation(boolean doKeyValidation) { - this.doKeyValidation = doKeyValidation; - return dirty(); - } - /** if true (the default) this will look at default locations set on keys */ - public OsCredential useDefaultKeys(boolean tryDefaultKeys) { - this.tryDefaultKeys = tryDefaultKeys; - return dirty(); - } - /** whether to log warnings on problems */ - public OsCredential warnOnErrors(boolean warnOnErrors) { - this.warnOnErrors = warnOnErrors; - return dirty(); - } - /** whether to throw on problems */ - public OsCredential throwOnErrors(boolean throwOnErrors) { - this.throwOnErrors = throwOnErrors; - return dirty(); - } - - private OsCredential dirty() { dirty = true; return this; } - - public static OsCredential newInstance(ConfigBag config) { - return new OsCredential(config); - } - - private synchronized void infer() { - if (!dirty) return; - warningMessages.clear(); - - log.debug("Inferring OS credentials"); - privateKeyData = config.get(LocationConfigKeys.PRIVATE_KEY_DATA); - password = config.get(LocationConfigKeys.PASSWORD); - publicKeyData = getKeyDataFromDataKeyOrFileKey(config, LocationConfigKeys.PUBLIC_KEY_DATA, LocationConfigKeys.PUBLIC_KEY_FILE); - - KeyPair privateKey = null; - - if (Strings.isBlank(privateKeyData)) { - // look up private key files - String privateKeyFiles = null; - boolean privateKeyFilesExplicitlySet = config.containsKey(LocationConfigKeys.PRIVATE_KEY_FILE); - if (privateKeyFilesExplicitlySet || (tryDefaultKeys && password==null)) - privateKeyFiles = config.get(LocationConfigKeys.PRIVATE_KEY_FILE); - if (Strings.isNonBlank(privateKeyFiles)) { - Iterator<String> fi = Arrays.asList(privateKeyFiles.split(File.pathSeparator)).iterator(); - while (fi.hasNext()) { - String file = fi.next(); - if (Strings.isNonBlank(file)) { - try { - // real URL's won't actual work, due to use of path separator above - // not real important, but we get it for free if "files" is a list instead. - // using ResourceUtils is useful for classpath resources - if (file!=null) - privateKeyData = ResourceUtils.create().getResourceAsString(file); - // else use data already set - - privateKey = getValidatedPrivateKey(file); - - if (privateKeyData==null) { - // was cleared due to validation error - } else if (Strings.isNonBlank(publicKeyData)) { - log.debug("Loaded private key data from "+file+" (public key data explicitly set)"); - break; - } else { - String publicKeyFile = (file!=null ? file+".pub" : "(data)"); - try { - publicKeyData = ResourceUtils.create().getResourceAsString(publicKeyFile); - - log.debug("Loaded private key data from "+file+ - " and public key data from "+publicKeyFile); - break; - } catch (Exception e) { - Exceptions.propagateIfFatal(e); - log.debug("No public key file "+publicKeyFile+"; will try extracting from private key"); - publicKeyData = AuthorizedKeysParser.encodePublicKey(privateKey.getPublic()); - - if (publicKeyData==null) { - if (requirePublicKey) { - addWarning("Unable to find or extract public key for "+file, "skipping"); - } else { - log.debug("Loaded private key data from "+file+" (public key data not found but not required)"); - break; - } - } else { - log.debug("Loaded private key data from "+file+" (public key data extracted)"); - break; - } - privateKeyData = null; - } - } - - } catch (Exception e) { - Exceptions.propagateIfFatal(e); - String message = "Missing/invalid private key file "+file; - if (privateKeyFilesExplicitlySet) addWarning(message, (!fi.hasNext() ? "no more files to try" : "trying next file")+": "+e); - } - } - } - if (privateKeyFilesExplicitlySet && Strings.isBlank(privateKeyData)) - error("No valid private keys found", ""+warningMessages); - } - } else { - privateKey = getValidatedPrivateKey("(data)"); - } - - if (privateKeyData!=null) { - if (requirePublicKey && Strings.isBlank(publicKeyData)) { - if (privateKey!=null) { - publicKeyData = AuthorizedKeysParser.encodePublicKey(privateKey.getPublic()); - } - if (Strings.isBlank(publicKeyData)) { - error("If explicit "+LocationConfigKeys.PRIVATE_KEY_DATA.getName()+" is supplied, then " - + "the corresponding "+LocationConfigKeys.PUBLIC_KEY_DATA.getName()+" must also be supplied.", null); - } else { - log.debug("Public key data extracted"); - } - } - if (doKeyValidation && privateKey!=null && privateKey.getPublic()!=null && Strings.isNonBlank(publicKeyData)) { - PublicKey decoded = null; - try { - decoded = AuthorizedKeysParser.decodePublicKey(publicKeyData); - } catch (Exception e) { - Exceptions.propagateIfFatal(e); - addWarning("Invalid public key: "+decoded); - } - if (decoded!=null && !privateKey.getPublic().equals( decoded )) { - error("Public key inferred from does not match public key extracted from private key", null); - } - } - } - - log.debug("OS credential inference: "+this); - dirty = false; - } - - private KeyPair getValidatedPrivateKey(String label) { - KeyPair privateKey = null; - String passphrase = config.get(CloudLocationConfig.PRIVATE_KEY_PASSPHRASE); - try { - privateKey = SecureKeys.readPem(new ByteArrayInputStream(privateKeyData.getBytes()), passphrase); - if (passphrase!=null) { - // get the unencrypted key data for our internal use (jclouds requires this) - privateKeyData = SecureKeys.toPem(privateKey); - } - } catch (PassphraseProblem e) { - if (doKeyValidation) { - log.debug("Encountered error handling key "+label+": "+e, e); - if (Strings.isBlank(passphrase)) - addWarning("Passphrase required for key '"+label+"'"); - else - addWarning("Invalid passphrase for key '"+label+"'"); - privateKeyData = null; - } - } catch (Exception e) { - Exceptions.propagateIfFatal(e); - if (doKeyValidation) { - addWarning("Unable to parse private key from '"+label+"': unknown format"); - privateKeyData = null; - } - } - return privateKey; - } - - Set<String> warningMessages = MutableSet.of(); - - private void error(String msg, String logExtension) { - addWarning(msg); - if (warnOnErrors) log.warn(msg+(logExtension==null ? "" : ": "+logExtension)); - if (throwOnErrors) throw new IllegalStateException(msg+(logExtension==null ? "" : "; "+logExtension)); - } - - private void addWarning(String msg) { - addWarning(msg, null); - } - private void addWarning(String msg, String debugExtension) { - log.debug(msg+(debugExtension==null ? "" : "; "+debugExtension)); - warningMessages.add(msg); - } - - @Override - public String toString() { - return getClass().getSimpleName()+"["+ - (Strings.isNonBlank(publicKeyData) ? publicKeyData : "no-public-key")+";"+ - (Strings.isNonBlank(privateKeyData) ? "private-key-present" : "no-private-key")+","+ - (password!=null ? "password(len="+password.length()+")" : "no-password")+"]"; - } - } - - /** @deprecated since 0.7.0, use #getOsCredential(ConfigBag) */ @Deprecated - public static String getPrivateKeyData(ConfigBag config) { - return getKeyData(config, LocationConfigKeys.PRIVATE_KEY_DATA, LocationConfigKeys.PRIVATE_KEY_FILE); - } - - /** @deprecated since 0.7.0, use #getOsCredential(ConfigBag) */ @Deprecated - public static String getPublicKeyData(ConfigBag config) { - String data = getKeyData(config, LocationConfigKeys.PUBLIC_KEY_DATA, LocationConfigKeys.PUBLIC_KEY_FILE); - if (groovyTruth(data)) return data; - - String privateKeyFile = config.get(LocationConfigKeys.PRIVATE_KEY_FILE); - if (groovyTruth(privateKeyFile)) { - List<String> privateKeyFiles = Arrays.asList(privateKeyFile.split(File.pathSeparator)); - List<String> publicKeyFiles = ImmutableList.copyOf(Iterables.transform(privateKeyFiles, StringFunctions.append(".pub"))); - List<String> publicKeyFilesTidied = tidyFilePaths(publicKeyFiles); - - String fileData = getFileContents(publicKeyFilesTidied); - if (groovyTruth(fileData)) { - if (log.isDebugEnabled()) log.debug("Loaded "+LocationConfigKeys.PUBLIC_KEY_DATA.getName()+" from inferred files, based on "+LocationConfigKeys.PRIVATE_KEY_FILE.getName() + ": used " + publicKeyFilesTidied + " for "+config.getDescription()); - config.put(LocationConfigKeys.PUBLIC_KEY_DATA, fileData); - return fileData; - } else { - log.info("Not able to load "+LocationConfigKeys.PUBLIC_KEY_DATA.getName()+" from inferred files, based on "+LocationConfigKeys.PRIVATE_KEY_FILE.getName() + ": tried " + publicKeyFilesTidied + " for "+config.getDescription()); - } - } - - return null; - } - - /** @deprecated since 0.7.0, use #getOsCredential(ConfigBag) */ @Deprecated - public static String getKeyData(ConfigBag config, ConfigKey<String> dataKey, ConfigKey<String> fileKey) { - return getKeyDataFromDataKeyOrFileKey(config, dataKey, fileKey); - } - - private static String getKeyDataFromDataKeyOrFileKey(ConfigBag config, ConfigKey<String> dataKey, ConfigKey<String> fileKey) { - boolean unused = config.isUnused(dataKey); - String data = config.get(dataKey); - if (groovyTruth(data) && !unused) { - return data; - } - - String file = config.get(fileKey); - if (groovyTruth(file)) { - List<String> files = Arrays.asList(file.split(File.pathSeparator)); - List<String> filesTidied = tidyFilePaths(files); - String fileData = getFileContents(filesTidied); - if (fileData == null) { - log.warn("Invalid file" + (files.size() > 1 ? "s" : "") + " for " + fileKey + " (given " + files + - (files.equals(filesTidied) ? "" : "; converted to " + filesTidied) + ") " + - "may fail provisioning " + config.getDescription()); - } else if (groovyTruth(data)) { - if (!fileData.trim().equals(data.trim())) - log.warn(dataKey.getName()+" and "+fileKey.getName()+" both specified; preferring the former"); - } else { - data = fileData; - config.put(dataKey, data); - config.get(dataKey); - } - } - - return data; - } - - /** - * Reads the given file(s) in-order, returning the contents of the first file that can be read. - * Returns the file contents, or null if none of the files can be read. - * - * @param files list of file paths - */ - private static String getFileContents(Iterable<String> files) { - Iterator<String> fi = files.iterator(); - while (fi.hasNext()) { - String file = fi.next(); - if (groovyTruth(file)) { - try { - // see comment above - String result = ResourceUtils.create().getResourceAsString(file); - if (result!=null) return result; - log.debug("Invalid file "+file+" ; " + (!fi.hasNext() ? "no more files to try" : "trying next file")+" (null)"); - } catch (Exception e) { - Exceptions.propagateIfFatal(e); - log.debug("Invalid file "+file+" ; " + (!fi.hasNext() ? "no more files to try" : "trying next file"), e); - } - } - } - return null; - } - - private static List<String> tidyFilePaths(Iterable<String> files) { - List<String> result = Lists.newArrayList(); - for (String file : files) { - result.add(Os.tidyPath(file)); - } - return result; - } - - /** @deprecated since 0.6.0 use configBag.getWithDeprecation */ - @Deprecated - @SuppressWarnings("unchecked") - public static <T> T getConfigCheckingDeprecatedAlternatives(ConfigBag configBag, ConfigKey<T> preferredKey, - ConfigKey<?> ...deprecatedKeys) { - T value1 = (T) configBag.getWithDeprecation(preferredKey, deprecatedKeys); - T value2 = getConfigCheckingDeprecatedAlternativesInternal(configBag, preferredKey, deprecatedKeys); - if (!Objects.equal(value1, value2)) { - // points to a bug in one of the get-with-deprecation methods - log.warn("Deprecated getConfig with deprecated keys "+Arrays.toString(deprecatedKeys)+" gets different value with " + - "new strategy "+preferredKey+" ("+value1+") and old ("+value2+"); preferring old value for now, but this behaviour will change"); - return value2; - } - return value1; - } - - @SuppressWarnings("unchecked") - private static <T> T getConfigCheckingDeprecatedAlternativesInternal(ConfigBag configBag, ConfigKey<T> preferredKey, - ConfigKey<?> ...deprecatedKeys) { - ConfigKey<?> keyProvidingValue = null; - T value = null; - boolean found = false; - if (configBag.containsKey(preferredKey)) { - value = configBag.get(preferredKey); - found = true; - keyProvidingValue = preferredKey; - } - - for (ConfigKey<?> deprecatedKey: deprecatedKeys) { - T altValue = null; - boolean altFound = false; - if (configBag.containsKey(deprecatedKey)) { - altValue = (T) configBag.get(deprecatedKey); - altFound = true; - - if (altFound) { - if (found) { - if (Objects.equal(value, altValue)) { - // fine -- nothing - } else { - log.warn("Detected deprecated key "+deprecatedKey+" with value "+altValue+" used in addition to "+keyProvidingValue+" " + - "with value "+value+" for "+configBag.getDescription()+"; ignoring"); - configBag.remove(deprecatedKey); - } - } else { - log.warn("Detected deprecated key "+deprecatedKey+" with value "+altValue+" used instead of recommended "+preferredKey+"; " + - "promoting to preferred key status; will not be supported in future versions"); - configBag.put(preferredKey, altValue); - configBag.remove(deprecatedKey); - value = altValue; - found = true; - keyProvidingValue = deprecatedKey; - } - } - } - } - - if (found) { - return value; - } else { - return configBag.get(preferredKey); // get the default - } - } - - public static Map<ConfigKey<String>,String> finalAndOriginalSpecs(String finalSpec, Object ...sourcesForOriginalSpec) { - // yuck!: TODO should clean up how these things get passed around - Map<ConfigKey<String>,String> result = MutableMap.of(); - if (finalSpec!=null) - result.put(LocationInternal.FINAL_SPEC, finalSpec); - - String originalSpec = null; - for (Object source: sourcesForOriginalSpec) { - if (source instanceof CharSequence) originalSpec = source.toString(); - else if (source instanceof Map) { - if (originalSpec==null) originalSpec = Strings.toString( ((Map<?,?>)source).get(LocationInternal.ORIGINAL_SPEC) ); - if (originalSpec==null) originalSpec = Strings.toString( ((Map<?,?>)source).get(LocationInternal.ORIGINAL_SPEC.getName()) ); - } - if (originalSpec!=null) break; - } - if (originalSpec==null) originalSpec = finalSpec; - if (originalSpec!=null) - result.put(LocationInternal.ORIGINAL_SPEC, originalSpec); - - return result; - } - - public static boolean isEnabled(ManagementContext mgmt, String prefix) { - ConfigKey<Boolean> key = ConfigKeys.newConfigKeyWithPrefix(prefix+".", LocationConfigKeys.ENABLED); - Boolean enabled = mgmt.getConfig().getConfig(key); - if (enabled!=null) return enabled.booleanValue(); - return true; - } - - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/location/basic/LocationDynamicType.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/location/basic/LocationDynamicType.java b/core/src/main/java/brooklyn/location/basic/LocationDynamicType.java deleted file mode 100644 index cc0b304..0000000 --- a/core/src/main/java/brooklyn/location/basic/LocationDynamicType.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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 brooklyn.location.basic; - -import brooklyn.basic.BrooklynDynamicType; -import brooklyn.location.Location; -import brooklyn.location.LocationType; - -public class LocationDynamicType extends BrooklynDynamicType<Location, AbstractLocation> { - - public LocationDynamicType(AbstractLocation location) { - super(location); - } - - public LocationType getSnapshot() { - return (LocationType) super.getSnapshot(); - } - - @Override - protected LocationTypeSnapshot newSnapshot() { - return new LocationTypeSnapshot(name, value(configKeys)); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/core/src/main/java/brooklyn/location/basic/LocationInternal.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/location/basic/LocationInternal.java b/core/src/main/java/brooklyn/location/basic/LocationInternal.java deleted file mode 100644 index e846cd3..0000000 --- a/core/src/main/java/brooklyn/location/basic/LocationInternal.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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 brooklyn.location.basic; - -import java.util.Map; - -import org.apache.brooklyn.api.entity.rebind.RebindSupport; -import org.apache.brooklyn.api.management.ManagementContext; -import org.apache.brooklyn.mementos.LocationMemento; - -import brooklyn.basic.BrooklynObjectInternal; -import brooklyn.config.ConfigInheritance; -import brooklyn.config.ConfigKey; -import brooklyn.entity.basic.ConfigKeys; -import brooklyn.location.Location; -import brooklyn.util.config.ConfigBag; - -import com.google.common.annotations.Beta; - -/** - * Information about locations private to Brooklyn. - */ -public interface LocationInternal extends BrooklynObjectInternal, Location { - - @Beta - public static final ConfigKey<String> ORIGINAL_SPEC = ConfigKeys.newStringConfigKey("spec.original", "The original spec used to instantiate a location"); - @Beta - public static final ConfigKey<String> FINAL_SPEC = ConfigKeys.newStringConfigKey("spec.final", "The actual spec (in a chain) which instantiates a location"); - @Beta - public static final ConfigKey<String> NAMED_SPEC_NAME = ConfigKeys.newStringConfigKey("spec.named.name", "The name on the (first) named spec in a chain"); - - /** - * Registers the given extension for the given type. If an extension already existed for - * this type, then this will override it. - * - * @throws NullPointerException if extensionType or extension are null - * @throws IllegalArgumentException if extension does not implement extensionType - */ - <T> void addExtension(Class<T> extensionType, T extension); - - /** - * Get a record of the metadata of this location. - * <p/> - * <p>Metadata records are used to record an audit trail of events relating to location usage - * (for billing purposes, for example). Implementations (and subclasses) should override this - * method to return information useful for this purpose.</p> - * - * @return - */ - public Map<String, String> toMetadataRecord(); - - /** - * @deprecated since 0.7.0; use {@link #config()}, such as {@code ((LocationInternal)location).config().getLocalBag()} - */ - @Deprecated - ConfigBag getLocalConfigBag(); - - /** - * Returns all config, including that inherited from parents. - * - * This method does not respect {@link ConfigInheritance} and so usage is discouraged. - * - * @deprecated since 0.7.0; use {@link #config()}, such as {@code ((LocationInternal)location).config().getBag()} - */ - @Deprecated - ConfigBag getAllConfigBag(); - - /** - * Users are strongly discouraged from calling or overriding this method. - * It is for internal calls only, relating to persisting/rebinding entities. - * This method may change (or be removed) in a future release without notice. - */ - @Override - @Beta - RebindSupport<LocationMemento> getRebindSupport(); - - ManagementContext getManagementContext(); -}
