Java Code Examples for org.apache.brooklyn.api.entity.Entity#getAttribute()

The following examples show how to use org.apache.brooklyn.api.entity.Entity#getAttribute() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: SensorResource.java    From brooklyn-server with Apache License 2.0 6 votes vote down vote up
protected Object get(boolean preferJson, String application, String entityToken, String sensorName, Boolean raw) {
    final Entity entity = brooklyn().getEntity(application, entityToken);
    AttributeSensor<?> sensor = findSensor(entity, sensorName);
    
    if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_ENTITY, entity)) {
        throw WebResourceUtils.forbidden("User '%s' is not authorized to see entity '%s'",
                Entitlements.getEntitlementContext().user(), entity);
    }
    if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_SENSOR, new EntityAndItem<String>(entity, sensor.getName()))) {
        throw WebResourceUtils.forbidden("User '%s' is not authorized to see entity '%s' sensor '%s'",
                Entitlements.getEntitlementContext().user(), entity, sensor.getName());
    }
    
    Object value = entity.getAttribute(sensor);
    return resolving(value).preferJson(preferJson).asJerseyOutermostReturnValue(true).raw(raw).context(entity).immediately(true).renderAs(sensor).resolve();
}
 
Example 2
Source File: AbstractNonProvisionedControllerImpl.java    From brooklyn-library with Apache License 2.0 6 votes vote down vote up
protected String getAddressOfEntity(Entity member) {
    AttributeSensor<String> hostAndPortSensor = getHostAndPortSensor();
    if (hostAndPortSensor != null) {
        String result = member.getAttribute(hostAndPortSensor);
        if (result != null) {
            return result;
        } else {
            LOG.error("No host:port set for {} (using attribute {}); skipping in {}", 
                    new Object[] {member, hostAndPortSensor, this});
            return null;
        }
    } else {
        String ip = member.getAttribute(getHostnameSensor());
        Integer port = member.getAttribute(getPortNumberSensor());
        if (ip!=null && port!=null) {
            return ip+":"+port;
        }
        LOG.error("Unable to construct hostname:port representation for {} ({}:{}); skipping in {}", 
                new Object[] {member, ip, port, this});
        return null;
    }
}
 
Example 3
Source File: SensorResource.java    From brooklyn-server with Apache License 2.0 6 votes vote down vote up
@Override
public Map<String, Object> batchSensorRead(final String application, final String entityToken, final Boolean raw) {
    final Entity entity = brooklyn().getEntity(application, entityToken);
    if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_ENTITY, entity)) {
        throw WebResourceUtils.forbidden("User '%s' is not authorized to see entity '%s'",
                Entitlements.getEntitlementContext().user(), entity);
    }

    Map<String, Object> sensorMap = Maps.newHashMap();
    @SuppressWarnings("rawtypes")
    Iterable<AttributeSensor> sensors = filter(entity.getEntityType().getSensors(), AttributeSensor.class);

    for (AttributeSensor<?> sensor : sensors) {
        // Exclude sensors that user is not allowed to see
        if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_SENSOR, new EntityAndItem<String>(entity, sensor.getName()))) {
            log.trace("User {} not authorized to see sensor {} of entity {}; excluding from current-state results", 
                    new Object[] {Entitlements.getEntitlementContext().user(), sensor.getName(), entity});
            continue;
        }

        Object value = entity.getAttribute(findSensor(entity, sensor.getName()));
        sensorMap.put(sensor.getName(), 
            resolving(value).preferJson(true).asJerseyOutermostReturnValue(false).raw(raw).context(entity).timeout(Duration.ZERO).renderAs(sensor).resolve());
    }
    return sensorMap;
}
 
Example 4
Source File: Machines.java    From brooklyn-server with Apache License 2.0 6 votes vote down vote up
public static Maybe<String> findSubnetOrPublicHostname(Entity entity) {
    String hn = entity.getAttribute(Attributes.HOSTNAME);
    if (hn!=null) {
        // attributes already set, see if there was a SUBNET_HOSTNAME set
        // note we rely on (public) hostname being set _after_ subnet_hostname,
        // to prevent tiny possibility of races resulting in hostname being returned
        // becasue subnet is still being looked up -- see MachineLifecycleEffectorTasks
        Maybe<String> sn = findSubnetHostname(entity);
        if (sn.isPresent()) return sn;
        // short-circuit discovery if attributes have been set already
        return Maybe.of(hn);
    }
    
    Maybe<MachineLocation> l = findUniqueMachineLocation(entity.getLocations());
    if (!l.isPresent()) return Maybe.absent();
    InetAddress addr = l.get().getAddress();
    if (addr==null) return Maybe.absent();
    return Maybe.fromNullable(addr.getHostName());
}
 
