You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@brooklyn.apache.org by grkvlt <gi...@git.apache.org> on 2017/06/29 15:55:12 UTC

[GitHub] brooklyn-server pull request #750: Adds a policy to create locations from an...

GitHub user grkvlt opened a pull request:

    https://github.com/apache/brooklyn-server/pull/750

    Adds a policy to create locations from an entity

    Adds `CreateLocationPolicy`which configures a location using sensor data from an entity, once the entity is running. The location is added to the catalog for use by other blueprints.

You can merge this pull request into a Git repository by running:

    $ git pull https://github.com/grkvlt/brooklyn-server feature/entity-location-policy

Alternatively you can review and apply these changes as the patch at:

    https://github.com/apache/brooklyn-server/pull/750.patch

To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:

    This closes #750
    
----
commit aee164ab290a5b197a0b1772ac2f123e34382bc0
Author: Andrew Donald Kennedy <an...@cloudsoftcorp.com>
Date:   2017-06-06T23:25:55Z

    Add policy to create location dynamically from entity

commit b9bf8da36ceda0239af7abb2cb2f706518ce922d
Author: Andrew Donald Kennedy <an...@cloudsoftcorp.com>
Date:   2017-06-07T13:31:50Z

    Tidy up and add logging

commit f58239db85391af96661b919516fe501ba0d1bf3
Author: Andrew Donald Kennedy <an...@cloudsoftcorp.com>
Date:   2017-06-13T15:43:53Z

    Add call to super.setEntity in create location policy

commit e18fd55e7f264c447bbf5d7c6bc3a2e5e49fa405
Author: Andrea Turli <an...@gmail.com>
Date:   2017-06-15T09:58:42Z

    use Catalog instead of LocationRegistry
    
    - add example to javadoc

commit 1aae33136281a29e613a7bbb46ebd5dd1f7c8406
Author: Andrea Turli <an...@gmail.com>
Date:   2017-06-15T10:06:36Z

    mark as Beta

commit 143b9d5cda1c13122c44c049403a442d37eae9f4
Author: Andrew Donald Kennedy <an...@cloudsoftcorp.com>
Date:   2017-06-18T16:58:56Z

    Update location YAML with tags and check return status

----


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] brooklyn-server issue #750: Adds a policy to create locations from an entity

Posted by drigodwin <gi...@git.apache.org>.
Github user drigodwin commented on the issue:

    https://github.com/apache/brooklyn-server/pull/750
  
    This looks really useful but it could probably do with some tests if that's possible @grkvlt?  


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] brooklyn-server issue #750: Adds a policy to create locations from an entity

Posted by andreaturli <gi...@git.apache.org>.
Github user andreaturli commented on the issue:

    https://github.com/apache/brooklyn-server/pull/750
  
    @grkvlt any updates on this?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] brooklyn-server issue #750: Adds a policy to create locations from an entity

Posted by grkvlt <gi...@git.apache.org>.
Github user grkvlt commented on the issue:

    https://github.com/apache/brooklyn-server/pull/750
  
    Thanks for the review @aledsage, I will update appropriately. The use case is for blueprints like Kubernetes, which would be able to add a new `KubernetesLocation` or similar.


---

[GitHub] brooklyn-server pull request #750: Adds a policy to create locations from an...

