You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2024/07/19 20:59:51 UTC
(brooklyn-server) 02/02: byon locations can be dynamic
This is an automated email from the ASF dual-hosted git repository.
heneveld pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git
commit 1006bff329d66683f503f347f248be5ec065dcfb
Author: Alex Heneveld <gi...@alex.heneveld.org>
AuthorDate: Fri Jul 19 15:43:40 2024 +0100
byon locations can be dynamic
---
.../camp/brooklyn/ByonLocationsYamlTest.java | 35 ++++++++++-
.../location/byon/ByonLocationResolver.java | 10 ++--
.../byon/FixedListMachineProvisioningLocation.java | 67 ++++++++++++++++------
3 files changed, 90 insertions(+), 22 deletions(-)
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ByonLocationsYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ByonLocationsYamlTest.java
index 6cab0ebb06..e76712b158 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ByonLocationsYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/ByonLocationsYamlTest.java
@@ -28,13 +28,16 @@ import java.util.Set;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.api.mgmt.Task;
import org.apache.brooklyn.core.config.ConfigKeys;
import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.trait.Startable;
import org.apache.brooklyn.core.location.LocationPredicates;
import org.apache.brooklyn.core.location.Machines;
import org.apache.brooklyn.core.location.access.PortForwardManager;
import org.apache.brooklyn.core.location.access.PortForwardManagerLocationResolver;
import org.apache.brooklyn.core.location.cloud.CloudLocationConfig;
+import org.apache.brooklyn.core.sensor.Sensors;
import org.apache.brooklyn.entity.software.base.DoNothingSoftwareProcess;
import org.apache.brooklyn.location.byon.FixedListMachineProvisioningLocation;
import org.apache.brooklyn.location.ssh.SshMachineLocation;
@@ -42,6 +45,8 @@ import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
import org.apache.brooklyn.test.Asserts;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.net.UserAndHostAndPort;
+import org.apache.brooklyn.util.time.Duration;
+import org.apache.brooklyn.util.time.Time;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.Test;
@@ -121,6 +126,34 @@ public class ByonLocationsYamlTest extends AbstractYamlTest {
assertMachine(machine, UserAndHostAndPort.fromParts(machine.getUser(), "1.2.3.4", 22), Collections.emptyMap());
}
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testByonMachineResolvesDynamicDependentConfigForHost() throws Exception {
+ String yaml = Joiner.on("\n").join(
+ "location:",
+ " byon:",
+ " hosts:",
+ " - $brooklyn:attributeWhenReady(\"ip_address\")",
+ "services:",
+ "- type: org.apache.brooklyn.entity.software.base.DoNothingSoftwareProcess"
+ );
+
+ Entity app = createApplicationUnstarted(yaml);
+ Task<Void> start = app.invoke(Startable.START, null);
+ Time.sleep(Duration.millis(100));
+ Asserts.assertFalse(start.isDone());
+
+ Iterables.getOnlyElement(app.getChildren()).sensors().set(Sensors.newStringSensor("ip_address"), "1.2.3.4");
+ start.getUnchecked();
+ start.getUnchecked(Duration.seconds(5));
+
+ FixedListMachineProvisioningLocation<SshMachineLocation> loc = (FixedListMachineProvisioningLocation<SshMachineLocation>) Iterables.get(app.getLocations(), 0);
+
+ Set<SshMachineLocation> machines = loc.getAllMachines();
+ SshMachineLocation machine = Iterables.getOnlyElement(machines);
+ assertMachine(machine, UserAndHostAndPort.fromParts(machine.getUser(), "1.2.3.4", 22), Collections.emptyMap());
+ }
+
@Test
@SuppressWarnings("unchecked")
public void testByonMachineResolvesDependentConfigForHosts() throws Exception {
@@ -357,7 +390,7 @@ public class ByonLocationsYamlTest extends AbstractYamlTest {
Entity app = createStartWaitAndLogApplication(yaml);
Asserts.shouldHaveFailedPreviously("app="+app);
} catch (Exception e) {
- Asserts.expectedFailureContains(e, "Invalid location", "byon", "at least one host must be defined");
+ Asserts.expectedFailureContains(e, "Invalid location", "byon", "hosts must be defined");
}
}
diff --git a/core/src/main/java/org/apache/brooklyn/location/byon/ByonLocationResolver.java b/core/src/main/java/org/apache/brooklyn/location/byon/ByonLocationResolver.java
index 26d42fd0a6..f219434c32 100644
--- a/core/src/main/java/org/apache/brooklyn/location/byon/ByonLocationResolver.java
+++ b/core/src/main/java/org/apache/brooklyn/location/byon/ByonLocationResolver.java
@@ -152,9 +152,11 @@ public class ByonLocationResolver extends AbstractLocationResolver {
return TypeCoercions.coerce(v, type);
}
protected <T> T resolveRemoveOrThrow(boolean dynamicAllowed, Map<String, Object> map, String key, Class<T> type) {
- Object v = map.remove(key);
+ Object v = map.get(key);
v = resolveOrThrow(dynamicAllowed, v);
- return TypeCoercions.coerce(v, type);
+ T result = TypeCoercions.coerce(v, type);
+ map.remove(key);
+ return result;
}
protected Object resolveOrThrow(boolean dynamicAllowed, Object v) {
if (v instanceof DeferredSupplier) {
@@ -171,7 +173,6 @@ public class ByonLocationResolver extends AbstractLocationResolver {
Class<? extends MachineLocation> locationClass;
MutableMap<String, Object> defaultProps = MutableMap.of();
- config.remove("hosts");
String user = resolveOrThrow(dynamicAllowed, "user", String.class);
Integer port = resolveOrThrow(dynamicAllowed, "port", Integer.class);
resolveOrThrow(dynamicAllowed, OS_FAMILY.getName(), Object.class);
@@ -192,7 +193,7 @@ public class ByonLocationResolver extends AbstractLocationResolver {
} else if (hosts instanceof Iterable) {
hostAddresses = ImmutableList.copyOf((Iterable<?>) hosts);
} else {
- throw new IllegalArgumentException("Invalid location '" + spec + "'; at least one host must be defined");
+ throw new IllegalArgumentException("Invalid location '" + spec + "'; hosts must be defined, as a string of a single host or list of hosts");
}
if (hostAddresses.isEmpty()) {
throw new IllegalArgumentException("Invalid location '" + spec + "'; at least one host must be defined");
@@ -213,6 +214,7 @@ public class ByonLocationResolver extends AbstractLocationResolver {
machineSpec.configureIfNotNull(LocalLocationManager.CREATE_UNMANAGED, config.get(LocalLocationManager.CREATE_UNMANAGED));
machineSpecs.add(machineSpec);
}
+ config.remove("hosts");
return machineSpecs;
}
diff --git a/core/src/main/java/org/apache/brooklyn/location/byon/FixedListMachineProvisioningLocation.java b/core/src/main/java/org/apache/brooklyn/location/byon/FixedListMachineProvisioningLocation.java
index 168bd3078d..3301678716 100644
--- a/core/src/main/java/org/apache/brooklyn/location/byon/FixedListMachineProvisioningLocation.java
+++ b/core/src/main/java/org/apache/brooklyn/location/byon/FixedListMachineProvisioningLocation.java
@@ -46,6 +46,8 @@ import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.collections.MutableSet;
import org.apache.brooklyn.util.core.config.ConfigBag;
import org.apache.brooklyn.util.core.flags.SetFromFlag;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.stream.Streams;
import org.apache.brooklyn.util.text.WildcardGlobs;
import org.apache.brooklyn.util.text.WildcardGlobs.PhraseTreatment;
@@ -158,17 +160,9 @@ implements MachineProvisioningLocation<T>, Closeable {
@Override
public void init() {
super.init();
-
- List<LocationSpec<? extends MachineLocation>> machineSpecs = getConfig(MACHINE_SPECS);
- if (machineSpecs != null) {
- for (LocationSpec<? extends MachineLocation> spec : machineSpecs) {
- @SuppressWarnings("unchecked")
- T machine = (T) getManagementContext().getLocationManager().createLocation(spec);
- machines.add(machine);
- }
- }
- config().set(MACHINE_SPECS, (List<LocationSpec<? extends MachineLocation>>) null);
-
+
+ attemptResolveMachineSpecs(false);
+
Supplier<? extends List<? extends MachineLocation>> initialMachinesFactory = getConfig(INITIAL_MACHINES_FACTORY);
if (initialMachinesFactory != null) {
List<? extends MachineLocation> initialMachines = initialMachinesFactory.get();
@@ -181,7 +175,11 @@ implements MachineProvisioningLocation<T>, Closeable {
}
}
config().set(INITIAL_MACHINES_FACTORY, (Supplier<List<? extends MachineLocation>>) null);
-
+
+ ensureMachinesInitialized();
+ }
+
+ private void ensureMachinesInitialized() {
Set<T> machinesCopy = MutableSet.of();
for (T location : machines) {
if (location==null) {
@@ -198,7 +196,34 @@ implements MachineProvisioningLocation<T>, Closeable {
machines = machinesCopy;
}
}
-
+
+ transient Exception dynamicMachineSpecsError;
+
+ private void attemptResolveMachineSpecs(boolean ensureMachinesInitialized) {
+ Maybe<Object> machineSpecsRaw = config().getRaw(MACHINE_SPECS);
+ if (machineSpecsRaw.isAbsent()) return;
+ List<LocationSpec<? extends MachineLocation>> machineSpecs = null;
+ try {
+ machineSpecs = config().get(MACHINE_SPECS);
+ } catch (Exception e) {
+ // don't treat interrupted as severe:
+ // Exceptions.propagateIfFatal(e);
+ log.debug("Machine specs for "+this+" are not resolvable at this time. Try again later. ("+e+")");
+ dynamicMachineSpecsError = e;
+ return;
+ }
+ dynamicMachineSpecsError = null;
+ if (machineSpecs != null) {
+ for (LocationSpec<? extends MachineLocation> spec : machineSpecs) {
+ @SuppressWarnings("unchecked")
+ T machine = (T) getManagementContext().getLocationManager().createLocation(spec);
+ machines.add(machine);
+ }
+ }
+ config().set(MACHINE_SPECS, (List<LocationSpec<? extends MachineLocation>>) null);
+ if (ensureMachinesInitialized) ensureMachinesInitialized();
+ }
+
@Override
public String toVerboseString() {
return MoreObjects.toStringHelper(this).omitNullValues()
@@ -267,7 +292,7 @@ implements MachineProvisioningLocation<T>, Closeable {
}
public Set<T> getAvailable() {
- Set<T> a = Sets.newLinkedHashSet(machines);
+ Set<T> a = Sets.newLinkedHashSet(getMachines());
a.removeAll(inUse);
return a;
}
@@ -277,7 +302,7 @@ implements MachineProvisioningLocation<T>, Closeable {
}
public Set<T> getAllMachines() {
- return ImmutableSet.copyOf(machines);
+ return ImmutableSet.copyOf(getMachines());
}
@Override
@@ -322,12 +347,20 @@ implements MachineProvisioningLocation<T>, Closeable {
synchronized (lock) {
Set<T> a = getAvailable();
if (a.isEmpty()) {
+ if (dynamicMachineSpecsError!=null) {
+ attemptResolveMachineSpecs(true);
+ a = getAvailable();
+ }
if (canProvisionMore()) {
provisionMore(1, allflags.getAllConfig());
a = getAvailable();
}
- if (a.isEmpty())
- throw new NoMachinesAvailableException("No machines available in "+toString());
+ if (a.isEmpty()) {
+ if (dynamicMachineSpecsError!=null) {
+ throw new NoMachinesAvailableException("Machines cannot be resolved at this time in " + toString()+": "+dynamicMachineSpecsError, dynamicMachineSpecsError);
+ }
+ throw new NoMachinesAvailableException("No machines available in " + toString());
+ }
}
if (desiredMachine != null) {
if (a.contains(desiredMachine)) {