Example 5
Source File: ServerPoolImpl.java    From brooklyn-server with Apache License 2.0 5 votes vote down vote up
private void updateCountSensors() {
    synchronized (mutex) {
        int available = 0, claimed = 0;
        for (Entity member : getMembers()) {
            MachinePoolMemberStatus status = member.getAttribute(SERVER_STATUS);
            if (MachinePoolMemberStatus.AVAILABLE.equals(status)) {
                available++;
            } else if (MachinePoolMemberStatus.CLAIMED.equals(status)) {
                claimed++;
            }
        }
        sensors().set(AVAILABLE_COUNT, available);
        sensors().set(CLAIMED_COUNT, claimed);
    }
}
 
Example 6
Source File: BindDnsServerImpl.java    From brooklyn-library with Apache License 2.0 5 votes vote down vote up
@Override
public boolean apply(Entity input) {
    switch (input.getAttribute(Attributes.SERVICE_STATE_ACTUAL)) {
    case STOPPED:
    case STOPPING:
    case DESTROYED:
        return false;
    default:
        return input.getAttribute(getConfig(HOSTNAME_SENSOR)) != null;
    }
}
 
Example 7
Source File: ElasticSearchClusterIntegrationTest.java    From brooklyn-library with Apache License 2.0 5 votes vote down vote up
private int clusterDocumentCount() {
    int result = 0;
    for (Entity entity : elasticSearchCluster.getMembers()) {
        result += entity.getAttribute(ElasticSearchNode.DOCUMENT_COUNT);
    }
    return result;
}
 
Example 8
Source File: CassandraDatacenterImpl.java    From brooklyn-library with Apache License 2.0 5 votes vote down vote up
public boolean isRunningSeed(Entity member) {
    boolean viableSeed = isViableSeed(member);
    boolean serviceUp = Boolean.TRUE.equals(member.getAttribute(Attributes.SERVICE_UP));
    Lifecycle serviceState = member.getAttribute(Attributes.SERVICE_STATE_ACTUAL);
    boolean result = viableSeed && serviceUp && serviceState == Lifecycle.RUNNING;
    if (log.isTraceEnabled()) log.trace("Node {} in Cluster {}: runningSeed={}; viableSeed={}; serviceUp={}; serviceState={}", new Object[] {member, this, result, viableSeed, serviceUp, serviceState});
    return result;
}
 
Example 9
Source File: ApplicationResource.java    From brooklyn-server with Apache License 2.0 5 votes vote down vote up
public static Map<String, Object> getSensorMap(String sensor, Iterable<Entity> descs) {
    if (Iterables.isEmpty(descs))
        return Collections.emptyMap();
    Map<String, Object> result = MutableMap.of();
    Iterator<Entity> di = descs.iterator();
    Sensor<?> s = null;
    while (di.hasNext()) {
        Entity potentialSource = di.next();
        s = potentialSource.getEntityType().getSensor(sensor);
        if (s!=null) break;
    }
    if (s==null)
        s = Sensors.newSensor(Object.class, sensor);
    if (!(s instanceof AttributeSensor<?>)) {
        log.warn("Cannot retrieve non-attribute sensor "+s+" for entities; returning empty map");
        return result;
    }
    for (Entity e: descs) {
        Object v = null;
        try {
            v = e.getAttribute((AttributeSensor<?>)s);
        } catch (Exception exc) {
            Exceptions.propagateIfFatal(exc);
            log.warn("Error retrieving sensor "+s+" for "+e+" (ignoring): "+exc);
        }
        if (v!=null)
            result.put(e.getId(), v);
    }
    return result;
}
 