Posted by aledsage <gi...@git.apache.org>.
Github user aledsage commented on a diff in the pull request:

    https://github.com/apache/brooklyn-server/pull/750#discussion_r138608438
  
    --- Diff: policy/src/main/java/org/apache/brooklyn/policy/location/CreateLocationPolicy.java ---
    @@ -0,0 +1,288 @@
    +/*
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *     http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + */
    +package org.apache.brooklyn.policy.location;
    +
    +import java.util.Map;
    +import java.util.NoSuchElementException;
    +import java.util.Set;
    +import java.util.concurrent.atomic.AtomicBoolean;
    +import java.util.concurrent.atomic.AtomicInteger;
    +
    +import org.apache.brooklyn.api.catalog.CatalogItem;
    +import org.apache.brooklyn.api.entity.EntityLocal;
    +import org.apache.brooklyn.api.policy.PolicySpec;
    +import org.apache.brooklyn.api.sensor.AttributeSensor;
    +import org.apache.brooklyn.api.sensor.SensorEvent;
    +import org.apache.brooklyn.api.sensor.SensorEventListener;
    +import org.apache.brooklyn.config.ConfigKey;
    +import org.apache.brooklyn.core.config.ConfigKeys;
    +import org.apache.brooklyn.core.entity.trait.Startable;
    +import org.apache.brooklyn.core.policy.AbstractPolicy;
    +import org.apache.brooklyn.util.collections.MutableMap;
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +
    +import com.google.common.annotations.Beta;
    +import com.google.common.base.Joiner;
    +import com.google.common.base.Predicates;
    +import com.google.common.collect.ImmutableList;
    +import com.google.common.collect.ImmutableMap;
    +import com.google.common.collect.ImmutableSet;
    +import com.google.common.collect.Iterables;
    +import com.google.common.reflect.TypeToken;
    +
    +/**
    + * Policy that is attached to an entity to create a location configured
    + * using its sensor data. The created location is added to the catalog
    + * and will be removed when the entity is no longer running, based on
    + * the entity {@link Startable#SERVICE_UP} sensor status.
    + * <p>
    + * The policy definition includes configuration for the id, name and
    + * type of the location, as well as the {@link #LOCATION_CONFIG} map
    + * of config keys and the sensors used to define them.
    + * <p>
    + * The YAML below shows a policy that creates a {@code jclouds:aws-ec2}
    + * location with the region defined by a sensor on the entity it is
    + * attached to:
    + * <pre>{@code
    + * name: My App
    + * brooklyn.policies:
    + *   - type: org.apache.brooklyn.policy.location.CreateLocationPolicy
    + *     id: create-my-cloud-location
    + *     brooklyn.config:
    + *       location.catalogId: my-cloud
    + *       location.displayName: "My Cloud"
    + *       location.type: jclouds:aws-ec2
    + *       location.config:
    + *         region: $brooklyn:sensor("aws.region")
    + * }</pre>
    + *
    + */
    +@Beta
    +public class CreateLocationPolicy extends AbstractPolicy {
    +
    +    private static final Logger LOG = LoggerFactory.getLogger(CreateLocationPolicy.class);
    +
    +    public static Builder builder() {
    +        return new Builder();
    +    }
    +
    +    public static class Builder {
    +        private String id;
    +        private String name;
    +        private AttributeSensor<Boolean> status;
    +        private Map<String,AttributeSensor<?>> configuration;
    +        private String catalogId;
    +        private String displayName;
    +        private String type;
    +        private Set<String> tags;
    +
    +        public Builder id(String val) {
    +            this.id = val; return this;
    +        }
    +        public Builder name(String val) {
    +            this.name = val; return this;
    +        }
    +        public Builder status(AttributeSensor<Boolean> val) {
    +            this.status = val; return this;
    +        }
    +        public Builder configuration(Map<String,AttributeSensor<?>> val) {
    +            this.configuration = val; return this;
    +        }
    +        public Builder catalogId(String val) {
    +            this.catalogId = val; return this;
    +        }
    +        public Builder displayName(String val) {
    +            this.displayName = val; return this;
    +        }
    +        public Builder type(String val) {
    +            this.type = val; return this;
    +        }
    +        public Builder tags(Set<String> val) {
    +            this.tags = val; return this;
    +        }
    +        public CreateLocationPolicy build() {
    +            return new CreateLocationPolicy(toFlags());
    +        }
    +        public PolicySpec<CreateLocationPolicy> buildSpec() {
    +            return PolicySpec.create(CreateLocationPolicy.class)
    +                    .configure(toFlags());
    +        }
    +        private Map<String,?> toFlags() {
    +            return MutableMap.<String,Object>builder()
    +                    .putIfNotNull("id", id)
    +                    .putIfNotNull("name", name)
    +                    .putIfNotNull("location.status", status)
    +                    .putIfNotNull("location.config", configuration)
    +                    .putIfNotNull("location.catalogId", catalogId)
    +                    .putIfNotNull("location.displayName", displayName)
    +                    .putIfNotNull("location.type", type)
    +                    .putIfNotNull("location.tags", tags)
    +                    .build();
    +        }
    +    }
    +
    +    @SuppressWarnings("serial")
    +    public static final ConfigKey<AttributeSensor<Boolean>> LOCATION_STATUS = ConfigKeys.builder(new TypeToken<AttributeSensor<Boolean>>() {})
    +            .name("location.status")
    +            .description("Sensor on the entity to trigger location creation; defaults to service.isUp")
    +            .defaultValue(Startable.SERVICE_UP)
    +            .build();
    +
    +    @SuppressWarnings("serial")
    +    public static final ConfigKey<Map<String,AttributeSensor<?>>> LOCATION_CONFIG = ConfigKeys.builder(new TypeToken<Map<String,AttributeSensor<?>>>() {})
    +            .name("location.config")
    +            .description("Map of location configuration keys to sensors on the entity that provide their values")
    +            .defaultValue(ImmutableMap.of())
    +            .build();
    +
    +    public static final ConfigKey<String> LOCATION_CATALOG_ID = ConfigKeys.builder(String.class)
    +            .name("location.catalogId")
    +            .description("The catalog item ID to use for the created location")
    +            .constraint(Predicates.notNull())
    +            .build();
    +
    +    public static final ConfigKey<String> LOCATION_DISPLAY_NAME = ConfigKeys.builder(String.class)
    +            .name("location.displayName")
    +            .description("The display name for the created location")
    +            .constraint(Predicates.notNull())
    +            .build();
    +
    +    public static final ConfigKey<String> LOCATION_TYPE = ConfigKeys.builder(String.class)
    +            .name("location.type")
    +            .description("The type of location to create, i.e. 'jclouds:aws-ec2'")
    +            .constraint(Predicates.notNull())
    +            .build();
    +
    +    @SuppressWarnings("serial")
    +    public static final ConfigKey<Set<String>> LOCATION_TAGS = ConfigKeys.builder(new TypeToken<Set<String>>() {})
    +            .name("location.tags")
    +            .description("Tags for the created location")
    +            .defaultValue(ImmutableSet.of())
    +            .build();
    +
    +    private AtomicBoolean created = new AtomicBoolean(false);
    +    private Object mutex = new Object[0];
    +    private CatalogItem<?,?> catalogItem;
    +    private AtomicInteger version = new AtomicInteger(0);
    +
    +    public CreateLocationPolicy() {
    +        this(MutableMap.<String,Object>of());
    +    }
    +
    +    public CreateLocationPolicy(Map<String,?> props) {
    +        super(props);
    +    }
    +
    +    protected AttributeSensor<Boolean> getStatusSensor() {
    +        return config().get(LOCATION_STATUS);
    +    }
    +
    +    protected Map<String,AttributeSensor<?>> getLocationConfiguration() {
    +        return config().get(LOCATION_CONFIG);
    +    }
    +
    +    protected String getLocationCatalogItemId() {
    +        return config().get(LOCATION_CATALOG_ID);
    +    }
    +
    +    protected String getLocationDisplayName() {
    +        return config().get(LOCATION_DISPLAY_NAME);
    +    }
    +
    +    protected String getLocationType() {
    +        return config().get(LOCATION_TYPE);
    +    }
    +
    +    protected Set<String> getLocationTags() {
    +        return config().get(LOCATION_TAGS);
    +    }
    +
    +    @Override
    +    protected <T> void doReconfigureConfig(ConfigKey<T> key, T val) {
    +        throw new UnsupportedOperationException("reconfiguring "+key+" unsupported for "+this);
    +    }
    +
    +    private final SensorEventListener<Boolean> lifecycleEventHandler = new SensorEventListener<Boolean>() {
    +        @Override
    +        public void onEvent(SensorEvent<Boolean> event) {
    +            synchronized (mutex) {
    +                Boolean status = event.getValue();
    +                if (status) {
    +                    if (created.compareAndSet(false, true)) {
    +                        LOG.info("Creating new location {} of type {}", getLocationCatalogItemId(), getLocationType());
    +
    +                        ImmutableList.Builder<String> builder = ImmutableList.<String>builder().add(
    +                                "brooklyn.catalog:",
    +                                "  id: " + getLocationCatalogItemId(),
    +                                "  version: " + version.incrementAndGet(),
    +                                "  itemType: location",
    +                                "  item:",
    +                                "    type: " + getLocationType(),
    +                                "    brooklyn.config:",
    +                                "      displayName: " + getLocationDisplayName());
    +
    +                        for (Map.Entry<String, AttributeSensor<?>> entry : getLocationConfiguration().entrySet()) {
    +                            AttributeSensor<?> sensor = getLocationConfiguration().get(entry.getKey());
    +                            Object value = entity.sensors().get(sensor);
    +                            builder.add("      " + entry.getKey() + ": " + value);
    +                        }
    +                        if (getLocationTags().size() > 0) {
    +                            builder.add("      tags:");
    +                            for (String tag : getLocationTags()) {
    +                                builder.add("        - " + tag);
    +                            }
    +                        }
    +                        String blueprint = Joiner.on("\n").join(builder.build());
    +                        LOG.debug("Creating location {} from YAML\n{}", getLocationCatalogItemId(), blueprint);
    +
    +                        Iterable<? extends CatalogItem<?,?>> catalogItems = getManagementContext().getCatalog().addItems(blueprint, true);
    +                        int items = Iterables.size(catalogItems);
    +                        if (items > 1) {
    +                            LOG.warn("Got {} catalog items for location {}, using first: {}",
    +                                    new Object[] { items, getLocationCatalogItemId(), Iterables.transform(catalogItems, item -> item.getCatalogItemId()) });
    +                        } else if (items == 0) {
    +                            throw new IllegalStateException("No catalog items returned for location: " + getLocationCatalogItemId());
    +                        }
    +                        catalogItem = Iterables.get(catalogItems, 0);
    +                    }
    +                } else {
    +                    if (created.compareAndSet(true, false) && catalogItem != null) {
    --- End diff --
    
    `created` and `catalogItem` fields won't survive rebind. Neither will the auto-incrementing version. Therefore this will likely misbehave on rebind.


---

[GitHub] brooklyn-server pull request #750: Adds a policy to create locations from an...

Posted by andreaturli <gi...@git.apache.org>.
Github user andreaturli commented on a diff in the pull request:

    https://github.com/apache/brooklyn-server/pull/750#discussion_r125004879
  
    --- Diff: policy/src/main/java/org/apache/brooklyn/policy/location/CreateLocationPolicy.java ---
    @@ -0,0 +1,288 @@
    +/*
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *     http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + */
    +package org.apache.brooklyn.policy.location;
    +
    +import java.util.Map;
    +import java.util.NoSuchElementException;
    +import java.util.Set;
    +import java.util.concurrent.atomic.AtomicBoolean;
    +import java.util.concurrent.atomic.AtomicInteger;
    +
    +import org.apache.brooklyn.api.catalog.CatalogItem;
    +import org.apache.brooklyn.api.entity.EntityLocal;
    +import org.apache.brooklyn.api.policy.PolicySpec;
    +import org.apache.brooklyn.api.sensor.AttributeSensor;
    +import org.apache.brooklyn.api.sensor.SensorEvent;
    +import org.apache.brooklyn.api.sensor.SensorEventListener;
    +import org.apache.brooklyn.config.ConfigKey;
    +import org.apache.brooklyn.core.config.ConfigKeys;
    +import org.apache.brooklyn.core.entity.trait.Startable;
    +import org.apache.brooklyn.core.policy.AbstractPolicy;
    +import org.apache.brooklyn.util.collections.MutableMap;
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +
    +import com.google.common.annotations.Beta;
    +import com.google.common.base.Joiner;
    +import com.google.common.base.Predicates;
    +import com.google.common.collect.ImmutableList;
    +import com.google.common.collect.ImmutableMap;
    +import com.google.common.collect.ImmutableSet;
    +import com.google.common.collect.Iterables;
    +import com.google.common.reflect.TypeToken;
    +
    +/**
    + * Policy that is attached to an entity to create a location configured
    + * using its sensor data. The created location is added to the catalog
    + * and will be removed when the entity is no longer running, based on
    + * the entity {@link Startable#SERVICE_UP} sensor status.
    + * <p>
    + * The policy definition includes configuration for the id, name and
    + * type of the location, as well as the {@link #LOCATION_CONFIG} map
    + * of config keys and the sensors used to define them.
    + * <p>
    + * The YAML below shows a policy that creates a {@code jclouds:aws-ec2}
    + * location with the region defined by a sensor on the entity it is
    + * attached to:
    + * <pre>{@code
    + * name: My App
    + * brooklyn.policies:
    + *   - type: org.apache.brooklyn.policy.location.CreateLocationPolicy
    + *     id: create-my-cloud-location
    + *     brooklyn.config:
    + *       location.catalogId: my-cloud
    + *       location.displayName: "My Cloud"
    + *       location.type: jclouds:aws-ec2
    + *       location.config:
    + *         region: $brooklyn:sensor("aws.region")
    + * }</pre>
    + *
    + */
    +@Beta
    +public class CreateLocationPolicy extends AbstractPolicy {
    +
    +    private static final Logger LOG = LoggerFactory.getLogger(CreateLocationPolicy.class);
    +
    +    public static Builder builder() {
    +        return new Builder();
    +    }
    +
    +    public static class Builder {
    +        private String id;
    +        private String name;
    +        private AttributeSensor<Boolean> status;
    +        private Map<String,AttributeSensor<?>> configuration;
    +        private String catalogId;
    +        private String displayName;
    +        private String type;
    +        private Set<String> tags;
    +
    +        public Builder id(String val) {
    +            this.id = val; return this;
    +        }
    +        public Builder name(String val) {
    +            this.name = val; return this;
    +        }
    +        public Builder status(AttributeSensor<Boolean> val) {
    +            this.status = val; return this;
    +        }
    +        public Builder configuration(Map<String,AttributeSensor<?>> val) {
    +            this.configuration = val; return this;
    +        }
    +        public Builder catalogId(String val) {
    +            this.catalogId = val; return this;
    +        }
    +        public Builder displayName(String val) {
    +            this.displayName = val; return this;
    +        }
    +        public Builder type(String val) {
    +            this.type = val; return this;
    +        }
    +        public Builder tags(Set<String> val) {
    +            this.tags = val; return this;
    +        }
    +        public CreateLocationPolicy build() {
    +            return new CreateLocationPolicy(toFlags());
    +        }
    +        public PolicySpec<CreateLocationPolicy> buildSpec() {
    +            return PolicySpec.create(CreateLocationPolicy.class)
    +                    .configure(toFlags());
    +        }
    +        private Map<String,?> toFlags() {
    +            return MutableMap.<String,Object>builder()
    +                    .putIfNotNull("id", id)
    +                    .putIfNotNull("name", name)
    +                    .putIfNotNull("location.status", status)
    +                    .putIfNotNull("location.config", configuration)
    +                    .putIfNotNull("location.catalogId", catalogId)
    +                    .putIfNotNull("location.displayName", displayName)
    +                    .putIfNotNull("location.type", type)
    +                    .putIfNotNull("location.tags", tags)
    +                    .build();
    +        }
    +    }
    +
    +    @SuppressWarnings("serial")
    +    public static final ConfigKey<AttributeSensor<Boolean>> LOCATION_STATUS = ConfigKeys.builder(new TypeToken<AttributeSensor<Boolean>>() {})
    +            .name("location.status")
    +            .description("Sensor on the entity to trigger location creation; defaults to service.isUp")
    +            .defaultValue(Startable.SERVICE_UP)
    +            .build();
    +
    +    @SuppressWarnings("serial")
    +    public static final ConfigKey<Map<String,AttributeSensor<?>>> LOCATION_CONFIG = ConfigKeys.builder(new TypeToken<Map<String,AttributeSensor<?>>>() {})
    +            .name("location.config")
    +            .description("Map of location configuration keys to sensors on the entity that provide their values")
    +            .defaultValue(ImmutableMap.of())
    +            .build();
    +
    +    public static final ConfigKey<String> LOCATION_CATALOG_ID = ConfigKeys.builder(String.class)
    +            .name("location.catalogId")
    +            .description("The catalog item ID to use for the created location")
    +            .constraint(Predicates.notNull())
    +            .build();
    +
    +    public static final ConfigKey<String> LOCATION_DISPLAY_NAME = ConfigKeys.builder(String.class)
    +            .name("location.displayName")
    +            .description("The display name for the created location")
    +            .constraint(Predicates.notNull())
    +            .build();
    +
    +    public static final ConfigKey<String> LOCATION_TYPE = ConfigKeys.builder(String.class)
    +            .name("location.type")
    +            .description("The type of location to create, i.e. 'jclouds:aws-ec2'")
    +            .constraint(Predicates.notNull())
    +            .build();
    +
    +    @SuppressWarnings("serial")
    +    public static final ConfigKey<Set<String>> LOCATION_TAGS = ConfigKeys.builder(new TypeToken<Set<String>>() {})
    +            .name("location.tags")
    +            .description("Tags for the created location")
    +            .defaultValue(ImmutableSet.of())
    +            .build();
    +
    +    private AtomicBoolean created = new AtomicBoolean(false);
    +    private Object mutex = new Object[0];
    +    private CatalogItem<?,?> catalogItem;
    +    private AtomicInteger version = new AtomicInteger(0);
    +
    +    public CreateLocationPolicy() {
    +        this(MutableMap.<String,Object>of());
    +    }
    +
    +    public CreateLocationPolicy(Map<String,?> props) {
    +        super(props);
    +    }
    +
    +    protected AttributeSensor<Boolean> getStatusSensor() {
    +        return config().get(LOCATION_STATUS);
    +    }
    +
    +    protected Map<String,AttributeSensor<?>> getLocationConfiguration() {
    +        return config().get(LOCATION_CONFIG);
    +    }
    +
    +    protected String getLocationCatalogItemId() {
    +        return config().get(LOCATION_CATALOG_ID);
    +    }
    +
    +    protected String getLocationDisplayName() {
    +        return config().get(LOCATION_DISPLAY_NAME);
    +    }
    +
    +    protected String getLocationType() {
    +        return config().get(LOCATION_TYPE);
    +    }
    +
    +    protected Set<String> getLocationTags() {
    +        return config().get(LOCATION_TAGS);
    +    }
    +
    +    @Override
    +    protected <T> void doReconfigureConfig(ConfigKey<T> key, T val) {
    +        throw new UnsupportedOperationException("reconfiguring "+key+" unsupported for "+this);
    +    }
    +
    +    private final SensorEventListener<Boolean> lifecycleEventHandler = new SensorEventListener<Boolean>() {
    +        @Override
    +        public void onEvent(SensorEvent<Boolean> event) {
    +            synchronized (mutex) {
    +                Boolean status = event.getValue();
    +                if (status) {
    +                    if (created.compareAndSet(false, true)) {
    +                        LOG.info("Creating new location {} of type {}", getLocationCatalogItemId(), getLocationType());
    +
    +                        ImmutableList.Builder<String> builder = ImmutableList.<String>builder().add(
    +                                "brooklyn.catalog:",
    +                                "  id: " + getLocationCatalogItemId(),
    +                                "  version: " + version.incrementAndGet(),
    +                                "  itemType: location",
    +                                "  item:",
    +                                "    type: " + getLocationType(),
    +                                "    brooklyn.config:",
    +                                "      displayName: " + getLocationDisplayName());
    +
    +                        for (Map.Entry<String, AttributeSensor<?>> entry : getLocationConfiguration().entrySet()) {
    +                            AttributeSensor<?> sensor = getLocationConfiguration().get(entry.getKey());
    +                            Object value = entity.sensors().get(sensor);
    --- End diff --
    
    what happens if the sensor is not yet populated, wouldn't be safer to require directly value so we can use `attributeWhenReady` in the blueprint? or maybe we can always assume that once `LOCATION_STATUS` is true, brooklyn would have sensor data ready?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] brooklyn-server pull request #750: Adds a policy to create locations from an...

Posted by aledsage <gi...@git.apache.org>.
Github user aledsage commented on a diff in the pull request:

    https://github.com/apache/brooklyn-server/pull/750#discussion_r138607171
  
    --- Diff: policy/src/main/java/org/apache/brooklyn/policy/location/CreateLocationPolicy.java ---
    @@ -0,0 +1,288 @@
    +/*
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *     http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + */
    +package org.apache.brooklyn.policy.location;
    +
    +import java.util.Map;
    +import java.util.NoSuchElementException;
    +import java.util.Set;
    +import java.util.concurrent.atomic.AtomicBoolean;
    +import java.util.concurrent.atomic.AtomicInteger;
    +
    +import org.apache.brooklyn.api.catalog.CatalogItem;
    +import org.apache.brooklyn.api.entity.EntityLocal;
    +import org.apache.brooklyn.api.policy.PolicySpec;
    +import org.apache.brooklyn.api.sensor.AttributeSensor;
    +import org.apache.brooklyn.api.sensor.SensorEvent;
    +import org.apache.brooklyn.api.sensor.SensorEventListener;
    +import org.apache.brooklyn.config.ConfigKey;
    +import org.apache.brooklyn.core.config.ConfigKeys;
    +import org.apache.brooklyn.core.entity.trait.Startable;
    +import org.apache.brooklyn.core.policy.AbstractPolicy;
    +import org.apache.brooklyn.util.collections.MutableMap;
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +
    +import com.google.common.annotations.Beta;
    +import com.google.common.base.Joiner;
    +import com.google.common.base.Predicates;
    +import com.google.common.collect.ImmutableList;
    +import com.google.common.collect.ImmutableMap;
    +import com.google.common.collect.ImmutableSet;
    +import com.google.common.collect.Iterables;
    +import com.google.common.reflect.TypeToken;
    +
    +/**
    + * Policy that is attached to an entity to create a location configured
    + * using its sensor data. The created location is added to the catalog
    + * and will be removed when the entity is no longer running, based on
    + * the entity {@link Startable#SERVICE_UP} sensor status.
    + * <p>
    + * The policy definition includes configuration for the id, name and
    + * type of the location, as well as the {@link #LOCATION_CONFIG} map
    + * of config keys and the sensors used to define them.
    + * <p>
    + * The YAML below shows a policy that creates a {@code jclouds:aws-ec2}
    + * location with the region defined by a sensor on the entity it is
    + * attached to:
    + * <pre>{@code
    + * name: My App
    + * brooklyn.policies:
    + *   - type: org.apache.brooklyn.policy.location.CreateLocationPolicy
    + *     id: create-my-cloud-location
    + *     brooklyn.config:
    + *       location.catalogId: my-cloud
    + *       location.displayName: "My Cloud"
    + *       location.type: jclouds:aws-ec2
    + *       location.config:
    + *         region: $brooklyn:sensor("aws.region")
    + * }</pre>
    + *
    + */
    +@Beta
    +public class CreateLocationPolicy extends AbstractPolicy {
    +
    +    private static final Logger LOG = LoggerFactory.getLogger(CreateLocationPolicy.class);
    +
    +    public static Builder builder() {
    +        return new Builder();
    +    }
    +
    +    public static class Builder {
    +        private String id;
    +        private String name;
    +        private AttributeSensor<Boolean> status;
    +        private Map<String,AttributeSensor<?>> configuration;
    +        private String catalogId;
    +        private String displayName;
    +        private String type;
    +        private Set<String> tags;
    +
    +        public Builder id(String val) {
    +            this.id = val; return this;
    +        }
    +        public Builder name(String val) {
    +            this.name = val; return this;
    +        }
    +        public Builder status(AttributeSensor<Boolean> val) {
    +            this.status = val; return this;
    +        }
    +        public Builder configuration(Map<String,AttributeSensor<?>> val) {
    +            this.configuration = val; return this;
    +        }
    +        public Builder catalogId(String val) {
    +            this.catalogId = val; return this;
    +        }
    +        public Builder displayName(String val) {
    +            this.displayName = val; return this;
    +        }
    +        public Builder type(String val) {
    +            this.type = val; return this;
    +        }
    +        public Builder tags(Set<String> val) {
    +            this.tags = val; return this;
    +        }
    +        public CreateLocationPolicy build() {
    +            return new CreateLocationPolicy(toFlags());
    +        }
    +        public PolicySpec<CreateLocationPolicy> buildSpec() {
    +            return PolicySpec.create(CreateLocationPolicy.class)
    +                    .configure(toFlags());
    +        }
    +        private Map<String,?> toFlags() {
    +            return MutableMap.<String,Object>builder()
    +                    .putIfNotNull("id", id)
    +                    .putIfNotNull("name", name)
    +                    .putIfNotNull("location.status", status)
    +                    .putIfNotNull("location.config", configuration)
    +                    .putIfNotNull("location.catalogId", catalogId)
    +                    .putIfNotNull("location.displayName", displayName)
    +                    .putIfNotNull("location.type", type)
    +                    .putIfNotNull("location.tags", tags)
    +                    .build();
    +        }
    +    }
    +
    +    @SuppressWarnings("serial")
    +    public static final ConfigKey<AttributeSensor<Boolean>> LOCATION_STATUS = ConfigKeys.builder(new TypeToken<AttributeSensor<Boolean>>() {})
    +            .name("location.status")
    +            .description("Sensor on the entity to trigger location creation; defaults to service.isUp")
    +            .defaultValue(Startable.SERVICE_UP)
    +            .build();
    +
    +    @SuppressWarnings("serial")
    +    public static final ConfigKey<Map<String,AttributeSensor<?>>> LOCATION_CONFIG = ConfigKeys.builder(new TypeToken<Map<String,AttributeSensor<?>>>() {})
    +            .name("location.config")
    +            .description("Map of location configuration keys to sensors on the entity that provide their values")
    +            .defaultValue(ImmutableMap.of())
    +            .build();
    +
    +    public static final ConfigKey<String> LOCATION_CATALOG_ID = ConfigKeys.builder(String.class)
    +            .name("location.catalogId")
    +            .description("The catalog item ID to use for the created location")
    +            .constraint(Predicates.notNull())
    +            .build();
    +
    +    public static final ConfigKey<String> LOCATION_DISPLAY_NAME = ConfigKeys.builder(String.class)
    +            .name("location.displayName")
    +            .description("The display name for the created location")
    +            .constraint(Predicates.notNull())
    +            .build();
    +
    +    public static final ConfigKey<String> LOCATION_TYPE = ConfigKeys.builder(String.class)
    +            .name("location.type")
    +            .description("The type of location to create, i.e. 'jclouds:aws-ec2'")
    --- End diff --
    
    "e.g." rather than "i.e."


---

[GitHub] brooklyn-server issue #750: Adds a policy to create locations from an entity

Posted by grkvlt <gi...@git.apache.org>.
Github user grkvlt commented on the issue:

    https://github.com/apache/brooklyn-server/pull/750
  
    Yes, that's probably useful - I'll put something together


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] brooklyn-server issue #750: Adds a policy to create locations from an entity

Posted by tbouron <gi...@git.apache.org>.
Github user tbouron commented on the issue:

    https://github.com/apache/brooklyn-server/pull/750
  
    @grkvlt Did you had the time to looks at @aledsage's comments for this PR?


---

[GitHub] brooklyn-server pull request #750: Adds a policy to create locations from an...

Posted by aledsage <gi...@git.apache.org>.
Github user aledsage commented on a diff in the pull request:

    https://github.com/apache/brooklyn-server/pull/750#discussion_r138607380
  
    --- Diff: policy/src/main/java/org/apache/brooklyn/policy/location/CreateLocationPolicy.java ---
    @@ -0,0 +1,288 @@
    +/*
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *     http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + */
    +package org.apache.brooklyn.policy.location;
    +
    +import java.util.Map;
    +import java.util.NoSuchElementException;
    +import java.util.Set;
    +import java.util.concurrent.atomic.AtomicBoolean;
    +import java.util.concurrent.atomic.AtomicInteger;
    +
    +import org.apache.brooklyn.api.catalog.CatalogItem;
    +import org.apache.brooklyn.api.entity.EntityLocal;
    +import org.apache.brooklyn.api.policy.PolicySpec;
    +import org.apache.brooklyn.api.sensor.AttributeSensor;
    +import org.apache.brooklyn.api.sensor.SensorEvent;
    +import org.apache.brooklyn.api.sensor.SensorEventListener;
    +import org.apache.brooklyn.config.ConfigKey;
    +import org.apache.brooklyn.core.config.ConfigKeys;
    +import org.apache.brooklyn.core.entity.trait.Startable;
    +import org.apache.brooklyn.core.policy.AbstractPolicy;
    +import org.apache.brooklyn.util.collections.MutableMap;
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +
    +import com.google.common.annotations.Beta;
    +import com.google.common.base.Joiner;
    +import com.google.common.base.Predicates;
    +import com.google.common.collect.ImmutableList;
    +import com.google.common.collect.ImmutableMap;
    +import com.google.common.collect.ImmutableSet;
    +import com.google.common.collect.Iterables;
    +import com.google.common.reflect.TypeToken;
    +
    +/**
    + * Policy that is attached to an entity to create a location configured
    + * using its sensor data. The created location is added to the catalog
    + * and will be removed when the entity is no longer running, based on
    + * the entity {@link Startable#SERVICE_UP} sensor status.
    + * <p>
    + * The policy definition includes configuration for the id, name and
    + * type of the location, as well as the {@link #LOCATION_CONFIG} map
    + * of config keys and the sensors used to define them.
    + * <p>
    + * The YAML below shows a policy that creates a {@code jclouds:aws-ec2}
    + * location with the region defined by a sensor on the entity it is
    + * attached to:
    + * <pre>{@code
    + * name: My App
    + * brooklyn.policies:
    + *   - type: org.apache.brooklyn.policy.location.CreateLocationPolicy
    + *     id: create-my-cloud-location
    + *     brooklyn.config:
    + *       location.catalogId: my-cloud
    + *       location.displayName: "My Cloud"
    + *       location.type: jclouds:aws-ec2
    + *       location.config:
    + *         region: $brooklyn:sensor("aws.region")
    + * }</pre>
    + *
    + */
    +@Beta
    +public class CreateLocationPolicy extends AbstractPolicy {
    +
    +    private static final Logger LOG = LoggerFactory.getLogger(CreateLocationPolicy.class);
    +
    +    public static Builder builder() {
    +        return new Builder();
    +    }
    +
    +    public static class Builder {
    +        private String id;
    +        private String name;
    +        private AttributeSensor<Boolean> status;
    +        private Map<String,AttributeSensor<?>> configuration;
    +        private String catalogId;
    +        private String displayName;
    +        private String type;
    +        private Set<String> tags;
    +
    +        public Builder id(String val) {
    +            this.id = val; return this;
    +        }
    +        public Builder name(String val) {
    +            this.name = val; return this;
    +        }
    +        public Builder status(AttributeSensor<Boolean> val) {
    +            this.status = val; return this;
    +        }
    +        public Builder configuration(Map<String,AttributeSensor<?>> val) {
    +            this.configuration = val; return this;
    +        }
    +        public Builder catalogId(String val) {
    +            this.catalogId = val; return this;
    +        }
    +        public Builder displayName(String val) {
    +            this.displayName = val; return this;
    +        }
    +        public Builder type(String val) {
    +            this.type = val; return this;
    +        }
    +        public Builder tags(Set<String> val) {
    +            this.tags = val; return this;
    +        }
    +        public CreateLocationPolicy build() {
    +            return new CreateLocationPolicy(toFlags());
    +        }
    +        public PolicySpec<CreateLocationPolicy> buildSpec() {
    +            return PolicySpec.create(CreateLocationPolicy.class)
    +                    .configure(toFlags());
    +        }
    +        private Map<String,?> toFlags() {
    +            return MutableMap.<String,Object>builder()
    +                    .putIfNotNull("id", id)
    +                    .putIfNotNull("name", name)
    +                    .putIfNotNull("location.status", status)
    +                    .putIfNotNull("location.config", configuration)
    +                    .putIfNotNull("location.catalogId", catalogId)
    +                    .putIfNotNull("location.displayName", displayName)
    +                    .putIfNotNull("location.type", type)
    +                    .putIfNotNull("location.tags", tags)
    +                    .build();
    +        }
    +    }
    +
    +    @SuppressWarnings("serial")
    +    public static final ConfigKey<AttributeSensor<Boolean>> LOCATION_STATUS = ConfigKeys.builder(new TypeToken<AttributeSensor<Boolean>>() {})
    +            .name("location.status")
    +            .description("Sensor on the entity to trigger location creation; defaults to service.isUp")
    +            .defaultValue(Startable.SERVICE_UP)
    +            .build();
    +
    +    @SuppressWarnings("serial")
    +    public static final ConfigKey<Map<String,AttributeSensor<?>>> LOCATION_CONFIG = ConfigKeys.builder(new TypeToken<Map<String,AttributeSensor<?>>>() {})
    +            .name("location.config")
    +            .description("Map of location configuration keys to sensors on the entity that provide their values")
    +            .defaultValue(ImmutableMap.of())
    +            .build();
    +
    +    public static final ConfigKey<String> LOCATION_CATALOG_ID = ConfigKeys.builder(String.class)
    +            .name("location.catalogId")
    +            .description("The catalog item ID to use for the created location")
    +            .constraint(Predicates.notNull())
    +            .build();
    +
    +    public static final ConfigKey<String> LOCATION_DISPLAY_NAME = ConfigKeys.builder(String.class)
    +            .name("location.displayName")
    +            .description("The display name for the created location")
    +            .constraint(Predicates.notNull())
    +            .build();
    +
    +    public static final ConfigKey<String> LOCATION_TYPE = ConfigKeys.builder(String.class)
    +            .name("location.type")
    +            .description("The type of location to create, i.e. 'jclouds:aws-ec2'")
    +            .constraint(Predicates.notNull())
    +            .build();
    +
    +    @SuppressWarnings("serial")
    +    public static final ConfigKey<Set<String>> LOCATION_TAGS = ConfigKeys.builder(new TypeToken<Set<String>>() {})
    +            .name("location.tags")
    +            .description("Tags for the created location")
    +            .defaultValue(ImmutableSet.of())
    +            .build();
    +
    +    private AtomicBoolean created = new AtomicBoolean(false);
    +    private Object mutex = new Object[0];
    +    private CatalogItem<?,?> catalogItem;
    +    private AtomicInteger version = new AtomicInteger(0);
    +
    +    public CreateLocationPolicy() {
    +        this(MutableMap.<String,Object>of());
    +    }
    +
    +    public CreateLocationPolicy(Map<String,?> props) {
    --- End diff --
    
    Remove this constructor - rely on `PolicySpec` for everything.


---

[GitHub] brooklyn-server issue #750: Adds a policy to create locations from an entity

Posted by andreaturli <gi...@git.apache.org>.
Github user andreaturli commented on the issue:

    https://github.com/apache/brooklyn-server/pull/750
  
    I agree with @drigodwin about the tests :)
    
    FYI I've tested the `CreateLocationPolicy` and it works fine in some scenarios, only a minor comment.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] brooklyn-server pull request #750: Adds a policy to create locations from an...

Posted by aledsage <gi...@git.apache.org>.
Github user aledsage commented on a diff in the pull request:

    https://github.com/apache/brooklyn-server/pull/750#discussion_r138607947
  
    --- Diff: policy/src/main/java/org/apache/brooklyn/policy/location/CreateLocationPolicy.java ---
    @@ -0,0 +1,288 @@
    +/*
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *     http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + */
    +package org.apache.brooklyn.policy.location;
    +
    +import java.util.Map;
    +import java.util.NoSuchElementException;
    +import java.util.Set;
    +import java.util.concurrent.atomic.AtomicBoolean;
    +import java.util.concurrent.atomic.AtomicInteger;
    +
    +import org.apache.brooklyn.api.catalog.CatalogItem;
    +import org.apache.brooklyn.api.entity.EntityLocal;
    +import org.apache.brooklyn.api.policy.PolicySpec;
    +import org.apache.brooklyn.api.sensor.AttributeSensor;
    +import org.apache.brooklyn.api.sensor.SensorEvent;
    +import org.apache.brooklyn.api.sensor.SensorEventListener;
    +import org.apache.brooklyn.config.ConfigKey;
    +import org.apache.brooklyn.core.config.ConfigKeys;
    +import org.apache.brooklyn.core.entity.trait.Startable;
    +import org.apache.brooklyn.core.policy.AbstractPolicy;
    +import org.apache.brooklyn.util.collections.MutableMap;
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +
    +import com.google.common.annotations.Beta;
    +import com.google.common.base.Joiner;
    +import com.google.common.base.Predicates;
    +import com.google.common.collect.ImmutableList;
    +import com.google.common.collect.ImmutableMap;
    +import com.google.common.collect.ImmutableSet;
    +import com.google.common.collect.Iterables;
    +import com.google.common.reflect.TypeToken;
    +
    +/**
    + * Policy that is attached to an entity to create a location configured
    + * using its sensor data. The created location is added to the catalog
    + * and will be removed when the entity is no longer running, based on
    + * the entity {@link Startable#SERVICE_UP} sensor status.
    + * <p>
    + * The policy definition includes configuration for the id, name and
    + * type of the location, as well as the {@link #LOCATION_CONFIG} map
    + * of config keys and the sensors used to define them.
    + * <p>
    + * The YAML below shows a policy that creates a {@code jclouds:aws-ec2}
    + * location with the region defined by a sensor on the entity it is
    + * attached to:
    + * <pre>{@code
    + * name: My App
    + * brooklyn.policies:
    + *   - type: org.apache.brooklyn.policy.location.CreateLocationPolicy
    + *     id: create-my-cloud-location
    + *     brooklyn.config:
    + *       location.catalogId: my-cloud
    + *       location.displayName: "My Cloud"
    + *       location.type: jclouds:aws-ec2
    + *       location.config:
    + *         region: $brooklyn:sensor("aws.region")
    + * }</pre>
    + *
    + */
    +@Beta
    +public class CreateLocationPolicy extends AbstractPolicy {
    +
    +    private static final Logger LOG = LoggerFactory.getLogger(CreateLocationPolicy.class);
    +
    +    public static Builder builder() {
    +        return new Builder();
    +    }
    +
    +    public static class Builder {
    +        private String id;
    +        private String name;
    +        private AttributeSensor<Boolean> status;
    +        private Map<String,AttributeSensor<?>> configuration;
    +        private String catalogId;
    +        private String displayName;
    +        private String type;
    +        private Set<String> tags;
    +
    +        public Builder id(String val) {
    +            this.id = val; return this;
    +        }
    +        public Builder name(String val) {
    +            this.name = val; return this;
    +        }
    +        public Builder status(AttributeSensor<Boolean> val) {
    +            this.status = val; return this;
    +        }
    +        public Builder configuration(Map<String,AttributeSensor<?>> val) {
    +            this.configuration = val; return this;
    +        }
    +        public Builder catalogId(String val) {
    +            this.catalogId = val; return this;
    +        }
    +        public Builder displayName(String val) {
    +            this.displayName = val; return this;
    +        }
    +        public Builder type(String val) {
    +            this.type = val; return this;
    +        }
    +        public Builder tags(Set<String> val) {
    +            this.tags = val; return this;
    +        }
    +        public CreateLocationPolicy build() {
    +            return new CreateLocationPolicy(toFlags());
    +        }
    +        public PolicySpec<CreateLocationPolicy> buildSpec() {
    +            return PolicySpec.create(CreateLocationPolicy.class)
    +                    .configure(toFlags());
    +        }
    +        private Map<String,?> toFlags() {
    +            return MutableMap.<String,Object>builder()
    +                    .putIfNotNull("id", id)
    +                    .putIfNotNull("name", name)
    +                    .putIfNotNull("location.status", status)
    +                    .putIfNotNull("location.config", configuration)
    +                    .putIfNotNull("location.catalogId", catalogId)
    +                    .putIfNotNull("location.displayName", displayName)
    +                    .putIfNotNull("location.type", type)
    +                    .putIfNotNull("location.tags", tags)
    +                    .build();
    +        }
    +    }
    +
    +    @SuppressWarnings("serial")
    +    public static final ConfigKey<AttributeSensor<Boolean>> LOCATION_STATUS = ConfigKeys.builder(new TypeToken<AttributeSensor<Boolean>>() {})
    +            .name("location.status")
    +            .description("Sensor on the entity to trigger location creation; defaults to service.isUp")
    +            .defaultValue(Startable.SERVICE_UP)
    +            .build();
    +
    +    @SuppressWarnings("serial")
    +    public static final ConfigKey<Map<String,AttributeSensor<?>>> LOCATION_CONFIG = ConfigKeys.builder(new TypeToken<Map<String,AttributeSensor<?>>>() {})
    +            .name("location.config")
    +            .description("Map of location configuration keys to sensors on the entity that provide their values")
    +            .defaultValue(ImmutableMap.of())
    +            .build();
    +
    +    public static final ConfigKey<String> LOCATION_CATALOG_ID = ConfigKeys.builder(String.class)
    +            .name("location.catalogId")
    +            .description("The catalog item ID to use for the created location")
    +            .constraint(Predicates.notNull())
    +            .build();
    +
    +    public static final ConfigKey<String> LOCATION_DISPLAY_NAME = ConfigKeys.builder(String.class)
    +            .name("location.displayName")
    +            .description("The display name for the created location")
    +            .constraint(Predicates.notNull())
    +            .build();
    +
    +    public static final ConfigKey<String> LOCATION_TYPE = ConfigKeys.builder(String.class)
    +            .name("location.type")
    +            .description("The type of location to create, i.e. 'jclouds:aws-ec2'")
    +            .constraint(Predicates.notNull())
    +            .build();
    +
    +    @SuppressWarnings("serial")
    +    public static final ConfigKey<Set<String>> LOCATION_TAGS = ConfigKeys.builder(new TypeToken<Set<String>>() {})
    +            .name("location.tags")
    +            .description("Tags for the created location")
    +            .defaultValue(ImmutableSet.of())
    +            .build();
    +
    +    private AtomicBoolean created = new AtomicBoolean(false);
    +    private Object mutex = new Object[0];
    +    private CatalogItem<?,?> catalogItem;
    +    private AtomicInteger version = new AtomicInteger(0);
    +
    +    public CreateLocationPolicy() {
    +        this(MutableMap.<String,Object>of());
    +    }
    +
    +    public CreateLocationPolicy(Map<String,?> props) {
    +        super(props);
    +    }
    +
    +    protected AttributeSensor<Boolean> getStatusSensor() {
    +        return config().get(LOCATION_STATUS);
    +    }
    +
    +    protected Map<String,AttributeSensor<?>> getLocationConfiguration() {
    +        return config().get(LOCATION_CONFIG);
    +    }
    +
    +    protected String getLocationCatalogItemId() {
    +        return config().get(LOCATION_CATALOG_ID);
    +    }
    +
    +    protected String getLocationDisplayName() {
    +        return config().get(LOCATION_DISPLAY_NAME);
    +    }
    +
    +    protected String getLocationType() {
    +        return config().get(LOCATION_TYPE);
    +    }
    +
    +    protected Set<String> getLocationTags() {
    +        return config().get(LOCATION_TAGS);
    +    }
    +
    +    @Override
    +    protected <T> void doReconfigureConfig(ConfigKey<T> key, T val) {
    +        throw new UnsupportedOperationException("reconfiguring "+key+" unsupported for "+this);
    +    }
    +
    +    private final SensorEventListener<Boolean> lifecycleEventHandler = new SensorEventListener<Boolean>() {
    +        @Override
    +        public void onEvent(SensorEvent<Boolean> event) {
    +            synchronized (mutex) {
    +                Boolean status = event.getValue();
    +                if (status) {
    --- End diff --
    
    `if (Boolean.TRUE.equals(status))`


---

[GitHub] brooklyn-server pull request #750: Adds a policy to create locations from an...

Posted by aledsage <gi...@git.apache.org>.
Github user aledsage commented on a diff in the pull request:

    https://github.com/apache/brooklyn-server/pull/750#discussion_r138606936
  
    --- Diff: policy/src/main/java/org/apache/brooklyn/policy/location/CreateLocationPolicy.java ---
    @@ -0,0 +1,288 @@
    +/*
    + * Licensed to the Apache Software Foundation (ASF) under one
    + * or more contributor license agreements.  See the NOTICE file
    + * distributed with this work for additional information
    + * regarding copyright ownership.  The ASF licenses this file
    + * to you under the Apache License, Version 2.0 (the
    + * "License"); you may not use this file except in compliance
    + * with the License.  You may obtain a copy of the License at
    + *
    + *     http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing,
    + * software distributed under the License is distributed on an
    + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + * KIND, either express or implied.  See the License for the
    + * specific language governing permissions and limitations
    + * under the License.
    + */
    +package org.apache.brooklyn.policy.location;
    +
    +import java.util.Map;
    +import java.util.NoSuchElementException;
    +import java.util.Set;
    +import java.util.concurrent.atomic.AtomicBoolean;
    +import java.util.concurrent.atomic.AtomicInteger;
    +
    +import org.apache.brooklyn.api.catalog.CatalogItem;
    +import org.apache.brooklyn.api.entity.EntityLocal;
    +import org.apache.brooklyn.api.policy.PolicySpec;
    +import org.apache.brooklyn.api.sensor.AttributeSensor;
    +import org.apache.brooklyn.api.sensor.SensorEvent;
    +import org.apache.brooklyn.api.sensor.SensorEventListener;
    +import org.apache.brooklyn.config.ConfigKey;
    +import org.apache.brooklyn.core.config.ConfigKeys;
    +import org.apache.brooklyn.core.entity.trait.Startable;
    +import org.apache.brooklyn.core.policy.AbstractPolicy;
    +import org.apache.brooklyn.util.collections.MutableMap;
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +
    +import com.google.common.annotations.Beta;
    +import com.google.common.base.Joiner;
    +import com.google.common.base.Predicates;
    +import com.google.common.collect.ImmutableList;
    +import com.google.common.collect.ImmutableMap;
    +import com.google.common.collect.ImmutableSet;
    +import com.google.common.collect.Iterables;
    +import com.google.common.reflect.TypeToken;
    +
    +/**
    + * Policy that is attached to an entity to create a location configured
    + * using its sensor data. The created location is added to the catalog
    + * and will be removed when the entity is no longer running, based on
    + * the entity {@link Startable#SERVICE_UP} sensor status.
    + * <p>
    + * The policy definition includes configuration for the id, name and
    + * type of the location, as well as the {@link #LOCATION_CONFIG} map
    + * of config keys and the sensors used to define them.
    + * <p>
    + * The YAML below shows a policy that creates a {@code jclouds:aws-ec2}
    + * location with the region defined by a sensor on the entity it is
    + * attached to:
    + * <pre>{@code
    + * name: My App
    + * brooklyn.policies:
    + *   - type: org.apache.brooklyn.policy.location.CreateLocationPolicy
    + *     id: create-my-cloud-location
    + *     brooklyn.config:
    + *       location.catalogId: my-cloud
    + *       location.displayName: "My Cloud"
    + *       location.type: jclouds:aws-ec2
    + *       location.config:
    + *         region: $brooklyn:sensor("aws.region")
    + * }</pre>
    + *
    + */
    +@Beta
    +public class CreateLocationPolicy extends AbstractPolicy {
    +
    +    private static final Logger LOG = LoggerFactory.getLogger(CreateLocationPolicy.class);
    +
    +    public static Builder builder() {
    +        return new Builder();
    +    }
    +
    +    public static class Builder {
    +        private String id;
    +        private String name;
    +        private AttributeSensor<Boolean> status;
    +        private Map<String,AttributeSensor<?>> configuration;
    +        private String catalogId;
    +        private String displayName;
    +        private String type;
    +        private Set<String> tags;
    +
    +        public Builder id(String val) {
    +            this.id = val; return this;
    +        }
    +        public Builder name(String val) {
    +            this.name = val; return this;
    +        }
    +        public Builder status(AttributeSensor<Boolean> val) {
    +            this.status = val; return this;
    +        }
    +        public Builder configuration(Map<String,AttributeSensor<?>> val) {
    +            this.configuration = val; return this;
    +        }
    +        public Builder catalogId(String val) {
    +            this.catalogId = val; return this;
    +        }
    +        public Builder displayName(String val) {
    +            this.displayName = val; return this;
    +        }
    +        public Builder type(String val) {
    +            this.type = val; return this;
    +        }
    +        public Builder tags(Set<String> val) {
    +            this.tags = val; return this;
    +        }
    +        public CreateLocationPolicy build() {
    +            return new CreateLocationPolicy(toFlags());
    --- End diff --
    
    Delete this `build` method - folk should always use the `PolicySpec`. I'd probably go further and delete the builder entirely, relying on using the standard `PolicySpec` as the way to build it.


---

[GitHub] brooklyn-server issue #750: Adds a policy to create locations from an entity

Posted by tbouron <gi...@git.apache.org>.
Github user tbouron commented on the issue:

    https://github.com/apache/brooklyn-server/pull/750
  
    @grkvlt Could you look at @aledsage comments please? Would be great to merge this PR 👍 


---