Example 10
Source File: CassandraFabricImpl.java    From brooklyn-library with Apache License 2.0 5 votes vote down vote up
public boolean isViableSeed(Entity member) {
    // TODO remove duplication from CassandraClusterImpl.SeedTracker.isViableSeed
    boolean managed = Entities.isManaged(member);
    String hostname = member.getAttribute(Attributes.HOSTNAME);
    boolean serviceUp = Boolean.TRUE.equals(member.getAttribute(Attributes.SERVICE_UP));
    Lifecycle serviceState = member.getAttribute(Attributes.SERVICE_STATE_ACTUAL);
    boolean hasFailed = !managed || (serviceState == Lifecycle.ON_FIRE) || (serviceState == Lifecycle.RUNNING && !serviceUp) || (serviceState == Lifecycle.STOPPED);
    boolean result = (hostname != null && !hasFailed);
    if (log.isTraceEnabled()) log.trace("Node {} in Fabric {}: viableSeed={}; hostname={}; serviceUp={}; serviceState={}; hasFailed={}", new Object[] {member, CassandraFabricImpl.this, result, hostname, serviceUp, serviceState, hasFailed});
    return result;
}
 
Example 11
Source File: AbstractMultipleSensorAggregator.java    From brooklyn-server with Apache License 2.0 5 votes vote down vote up
@Override
protected void onProducerAdded(Entity producer) {
    BrooklynLogging.log(LOG, BrooklynLogging.levelDebugOrTraceIfReadOnly(producer),
        "{} listening to {}", this, producer);
    synchronized (values) {
        for (Sensor<?> sensor: getSourceSensors()) {
            Map<Entity,Object> vs = values.get(sensor.getName());
            if (vs==null) {
                vs = new LinkedHashMap<Entity,Object>();
                values.put(sensor.getName(), vs);
            }

            Object vo = vs.get(producer);
            if (vo==null) {
                Object initialVal;
                if (sensor instanceof AttributeSensor) {
                    initialVal = producer.getAttribute((AttributeSensor<?>)sensor);
                } else {
                    initialVal = null;
                }
                vs.put(producer, initialVal != null ? initialVal : defaultMemberValue);
                // there may be sensor events older than initialVal because this is run in 
                // the _parents_ synched subscription block.  we live with this for now,
                // as those sensor events will catch up, but val here might see
                // second -> first -> second on child publishing second -> first .
                // could resolve by running this init in the subscription manager thread;
                // but it's not necessary yet; see Aggregator#onProducerAdded and
                // ApplicationLifecycleStateTest#testSensorInitAndPublishOrder
            }
        }
    }
}
 
Example 12
Source File: Machines.java    From brooklyn-server with Apache License 2.0 5 votes vote down vote up
public static Maybe<String> findSubnetOrPrivateIp(Entity entity) {
    // see comments in findSubnetOrPrivateHostname
    String hn = entity.getAttribute(Attributes.ADDRESS);
    if (hn!=null) {
        Maybe<String> sn = findSubnetIp(entity);
        if (sn.isPresent()) return sn;
        return Maybe.of(hn);
    }
    
    Maybe<MachineLocation> l = findUniqueMachineLocation(entity.getLocations());
    if (!l.isPresent()) return Maybe.absent();
    InetAddress addr = l.get().getAddress();
    if (addr==null) return Maybe.absent();
    return Maybe.fromNullable(addr.getHostAddress());
}
 
Example 13
Source File: Machines.java    From brooklyn-server with Apache License 2.0 4 votes vote down vote up
public static Maybe<String> findSubnetHostname(Entity entity) {
    String sh = entity.getAttribute(Attributes.SUBNET_HOSTNAME);
    if (sh!=null) return Maybe.of(sh);
    return findSubnetHostname(entity.getLocations());
}
 
Example 14
Source File: Machines.java    From brooklyn-server with Apache License 2.0 4 votes vote down vote up
public static Maybe<String> findSubnetIp(Entity entity) {
    String sh = entity.getAttribute(Attributes.SUBNET_ADDRESS);
    if (sh!=null) return Maybe.of(sh);
    return findSubnetIp(entity.getLocations());
}
 
Example 15
Source File: RiakClusterImpl.java    From brooklyn-library with Apache License 2.0 4 votes vote down vote up
private String getRiakName(Entity node) {
    return node.getAttribute(RiakNode.RIAK_NODE_NAME);
}
 
Example 16
Source File: BindDnsServerImpl.java    From brooklyn-library with Apache License 2.0 4 votes vote down vote up
public void update() {
    Lifecycle serverState = getAttribute(Attributes.SERVICE_STATE_ACTUAL);
    if (Lifecycle.STOPPED.equals(serverState) || Lifecycle.STOPPING.equals(serverState)
            || Lifecycle.DESTROYED.equals(serverState) || !getAttribute(Attributes.SERVICE_UP)) {
        LOG.debug("Skipped update of {} when service state is {} and running is {}",
                new Object[]{this, getAttribute(Attributes.SERVICE_STATE_ACTUAL), getAttribute(SERVICE_UP)});
        return;
    }
    synchronized (this) {
        Iterable<Entity> availableEntities = FluentIterable.from(getEntities().getMembers())
                .filter(new HasHostnameAndValidLifecycle());
        LOG.debug("{} updating with entities: {}", this, Iterables.toString(availableEntities));
        ImmutableListMultimap<String, Entity> hostnameToEntity = Multimaps.index(availableEntities,
                new HostnameTransformer());

        Map<String, String> octetToName = Maps.newHashMap();
        BiMap<String, String> ipToARecord = HashBiMap.create();
        Multimap<String, String> aRecordToCnames = MultimapBuilder.hashKeys().hashSetValues().build();
        Multimap<String, String> ipToAllNames = MultimapBuilder.hashKeys().hashSetValues().build();

        for (Map.Entry<String, Entity> entry : hostnameToEntity.entries()) {
            String domainName = entry.getKey();
            Entity entity = entry.getValue();
            
            String address = null;
            
            AttributeSensor<String> addressSensor = getConfig(ADDRESS_SENSOR);
            if (addressSensor!=null) {
                address = entity.getAttribute(addressSensor);
                
            } else {
                if (!hasLoggedDeprecationAboutAddressSensor) {
                    LOG.warn("BIND entity "+this+" is using legacy machine inspection to determine IP address; set the "+ADDRESS_SENSOR.getName()+" config to ensure compatibility with future versions");
                    hasLoggedDeprecationAboutAddressSensor = true;
                }
                Maybe<SshMachineLocation> location = Machines.findUniqueMachineLocation(entity.getLocations(), SshMachineLocation.class);
                if (!location.isPresent()) {
                    LOG.debug("Member {} of {} does not have an hostname so will not be configured", entity, this);
                } else if (ipToARecord.inverse().containsKey(domainName)) {
                    // already has a hostname, ignore (could log if domain is different?)
                } else {
                    address = location.get().getAddress().getHostAddress();
                }
            }
            
            if (Strings.isBlank(address)) {
                continue;
            }
            
            ipToAllNames.put(address, domainName);
            if (!ipToARecord.containsKey(address)) {
                ipToARecord.put(address, domainName);
                if (getReverseLookupNetwork().contains(new Cidr(address + "/32"))) {
                    String octet = Iterables.get(Splitter.on('.').split(address), 3);
                    if (!octetToName.containsKey(octet)) octetToName.put(octet, domainName);
                }
            } else {
                aRecordToCnames.put(ipToARecord.get(address), domainName);
            }
        }
        sensors().set(A_RECORDS, ImmutableMap.copyOf(ipToARecord.inverse()));
        sensors().set(PTR_RECORDS, ImmutableMap.copyOf(octetToName));
        sensors().set(CNAME_RECORDS, Multimaps.unmodifiableMultimap(aRecordToCnames));
        sensors().set(ADDRESS_MAPPINGS, Multimaps.unmodifiableMultimap(ipToAllNames));

        // Update Bind configuration files and restart the service
        getDriver().updateBindConfiguration();
   }
}
 
Example 17
Source File: ApplicationResource.java    From brooklyn-server with Apache License 2.0 4 votes vote down vote up
/** depth 0 means no detail even at root; negative means infinite; positive means include details for that many levels 
 * (ie 1 means this entity but no details of descendants) */
private EntitySummary fromEntity(Entity entity, boolean includeTags, int detailDepth, List<String> extraSensorGlobs, List<String> extraConfigGlobs) {
    if (detailDepth==0) {
        return new EntitySummary(
            entity.getId(), 
            entity.getDisplayName(),
            entity.getEntityType().getName(),
            entity.getCatalogItemId(),
            MutableMap.of("self", EntityTransformer.entityUri(entity, ui.getBaseUriBuilder())) );
    }

    Boolean serviceUp = entity.getAttribute(Attributes.SERVICE_UP);

    Lifecycle serviceState = entity.getAttribute(Attributes.SERVICE_STATE_ACTUAL);

    String iconUrl = RegisteredTypes.getIconUrl(entity);
    if (iconUrl!=null) {
        if (brooklyn().isUrlServerSideAndSafe(iconUrl))
            // route to server if it is a server-side url
            iconUrl = EntityTransformer.entityUri(entity, ui.getBaseUriBuilder())+"/icon";
    }

    List<EntitySummary> children = Lists.newArrayList();
    if (!entity.getChildren().isEmpty()) {
        for (Entity child : entity.getChildren()) {
            if (Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_ENTITY, child)) {
                children.add(fromEntity(child, includeTags, detailDepth-1, extraSensorGlobs, extraConfigGlobs));
            }
        }
    }

    String parentId = null;
    if (entity.getParent()!= null) {
        parentId = entity.getParent().getId();
    }

    List<String> groupIds = Lists.newArrayList();
    if (!entity.groups().isEmpty()) {
        groupIds.addAll(entitiesIdAsArray(entity.groups()));
    }

    List<Map<String, String>> members = Lists.newArrayList();
    if (entity instanceof Group) {
        // use attribute instead of method in case it is read-only
        Collection<Entity> memberEntities = entity.getAttribute(AbstractGroup.GROUP_MEMBERS);
        if (memberEntities != null && !memberEntities.isEmpty())
            members.addAll(entitiesIdAndNameAsList(memberEntities));
    }

    EntityDetail result = new EntityDetail(
            entity.getApplicationId(),
            entity.getId(),
            parentId,
            entity.getDisplayName(),
            entity.getEntityType().getName(),
            serviceUp,
            serviceState,
            iconUrl,
            entity.getCatalogItemId(),
            children,
            groupIds,
            members,
            MutableMap.of("self", EntityTransformer.entityUri(entity, ui.getBaseUriBuilder())) );
    
    if (includeTags) {
        result.setExtraField("tags", resolving(MutableList.copyOf(entity.tags().getTags())).preferJson(true).resolve() );
    }
    result.setExtraField("creationTimeUtc", entity.getCreationTime());
    addSensorsByGlobs(result, entity, extraSensorGlobs);
    addConfigByGlobs(result, entity, extraConfigGlobs);
    
    return result;
}
 
Example 18
Source File: SshCommandMembershipTrackingPolicy.java    From brooklyn-server with Apache License 2.0 4 votes vote down vote up
@SuppressWarnings("unchecked")
private void execute(Entity target, String command, String type, String memberId, boolean highlight) {
    if (Entities.isNoLongerManaged(target)) return;
    Lifecycle state = target.getAttribute(Attributes.SERVICE_STATE_ACTUAL);
    if (state==Lifecycle.STOPPING || state==Lifecycle.STOPPED) return;
    
    Collection<? extends Location> locations = Locations.getLocationsCheckingAncestors(target.getLocations(), target);
    Maybe<SshMachineLocation> machine = Machines.findUniqueMachineLocation(locations, SshMachineLocation.class);
    if (machine.isAbsentOrNull()) {
        LOG.debug("No machine available to execute command");
        return;
    }

    LOG.info("Executing command on {}: {}", machine.get(), command);
    String executionDir = config().get(EXECUTION_DIR);
    String sshCommand = SshCommandSensor.makeCommandExecutingInDirectory(command, executionDir, target);

    // Set things from the entities defined shell environment, overriding with our config
    Map<String, Object> env = MutableMap.of();
    env.putAll(MutableMap.copyOf(entity.config().get(BrooklynConfigKeys.SHELL_ENVIRONMENT)));
    env.putAll(MutableMap.copyOf(config().get(BrooklynConfigKeys.SHELL_ENVIRONMENT)));

    // Add variables describing this invocation
    env.put(EVENT_TYPE, type);
    env.put(MEMBER_ID, memberId);

    // Try to resolve the configuration in the env Map
    try {
        env = (Map<String, Object>) Tasks.resolveDeepValue(env, Object.class, getExecutionContext());
    } catch (InterruptedException | ExecutionException e) {
        throw Exceptions.propagate(e);
    }

    // Execute the command with the serialized environment strings
    ShellEnvironmentSerializer serializer = new ShellEnvironmentSerializer(getManagementContext());
    SshEffectorTasks.SshEffectorTaskFactory<String> task = SshEffectorTasks.ssh(sshCommand)
            .machine(machine.get())
            .requiringZeroAndReturningStdout()
            .summary("group-" + CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, type))
            .environmentVariables(serializer.serialize(env));

    Task<String> taskI = DynamicTasks.submit(task.newTask(), target);
    if (highlight) {
        highlightAction("Run at "+machine.get().getAddress().getHostAddress(), taskI);
    }
    String output = taskI.getUnchecked();
    LOG.trace("Command returned: {}", output);
}
 
Example 19
Source File: CreatePasswordSensorTest.java    From brooklyn-server with Apache License 2.0 4 votes vote down vote up
private void assertPasswordLength(Entity entity, AttributeSensor<String> password, int expectedLength) {
    String attribute_1 = entity.getAttribute(password);
    Asserts.assertEquals(attribute_1.length(), expectedLength);
}
 
Example 20
Source File: NginxUrlMappingIntegrationTest.java    From brooklyn-library with Apache License 2.0 4 votes vote down vote up
@Test(groups = "Integration")
public void testUrlMappingGroupRespondsToScaleOut() throws Exception {
    checkExtraLocalhosts();
    
    nginx = app.createAndManageChild(EntitySpec.create(NginxController.class)
            .configure("domain", "localhost")
            .configure("port", "8000+")
            .configure("portNumberSensor", WebAppService.HTTP_PORT)
            .configure("urlMappings", urlMappingsGroup));
    
    final DynamicCluster c1 = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
            .configure("initialSize", 1)
            .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(Tomcat8Server.class).configure("httpPort", "8100+"))
            .configure(JavaWebAppService.ROOT_WAR, getTestWar()));
    final UrlMapping u1 = urlMappingsGroup.addChild(EntitySpec.create(UrlMapping.class)
            .configure("domain", "localhost1")
            .configure("target", c1));
    
    app.start(ImmutableList.of(localLoc));
    int port = nginx.getAttribute(NginxController.PROXY_HTTP_PORT);
    
    Entity c1jboss = Iterables.getOnlyElement(c1.getMembers());
    
    // Wait for app-server to be responsive, and url-mapping to update its TARGET_ADDRESSES (through async subscription)
    Asserts.succeedsEventually(new Runnable() {
        @Override
        public void run() {
            // Entities.dumpInfo(app);
            assertEquals(u1.getAttribute(UrlMapping.TARGET_ADDRESSES).size(), 1);
        }});

    // check nginx forwards localhost1 to c1
    HttpTestUtils.assertContentEventuallyContainsText("http://localhost1:"+port+"", "Hello");
    
    // Resize target cluster of url-mapping
    c1.resize(2);
    List c1jbosses = new ArrayList(c1.getMembers());
    c1jbosses.remove(c1jboss);
    // the unnecessary (Entity) cast is required as a work-around to an IntelliJ issue that prevents Brooklyn from launching from the IDE
    Entity c1jboss2 = (Entity)Iterables.getOnlyElement(c1jbosses);

    // TODO Have to wait for new app-server; should fix app-servers to block
    // Also wait for TARGET_ADDRESSES to update
    assertAppServerRespondsEventually(c1jboss2);
    Asserts.succeedsEventually(new Runnable() {
        @Override
        public void run() {
            assertEquals(u1.getAttribute(UrlMapping.TARGET_ADDRESSES).size(), 2);
        }});

    // check jboss2 is included in nginx rules
    // TODO Should getConfigFile return the current config file, rather than recalculate?
    //      This assertion isn't good enough to tell if it's been deployed.
    final String c1jboss2addr = c1jboss2.getAttribute(Attributes.HOSTNAME)+":"+c1jboss2.getAttribute(Attributes.HTTP_PORT);
    Asserts.succeedsEventually(new Runnable() {
        @Override
        public void run() {
            String conf = nginx.getConfigFile();
            assertTrue(conf.contains(c1jboss2addr), "could not find "+c1jboss2addr+" in:\n"+conf);
        }});
    
    // and check forwarding to c1 by nginx still works
    for (int i = 0; i < 2; i++) {
        HttpTestUtils.assertContentContainsText("http://localhost1:"+port+"", "Hello");
    }
}