You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by ha...@apache.org on 2015/08/14 05:42:47 UTC
[18/54] incubator-brooklyn git commit: [BROOKLYN-162] Renaming
package brooklyn.location
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java
deleted file mode 100644
index d555cd9..0000000
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.location.jclouds;
-
-import static brooklyn.util.JavaGroovyEquivalents.groovyTruth;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Iterator;
-import java.util.Set;
-
-import org.jclouds.compute.domain.NodeMetadata;
-import org.jclouds.compute.domain.Template;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.location.basic.WinRmMachineLocation;
-import brooklyn.util.flags.SetFromFlag;
-import brooklyn.util.net.Networking;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Optional;
-import com.google.common.net.HostAndPort;
-
-public class JcloudsWinRmMachineLocation extends WinRmMachineLocation implements JcloudsMachineLocation {
-
- private static final Logger LOG = LoggerFactory.getLogger(JcloudsWinRmMachineLocation.class);
-
- @SetFromFlag
- JcloudsLocation jcloudsParent;
-
- @SetFromFlag
- NodeMetadata node;
-
- @SetFromFlag
- Template template;
-
- public JcloudsWinRmMachineLocation() {
- }
-
- @Override
- public String toVerboseString() {
- return Objects.toStringHelper(this).omitNullValues()
- .add("id", getId()).add("name", getDisplayName())
- .add("user", getUser())
- .add("address", getAddress())
- .add("port", getPort())
- .add("node", getNode())
- .add("jcloudsId", getJcloudsId())
- .add("privateAddresses", node.getPrivateAddresses())
- .add("publicAddresses", node.getPublicAddresses())
- .add("parentLocation", getParent())
- .add("osDetails", getOsDetails())
- .toString();
- }
-
- @Override
- public int getPort() {
- return getConfig(WINRM_PORT);
- }
-
- @Override
- public NodeMetadata getNode() {
- return node;
- }
-
- @Override
- public Template getTemplate() {
- return template;
- }
-
- @Override
- public JcloudsLocation getParent() {
- return jcloudsParent;
- }
-
- @Override
- public String getHostname() {
- InetAddress address = getAddress();
- return (address != null) ? address.getHostAddress() : null;
- }
-
- @Override
- public Set<String> getPublicAddresses() {
- return node.getPublicAddresses();
- }
-
- @Override
- public Set<String> getPrivateAddresses() {
- return node.getPrivateAddresses();
- }
-
- @Override
- public String getSubnetHostname() {
- // TODO: TEMP FIX: WAS:
- // String publicHostname = jcloudsParent.getPublicHostname(node, Optional.<HostAndPort>absent(), config().getBag());
- // but this causes a call to JcloudsUtil.getFirstReachableAddress, which searches for accessible SSH service.
- // This workaround is good for public nodes but not private-subnet ones.
- return getHostname();
- }
-
- @Override
- public String getSubnetIp() {
- Optional<String> privateAddress = getPrivateAddress();
- if (privateAddress.isPresent()) {
- return privateAddress.get();
- }
-
- String hostname = jcloudsParent.getPublicHostname(node, Optional.<HostAndPort>absent(), config().getBag());
- if (hostname != null && !Networking.isValidIp4(hostname)) {
- try {
- return InetAddress.getByName(hostname).getHostAddress();
- } catch (UnknownHostException e) {
- LOG.debug("Cannot resolve IP for hostname {} of machine {} (so returning hostname): {}", new Object[] {hostname, this, e});
- }
- }
- return hostname;
- }
-
- protected Optional<String> getPrivateAddress() {
- if (groovyTruth(node.getPrivateAddresses())) {
- Iterator<String> pi = node.getPrivateAddresses().iterator();
- while (pi.hasNext()) {
- String p = pi.next();
- // disallow local only addresses
- if (Networking.isLocalOnly(p)) continue;
- // other things may be public or private, but either way, return it
- return Optional.of(p);
- }
- }
- return Optional.absent();
- }
-
- @Override
- public String getJcloudsId() {
- return node.getId();
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java
deleted file mode 100644
index 889c7e3..0000000
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.location.jclouds;
-
-import org.jclouds.compute.ComputeService;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Preconditions;
-
-import brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.ssh.SshTasks;
-import brooklyn.util.task.ssh.SshTasks.OnFailingTask;
-
-/**
- * Wraps Brooklyn's sudo-tty mitigations in a {@link JcloudsLocationCustomizer} for easy(-ish) consumption
- * in YAML blueprints:
- *
- * <pre>
- * name: My App
- * brooklyn.config:
- * provisioning.properties:
- * customizerType: brooklyn.location.jclouds.SudoTtyFixingCustomizer
- * services: ...
- * </pre>
- *
- * <p>This class should be seen as a temporary workaround and might disappear completely if/when Brooklyn takes care of this automatically.
- *
- * <p>See
- * <a href='http://unix.stackexchange.com/questions/122616/why-do-i-need-a-tty-to-run-sudo-if-i-can-sudo-without-a-password'>http://unix.stackexchange.com/questions/122616/why-do-i-need-a-tty-to-run-sudo-if-i-can-sudo-without-a-password</a>
- * for background.
- */
-@Beta
-public class SudoTtyFixingCustomizer extends BasicJcloudsLocationCustomizer {
-
- @Override
- public void customize(JcloudsLocation location, ComputeService computeService, JcloudsMachineLocation machine) {
- Preconditions.checkArgument(machine instanceof SshMachineLocation, "machine must be SshMachineLocation, but is %s", machine.getClass());
- DynamicTasks.queueIfPossible(SshTasks.dontRequireTtyForSudo((SshMachineLocation)machine, OnFailingTask.FAIL)).orSubmitAndBlock();
- DynamicTasks.waitForLast();
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java
deleted file mode 100644
index 3944912..0000000
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java
+++ /dev/null
@@ -1,561 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.location.jclouds.networking;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.Iterator;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.jclouds.aws.AWSResponseException;
-import org.jclouds.compute.ComputeService;
-import org.jclouds.compute.domain.SecurityGroup;
-import org.jclouds.compute.domain.Template;
-import org.jclouds.compute.extensions.SecurityGroupExtension;
-import org.jclouds.domain.Location;
-import org.jclouds.net.domain.IpPermission;
-import org.jclouds.net.domain.IpProtocol;
-import org.jclouds.providers.ProviderMetadata;
-import org.jclouds.providers.Providers;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.location.geo.LocalhostExternalIpLoader;
-import brooklyn.location.jclouds.BasicJcloudsLocationCustomizer;
-import brooklyn.location.jclouds.JcloudsLocation;
-import brooklyn.location.jclouds.JcloudsMachineLocation;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.net.Cidr;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.time.Duration;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
-import com.google.common.base.Optional;
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.base.Throwables;
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-
-/**
- * Configures custom security groups on Jclouds locations.
- *
- * @see SecurityGroupExtension is an optional extension to jclouds compute service. It allows the manipulation of
- * {@link SecurityGroup}s.
- *
- * This customizer can be injected into {@link JcloudsLocation#obtainOnce} using
- * It will be executed after the provisiioning of the {@link JcloudsMachineLocation} to apply app-specific
- * customization related to the security groups.
- *
- * @since 0.7.0
- */
-@Beta
-public class JcloudsLocationSecurityGroupCustomizer extends BasicJcloudsLocationCustomizer {
-
- private static final Logger LOG = LoggerFactory.getLogger(JcloudsLocationSecurityGroupCustomizer.class);
-
- // Caches instances of JcloudsLocationSecurityGroupCustomizer by application IDs.
- private static final LoadingCache<String, JcloudsLocationSecurityGroupCustomizer> CUSTOMISERS = CacheBuilder.newBuilder()
- .build(new CacheLoader<String, JcloudsLocationSecurityGroupCustomizer>() {
- @Override
- public JcloudsLocationSecurityGroupCustomizer load(final String appContext) throws Exception {
- return new JcloudsLocationSecurityGroupCustomizer(appContext);
- }
- });
-
- /** Caches the base security group that should be shared between all instances in the same Jclouds location */
- private final Cache<Location, SecurityGroup> sharedGroupCache = CacheBuilder.newBuilder().build();
-
- /** Caches security groups unique to instances */
- private final Cache<String, SecurityGroup> uniqueGroupCache = CacheBuilder.newBuilder().build();
-
- /** The context for this location customizer. */
- private final String applicationId;
-
- /** The CIDR for addresses that may SSH to machines. */
- private Supplier<Cidr> sshCidrSupplier;
-
- /**
- * A predicate indicating whether the customiser can retry a request to add a security group
- * or a rule after an throwable is thrown.
- */
- private Predicate<Exception> isExceptionRetryable = Predicates.alwaysFalse();
-
- protected JcloudsLocationSecurityGroupCustomizer(String applicationId) {
- // Would be better to restrict with something like LocalhostExternalIpCidrSupplier, but
- // we risk making machines inaccessible from Brooklyn when HA fails over.
- this(applicationId, Suppliers.ofInstance(new Cidr("0.0.0.0/0")));
- }
-
- protected JcloudsLocationSecurityGroupCustomizer(String applicationId, Supplier<Cidr> sshCidrSupplier) {
- this.applicationId = applicationId;
- this.sshCidrSupplier = sshCidrSupplier;
- }
-
- /**
- * Gets the customizer for the given applicationId. Multiple calls to this method with the
- * same application context will return the same JcloudsLocationSecurityGroupCustomizer instance.
- * @param applicationId An identifier for the application the customizer is to be used for
- * @return the unique customizer for the given context
- */
- public static JcloudsLocationSecurityGroupCustomizer getInstance(String applicationId) {
- return CUSTOMISERS.getUnchecked(applicationId);
- }
-
- /**
- * Gets a customizer for the given entity's application. Multiple calls to this method with entities
- * in the same application will return the same JcloudsLocationSecurityGroupCustomizer instance.
- * @param entity The entity the customizer is to be used for
- * @return the unique customizer for the entity's owning application
- */
- public static JcloudsLocationSecurityGroupCustomizer getInstance(Entity entity) {
- return getInstance(entity.getApplicationId());
- }
-
- /**
- * @param predicate
- * A predicate whose return value indicates whether a request to add a security group
- * or permission may be retried after its input {@link Exception} was thrown.
- * @return this
- */
- public JcloudsLocationSecurityGroupCustomizer setRetryExceptionPredicate(Predicate<Exception> predicate) {
- this.isExceptionRetryable = checkNotNull(predicate, "predicate");
- return this;
- }
-
- /**
- * @param cidrSupplier A supplier returning a CIDR for hosts that are allowed to SSH to locations.
- */
- public JcloudsLocationSecurityGroupCustomizer setSshCidrSupplier(Supplier<Cidr> cidrSupplier) {
- this.sshCidrSupplier = checkNotNull(cidrSupplier, "cidrSupplier");
- return this;
- }
-
- /** @see #addPermissionsToLocation(brooklyn.location.jclouds.JcloudsSshMachineLocation, java.lang.Iterable) */
- public JcloudsLocationSecurityGroupCustomizer addPermissionsToLocation(final JcloudsMachineLocation location, IpPermission... permissions) {
- addPermissionsToLocation(location, ImmutableList.copyOf(permissions));
- return this;
- }
-
- /** @see #addPermissionsToLocation(brooklyn.location.jclouds.JcloudsSshMachineLocation, java.lang.Iterable) */
- public JcloudsLocationSecurityGroupCustomizer addPermissionsToLocation(final JcloudsMachineLocation location, SecurityGroupDefinition securityGroupDefinition) {
- addPermissionsToLocation(location, securityGroupDefinition.getPermissions());
- return this;
- }
-
- /**
- * Applies the given security group permissions to the given location.
- * <p>
- * Takes no action if the location's compute service does not have a security group extension.
- * @param permissions The set of permissions to be applied to the location
- * @param location Location to gain permissions
- */
- public JcloudsLocationSecurityGroupCustomizer addPermissionsToLocation(final JcloudsMachineLocation location, final Iterable<IpPermission> permissions) {
- ComputeService computeService = location.getParent().getComputeService();
- String nodeId = location.getNode().getId();
- addPermissionsToLocation(permissions, nodeId, computeService);
- return this;
- }
-
- /**
- * Applies the given security group permissions to the given node with the given compute service.
- * <p>
- * Takes no action if the compute service does not have a security group extension.
- * @param permissions The set of permissions to be applied to the node
- * @param nodeId The id of the node to update
- * @param computeService The compute service to use to apply the changes
- */
- @VisibleForTesting
- void addPermissionsToLocation(Iterable<IpPermission> permissions, final String nodeId, ComputeService computeService) {
- if (!computeService.getSecurityGroupExtension().isPresent()) {
- LOG.warn("Security group extension for {} absent; cannot update node {} with {}",
- new Object[] {computeService, nodeId, permissions});
- return;
- }
- final SecurityGroupExtension securityApi = computeService.getSecurityGroupExtension().get();
- final String locationId = computeService.getContext().unwrap().getId();
-
- // Expect to have two security groups on the node: one shared between all nodes in the location,
- // that is cached in sharedGroupCache, and one created by Jclouds that is unique to the node.
- // Relies on customize having been called before. This should be safe because the arguments
- // needed to call this method are not available until post-instance creation.
- SecurityGroup machineUniqueSecurityGroup;
- Tasks.setBlockingDetails("Loading unique security group for node: " + nodeId);
- try {
- machineUniqueSecurityGroup = uniqueGroupCache.get(nodeId, new Callable<SecurityGroup>() {
- @Override public SecurityGroup call() throws Exception {
- SecurityGroup sg = getUniqueSecurityGroupForNodeCachingSharedGroupIfPreviouslyUnknown(nodeId, locationId, securityApi);
- if (sg == null) {
- throw new IllegalStateException("Failed to find machine-unique group on node: " + nodeId);
- }
- return sg;
- }
- });
- } catch (ExecutionException e) {
- throw Throwables.propagate(new Exception(e.getCause()));
- } finally {
- Tasks.resetBlockingDetails();
- }
- for (IpPermission permission : permissions) {
- addPermission(permission, machineUniqueSecurityGroup, securityApi);
- }
- }
-
- /**
- * Loads the security groups attached to the node with the given ID and returns the group
- * that is unique to the node, per the application context. This method will also update
- * {@link #sharedGroupCache} if no mapping for the shared group's location previously
- * existed (e.g. Brooklyn was restarted and rebound to an existing application).
- *
- * Notice that jclouds will attach 2 securityGroups to the node if the locationId is `aws-ec2` so it needs to
- * look for the uniqueSecurityGroup rather than the shared securityGroup.
- *
- * @param nodeId The id of the node in question
- * @param locationId The id of the location in question
- * @param securityApi The API to use to list security groups
- * @return the security group unique to the given node, or null if one could not be determined.
- */
- private SecurityGroup getUniqueSecurityGroupForNodeCachingSharedGroupIfPreviouslyUnknown(String nodeId, String locationId, SecurityGroupExtension securityApi) {
- Set<SecurityGroup> groupsOnNode = securityApi.listSecurityGroupsForNode(nodeId);
- SecurityGroup unique;
- if (locationId.equals("aws-ec2")) {
- if (groupsOnNode.size() != 2) {
- LOG.warn("Expected to find two security groups on node {} in app {} (one shared, one unique). Found {}: {}",
- new Object[]{nodeId, applicationId, groupsOnNode.size(), groupsOnNode});
- return null;
- }
- String expectedSharedName = getNameForSharedSecurityGroup();
- Iterator<SecurityGroup> it = groupsOnNode.iterator();
- SecurityGroup shared = it.next();
- if (shared.getName().endsWith(expectedSharedName)) {
- unique = it.next();
- } else {
- unique = shared;
- shared = it.next();
- }
- if (!shared.getName().endsWith(expectedSharedName)) {
- LOG.warn("Couldn't determine which security group is shared between instances in app {}. Expected={}, found={}",
- new Object[]{applicationId, expectedSharedName, groupsOnNode});
- return null;
- }
- // Shared entry might be missing if Brooklyn has rebound to an application
- SecurityGroup old = sharedGroupCache.asMap().putIfAbsent(shared.getLocation(), shared);
- LOG.info("Loaded unique security group for node {} (in {}): {}",
- new Object[]{nodeId, applicationId, unique});
- if (old == null) {
- LOG.info("Proactively set shared group for app {} to: {}", applicationId, shared);
- }
- return unique;
- }
- return Iterables.getOnlyElement(groupsOnNode);
- }
-
- /**
- * Replaces security groups configured on the given template with one that allows
- * SSH access on port 22 and allows communication on all ports between machines in
- * the same group. Security groups are reused when templates have equal
- * {@link org.jclouds.compute.domain.Template#getLocation locations}.
- * <p>
- * This method is called by Brooklyn when obtaining machines, as part of the
- * {@link brooklyn.location.jclouds.JcloudsLocationCustomizer} contract. It
- * should not be called from anywhere else.
- *
- * @param location The Brooklyn location that has called this method while obtaining a machine
- * @param computeService The compute service being used by the location argument to provision a machine
- * @param template The machine template created by the location argument
- */
- @Override
- public void customize(JcloudsLocation location, ComputeService computeService, Template template) {
- if (!computeService.getSecurityGroupExtension().isPresent()) {
- LOG.warn("Security group extension for {} absent; cannot configure security groups in context: {}", computeService, applicationId);
- } else if (template.getLocation() == null) {
- LOG.warn("No location has been set on {}; cannot configure security groups in context: {}", template, applicationId);
- } else {
- LOG.info("Configuring security groups on location {} in context {}", location, applicationId);
- setSecurityGroupOnTemplate(location, template, computeService.getSecurityGroupExtension().get());
- }
- }
-
- private void setSecurityGroupOnTemplate(final JcloudsLocation location, final Template template, final SecurityGroupExtension securityApi) {
- SecurityGroup shared;
- Tasks.setBlockingDetails("Loading security group shared by instances in " + template.getLocation() +
- " in app " + applicationId);
- try {
- shared = sharedGroupCache.get(template.getLocation(), new Callable<SecurityGroup>() {
- @Override public SecurityGroup call() throws Exception {
- return getOrCreateSharedSecurityGroup(template.getLocation(), securityApi);
- }
- });
- } catch (ExecutionException e) {
- throw Throwables.propagate(new Exception(e.getCause()));
- } finally {
- Tasks.resetBlockingDetails();
- }
-
- Set<String> originalGroups = template.getOptions().getGroups();
- template.getOptions().securityGroups(shared.getName());
- if (!originalGroups.isEmpty()) {
- LOG.info("Replaced configured security groups: configured={}, replaced with={}", originalGroups, template.getOptions().getGroups());
- } else {
- LOG.debug("Configured security groups at {} to: {}", location, template.getOptions().getGroups());
- }
- }
-
- /**
- * Loads the security group to be shared between nodes in the same application in the
- * given Location. If no such security group exists it is created.
- *
- * @param location The location in which the security group will be found
- * @param securityApi The API to use to list and create security groups
- * @return the security group to share between instances in the given location in this application
- */
- private SecurityGroup getOrCreateSharedSecurityGroup(Location location, SecurityGroupExtension securityApi) {
- final String groupName = getNameForSharedSecurityGroup();
- // Could sort-and-search if straight search is too expensive
- Optional<SecurityGroup> shared = Iterables.tryFind(securityApi.listSecurityGroupsInLocation(location), new Predicate<SecurityGroup>() {
- @Override
- public boolean apply(final SecurityGroup input) {
- // endsWith because Jclouds prepends 'jclouds#' to security group names.
- return input.getName().endsWith(groupName);
- }
- });
- if (shared.isPresent()) {
- LOG.info("Found existing shared security group in {} for app {}: {}",
- new Object[]{location, applicationId, groupName});
- return shared.get();
- } else {
- LOG.info("Creating new shared security group in {} for app {}: {}",
- new Object[]{location, applicationId, groupName});
- return createBaseSecurityGroupInLocation(groupName, location, securityApi);
- }
- }
-
- /**
- * Creates a security group with rules to:
- * <ul>
- * <li>Allow SSH access on port 22 from the world</li>
- * <li>Allow TCP, UDP and ICMP communication between machines in the same group</li>
- * </ul>
- *
- * It needs to consider locationId as port ranges and groupId are cloud provider-dependent e.g openstack nova
- * wants from 1-65535 while aws-ec2 accepts from 0-65535.
- *
- *
- * @param groupName The name of the security group to create
- * @param location The location in which the security group will be created
- * @param securityApi The API to use to create the security group
- *
- * @return the created security group
- */
- private SecurityGroup createBaseSecurityGroupInLocation(String groupName, Location location, SecurityGroupExtension securityApi) {
- SecurityGroup group = addSecurityGroupInLocation(groupName, location, securityApi);
-
- Set<String> openstackNovaIds = getJcloudsLocationIds("openstack-nova");
-
- String groupId = group.getProviderId();
- int fromPort = 0;
- if (location.getParent() != null && Iterables.contains(openstackNovaIds, location.getParent().getId())) {
- groupId = group.getId();
- fromPort = 1;
- }
- // Note: For groupName to work with GCE we also need to tag the machines with the same ID.
- // See sourceTags section at https://developers.google.com/compute/docs/networking#firewalls
- IpPermission.Builder allWithinGroup = IpPermission.builder()
- .groupId(groupId)
- .fromPort(fromPort)
- .toPort(65535);
- addPermission(allWithinGroup.ipProtocol(IpProtocol.TCP).build(), group, securityApi);
- addPermission(allWithinGroup.ipProtocol(IpProtocol.UDP).build(), group, securityApi);
- addPermission(allWithinGroup.ipProtocol(IpProtocol.ICMP).fromPort(-1).toPort(-1).build(), group, securityApi);
-
- IpPermission sshPermission = IpPermission.builder()
- .fromPort(22)
- .toPort(22)
- .ipProtocol(IpProtocol.TCP)
- .cidrBlock(getBrooklynCidrBlock())
- .build();
- addPermission(sshPermission, group, securityApi);
-
- return group;
- }
-
- private Set<String> getJcloudsLocationIds(final String jcloudsApiId) {
- Set<String> openstackNovaProviders = FluentIterable.from(Providers.all())
- .filter(new Predicate<ProviderMetadata>() {
- @Override
- public boolean apply(ProviderMetadata providerMetadata) {
- return providerMetadata.getApiMetadata().getId().equals(jcloudsApiId);
- }
- }).transform(new Function<ProviderMetadata, String>() {
- @Nullable
- @Override
- public String apply(ProviderMetadata input) {
- return input.getId();
- }
- }).toSet();
-
- return new ImmutableSet.Builder<String>()
- .addAll(openstackNovaProviders)
- .add(jcloudsApiId)
- .build();
- }
-
- protected SecurityGroup addSecurityGroupInLocation(final String groupName, final Location location, final SecurityGroupExtension securityApi) {
- LOG.debug("Creating security group {} in {}", groupName, location);
- Callable<SecurityGroup> callable = new Callable<SecurityGroup>() {
- @Override
- public SecurityGroup call() throws Exception {
- return securityApi.createSecurityGroup(groupName, location);
- }
- };
- return runOperationWithRetry(callable);
- }
-
- protected SecurityGroup addPermission(final IpPermission permission, final SecurityGroup group, final SecurityGroupExtension securityApi) {
- LOG.debug("Adding permission to security group {}: {}", group.getName(), permission);
- Callable<SecurityGroup> callable = new Callable<SecurityGroup>() {
- @Override
- public SecurityGroup call() throws Exception {
- return securityApi.addIpPermission(permission, group);
- }
- };
- return runOperationWithRetry(callable);
- }
-
- /** @return the CIDR block used to configure Brooklyn's in security groups */
- public String getBrooklynCidrBlock() {
- return sshCidrSupplier.get().toString();
- }
-
- /**
- * @return The name to be used by security groups that will be shared between machines
- * in the same location for this instance's application context.
- */
- @VisibleForTesting
- String getNameForSharedSecurityGroup() {
- return "brooklyn-" + applicationId.toLowerCase() + "-shared";
- }
-
- /**
- * Invalidates all entries in {@link #sharedGroupCache} and {@link #uniqueGroupCache}.
- * Use to simulate the effects of rebinding Brooklyn to a deployment.
- */
- @VisibleForTesting
- void clearSecurityGroupCaches() {
- LOG.info("Clearing security group caches");
- sharedGroupCache.invalidateAll();
- uniqueGroupCache.invalidateAll();
- }
-
- /**
- * Runs the given callable. Repeats until the operation succeeds or {@link #isExceptionRetryable} indicates
- * that the request cannot be retried.
- */
- protected <T> T runOperationWithRetry(Callable<T> operation) {
- int backoff = 64;
- Exception lastException = null;
- for (int retries = 0; retries < 100; retries++) {
- try {
- return operation.call();
- } catch (Exception e) {
- lastException = e;
- if (isExceptionRetryable.apply(e)) {
- LOG.debug("Attempt #{} failed to add security group: {}", retries + 1, e.getMessage());
- try {
- Thread.sleep(backoff);
- } catch (InterruptedException e1) {
- throw Exceptions.propagate(e1);
- }
- backoff = backoff << 1;
- } else {
- break;
- }
- }
- }
-
- throw new RuntimeException("Unable to add security group rule; repeated errors from provider", lastException);
- }
-
- /**
- * @return
- * A predicate that is true if an exception contains an {@link org.jclouds.aws.AWSResponseException}
- * whose error code is either <code>InvalidGroup.InUse</code>, <code>DependencyViolation</code> or
- * <code>RequestLimitExceeded</code>.
- */
- public static Predicate<Exception> newAwsExceptionRetryPredicate() {
- return new AwsExceptionRetryPredicate();
- }
-
- private static class AwsExceptionRetryPredicate implements Predicate<Exception> {
- // Error reference: http://docs.aws.amazon.com/AWSEC2/latest/APIReference/errors-overview.html
- private static final Set<String> AWS_ERRORS_TO_RETRY = ImmutableSet.of(
- "InvalidGroup.InUse", "DependencyViolation", "RequestLimitExceeded");
-
- @Override
- public boolean apply(Exception input) {
- @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
- AWSResponseException exception = Exceptions.getFirstThrowableOfType(input, AWSResponseException.class);
- if (exception != null) {
- String code = exception.getError().getCode();
- return AWS_ERRORS_TO_RETRY.contains(code);
- }
- return false;
- }
- }
-
- /**
- * A supplier of CIDRs that loads the external IP address of the localhost machine.
- */
- private static class LocalhostExternalIpCidrSupplier implements Supplier<Cidr> {
-
- private volatile Cidr cidr;
-
- @Override
- public Cidr get() {
- Cidr local = cidr;
- if (local == null) {
- synchronized (this) {
- local = cidr;
- if (local == null) {
- String externalIp = LocalhostExternalIpLoader.getLocalhostIpWithin(Duration.seconds(5));
- cidr = local = new Cidr(externalIp + "/32");
- }
- }
- }
- return local;
- }
-
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsPortForwarderExtension.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsPortForwarderExtension.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsPortForwarderExtension.java
deleted file mode 100644
index adfdde3..0000000
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/JcloudsPortForwarderExtension.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.location.jclouds.networking;
-
-import org.jclouds.compute.domain.NodeMetadata;
-
-import brooklyn.location.access.BrooklynAccessUtils;
-import brooklyn.location.access.PortForwardManager;
-import brooklyn.util.net.Cidr;
-import brooklyn.util.net.Protocol;
-
-import com.google.common.base.Optional;
-import com.google.common.net.HostAndPort;
-
-public interface JcloudsPortForwarderExtension {
-
- /**
- * Opens port forwarding (e.g. DNAT or iptables port-forwarding) to reach the given given
- * target port on this node (from the given cidr).
- *
- * This should also register the port with the {@link PortForwardManager}, via
- * {@code portForwardManager.associate(node.getId(), result, targetPort)} so that
- * subsequent calls to {@link BrooklynAccessUtils#getBrooklynAccessibleAddress(brooklyn.entity.Entity, int)}
- * will know about the mapped port.
- */
- public HostAndPort openPortForwarding(NodeMetadata node, int targetPort, Optional<Integer> optionalPublicPort, Protocol protocol, Cidr accessingCidr);
-
- public void closePortForwarding(NodeMetadata node, int targetPort, HostAndPort publicHostAndPort, Protocol protocol);
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/SecurityGroupDefinition.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/SecurityGroupDefinition.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/SecurityGroupDefinition.java
deleted file mode 100644
index 7ced79f..0000000
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/SecurityGroupDefinition.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.location.jclouds.networking;
-
-import java.util.List;
-import java.util.concurrent.Callable;
-
-import org.jclouds.aws.ec2.AWSEC2Api;
-import org.jclouds.compute.ComputeServiceContext;
-import org.jclouds.net.domain.IpPermission;
-import org.jclouds.net.domain.IpProtocol;
-import org.jclouds.net.util.IpPermissions;
-
-import brooklyn.util.collections.MutableList;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.net.Cidr;
-import brooklyn.util.text.Identifiers;
-
-import com.google.common.annotations.Beta;
-
-/** WIP to define a security group in an up-front way, where subsequently it can be applied to a jclouds location */
-@Beta
-public class SecurityGroupDefinition {
-
- private Callable<String> groupNameFactory = new Callable<String>() { public String call() { return "br-sg-"+Identifiers.makeRandomId(8); } };
- private List<IpPermission> ipPerms = MutableList.of();
-
- public void createGroupInAwsRegion(ComputeServiceContext computeServiceContext, String region) {
- AWSEC2Api ec2Client = computeServiceContext.unwrapApi(AWSEC2Api.class);
- String sgId = ec2Client.getSecurityGroupApi().get().createSecurityGroupInRegionAndReturnId(region, getName(), "Brooklyn-managed security group "+getName());
- ec2Client.getSecurityGroupApi().get().authorizeSecurityGroupIngressInRegion(region, sgId, ipPerms);
- }
-
- /** allows access to the given port on TCP from within the subnet */
- public SecurityGroupDefinition allowingInternalPort(int port) {
- return allowing(IpPermissions.permit(IpProtocol.TCP).port(port));
- }
- public SecurityGroupDefinition allowingInternalPorts(int port1, int port2, int ...ports) {
- allowing(IpPermissions.permit(IpProtocol.TCP).port(port1));
- allowing(IpPermissions.permit(IpProtocol.TCP).port(port2));
- for (int port: ports)
- allowing(IpPermissions.permit(IpProtocol.TCP).port(port));
- return this;
- }
- public SecurityGroupDefinition allowingInternalPortRange(int portRangeStart, int portRangeEnd) {
- return allowing(IpPermissions.permit(IpProtocol.TCP).fromPort(portRangeStart).to(portRangeEnd));
- }
- public SecurityGroupDefinition allowingInternalPing() {
- return allowing(IpPermissions.permit(IpProtocol.ICMP));
- }
-
- public SecurityGroupDefinition allowingPublicPort(int port) {
- return allowing(IpPermissions.permit(IpProtocol.TCP).port(port).originatingFromCidrBlock(Cidr.UNIVERSAL.toString()));
- }
- public SecurityGroupDefinition allowingPublicPorts(int port1, int port2, int ...ports) {
- allowing(IpPermissions.permit(IpProtocol.TCP).port(port1).originatingFromCidrBlock(Cidr.UNIVERSAL.toString()));
- allowing(IpPermissions.permit(IpProtocol.TCP).port(port2).originatingFromCidrBlock(Cidr.UNIVERSAL.toString()));
- for (int port: ports)
- allowing(IpPermissions.permit(IpProtocol.TCP).port(port).originatingFromCidrBlock(Cidr.UNIVERSAL.toString()));
- return this;
- }
- public SecurityGroupDefinition allowingPublicPortRange(int portRangeStart, int portRangeEnd) {
- return allowing(IpPermissions.permit(IpProtocol.TCP).fromPort(portRangeStart).to(portRangeEnd).originatingFromCidrBlock(Cidr.UNIVERSAL.toString()));
- }
- public SecurityGroupDefinition allowingPublicPing() {
- return allowing(IpPermissions.permit(IpProtocol.ICMP).originatingFromCidrBlock(Cidr.UNIVERSAL.toString()));
- }
-
- public SecurityGroupDefinition allowing(IpPermission permission) {
- ipPerms.add(permission);
- return this;
- }
-
- // TODO use cloud machine namer
- public SecurityGroupDefinition named(final String name) {
- groupNameFactory = new Callable<String>() { public String call() { return name; } };
- return this;
- }
- public String getName() {
- try { return groupNameFactory.call(); }
- catch (Exception e) { throw Exceptions.propagate(e); }
- }
-
- public Iterable<IpPermission> getPermissions() {
- return ipPerms;
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/SecurityGroupTool.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/SecurityGroupTool.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/SecurityGroupTool.java
deleted file mode 100644
index 31b06a0..0000000
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/networking/SecurityGroupTool.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.location.jclouds.networking;
-
-import java.util.Set;
-
-import org.jclouds.aws.ec2.AWSEC2Api;
-import org.jclouds.aws.util.AWSUtils;
-import org.jclouds.compute.domain.SecurityGroup;
-import org.jclouds.compute.extensions.SecurityGroupExtension;
-import org.jclouds.net.domain.IpPermission;
-import org.jclouds.rest.ApiContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.location.jclouds.JcloudsLocation;
-import brooklyn.location.jclouds.JcloudsLocationConfig;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.text.Strings;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-
-/** WIP to apply a security group to a jclouds endpoint.
- * <p>
- * sections of this code have been used but overall it is not yet in a working state,
- * but merged May 2014 to make it easier to pick up if and when needed.
- * (if not needed after several months this may simply be removed.) */
-@Beta
-public class SecurityGroupTool {
-
- private static final Logger log = LoggerFactory.getLogger(SecurityGroupTool.class);
-
- protected final JcloudsLocation location;
- protected final SecurityGroupDefinition sgDef;
-
- public SecurityGroupTool(JcloudsLocation location, SecurityGroupDefinition sgDef) {
- this.location = Preconditions.checkNotNull(location);
- this.sgDef = Preconditions.checkNotNull(sgDef);
- }
-
- public String getName() {
- return sgDef.getName();
- }
-
- public void apply() {
- Optional<SecurityGroupExtension> sgExtO = location.getComputeService().getSecurityGroupExtension();
- if (!sgExtO.isPresent()) {
- throw new IllegalStateException("Advanced networking not supported in this location ("+location+")");
- }
- SecurityGroupExtension sgExt = sgExtO.get();
-
- SecurityGroup sg = findSecurityGroupWithName(sgExt, getName());
- if (sg==null) {
- // TODO initialize the location
- org.jclouds.domain.Location sgLoc = null;
-
- // TODO record that we created it
- // create it
- try {
- // FIXME this will always fail for providers which need a location, until we set it above
- // https://github.com/brooklyncentral/brooklyn/pull/1343#discussion_r12275188
- sg = sgExt.createSecurityGroup(getName(), sgLoc);
- } catch (Exception e) {
- Exceptions.propagateIfFatal(e);
- // check if someone else already created it
- sg = findSecurityGroupWithName(sgExt, getName());
- if (sg==null) {
- // no - so propagate error
- throw Exceptions.propagate(e);
- } else {
- log.debug("Looks like parallel thread created security group "+getName()+"; ignoring error in our thread ("+e+") as we now have an SG");
- }
- }
- }
-
- if (sg==null)
- throw new IllegalStateException("Unable to find or create security group ID for "+getName());
-
- addPermissions(sgExt, sg);
- }
-
- protected SecurityGroup findSecurityGroupWithName(SecurityGroupExtension sgExt, String name) {
- Set<SecurityGroup> groups = sgExt.listSecurityGroups();
- // jclouds appends this sometimes so for portability let's add this
- String nameAlt = name.startsWith("jclouds#") ? Strings.removeFromStart(name, "jclouds#") : "jclouds#"+name;
- for (SecurityGroup g: groups) {
- if (name.equals(g.getName())) return g;
- if (nameAlt.equals(g.getName())) return g;
- }
- return null;
- }
-
- protected void addPermissions(SecurityGroupExtension sgExt, SecurityGroup sg) {
-
- Object api = ((ApiContext<?>)location.getComputeService().getContext().unwrap()).getApi();
- if (api instanceof AWSEC2Api) {
- // optimization for AWS where rules can be added all at once, and it cuts down Req Limit Exceeded problems!
- String region = AWSUtils.getRegionFromLocationOrNull(sg.getLocation());
- String id = sg.getProviderId();
-
- ((AWSEC2Api)api).getSecurityGroupApi().get().authorizeSecurityGroupIngressInRegion(region, id, sgDef.getPermissions());
-
- } else {
- for (IpPermission p: sgDef.getPermissions()) {
- sgExt.addIpPermission(p, sg);
- }
- }
- }
-
-
- // TODO remove this method once we've confirmed the above works nicely (this is an early attempt)
- protected void applyOldEc2(AWSEC2Api client) {
- String region = location.getConfig(JcloudsLocationConfig.CLOUD_REGION_ID);
- if (region==null) {
- // TODO where does the default come from?
- log.warn("No region set for "+location+"; assuming EC2");
- region = "us-east-1";
- }
-
- Set<org.jclouds.ec2.domain.SecurityGroup> groups = client.getSecurityGroupApi().get().describeSecurityGroupsInRegion(region, getName());
- String id = null;
- if (groups.isEmpty()) {
- // create it
- try {
- id = client.getSecurityGroupApi().get().createSecurityGroupInRegionAndReturnId(region , getName(), "Brooklyn-managed security group "+getName());
- } catch (Exception e) {
- Exceptions.propagateIfFatal(e);
- // check if someone else already created it!
- groups = client.getSecurityGroupApi().get().describeSecurityGroupsInRegion(region, getName());
- if (groups.isEmpty()) {
- // no - so propagate error
- throw Exceptions.propagate(e);
- } else {
- log.debug("Looks like parallel thread created security group "+getName()+"; ignoring error in our thread ("+e+") as we now have an SG");
- }
- }
- }
- if (!groups.isEmpty()) {
- if (groups.size()>1)
- log.warn("Multiple security groups matching '"+getName()+"' (using the first): "+groups);
- id = groups.iterator().next().getId();
- }
- if (id==null)
- throw new IllegalStateException("Unable to find or create security group ID for "+getName());
-
- client.getSecurityGroupApi().get().authorizeSecurityGroupIngressInRegion(region, id, sgDef.getPermissions());
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/brooklyn/location/jclouds/pool/MachinePool.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/pool/MachinePool.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/pool/MachinePool.java
deleted file mode 100644
index d2dcf80..0000000
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/pool/MachinePool.java
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.location.jclouds.pool;
-
-import static brooklyn.location.jclouds.pool.MachinePoolPredicates.compose;
-import static brooklyn.location.jclouds.pool.MachinePoolPredicates.matching;
-
-import java.util.ArrayList;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.jclouds.compute.ComputeService;
-import org.jclouds.compute.RunNodesException;
-import org.jclouds.compute.domain.ComputeMetadata;
-import org.jclouds.compute.domain.NodeMetadata;
-import org.jclouds.compute.domain.Template;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-
-/**
- * Contains details of machines detected at a given cloud (ComputeService),
- * and records claims made against those machines via this pool.
- * <p>
- * Machine instances themselves are persisted and rescanned as new instances of this class are created.
- * Claims however are specific to this instance of the class, i.e. <b>not</b> persisted.
- * <p>
- * This class is believed to be thread-safe.
- * Refreshes to the remote detected machines are synchronized on the pool instance.
- * Details of detected and claimed machines are also synchronized on the pool instance.
- * (If it is necessary to claim machines whilst the pool is being rescanned,
- * we can investigate a more sophisticated threading model.
- * Access to some fields is clearly independent and uses a tighter synchonization
- * strategy, e.g. templates.
- * Synchronization of fields within a synch block on the class instance
- * is permitted, but not the other way round,
- * and synching on multiple fields is also not permitted.)
- * <p>
- * Callers wishing to guarantee results of e.g. ensureUnclaimed remaining available
- * can synchronize on this class for the duration that they wish to have that guarantee
- * (at the cost, of course, of any other threads being able to access this pool).
- * <p>
- * If underlying provisioning/destroying operations fail, the pool
- * currently may be in an unknown state, currently.
- * If more robustness is needed this can be added.
- *
- * @deprecated since 0.6.0; never used in production setting, and thus of dubious value; best avoided as unlikely to be supported in future versions
- */
-@Deprecated
-public class MachinePool {
-
- private static final Logger log = LoggerFactory.getLogger(MachinePool.class);
-
- protected final ComputeService computeService;
- final AtomicBoolean refreshNeeded = new AtomicBoolean(true);
- final List<ReusableMachineTemplate> templates = new ArrayList<ReusableMachineTemplate>();
- String poolName = null;
-
- /** all machines detected, less those in the black list */
- volatile MachineSet detectedMachines = new MachineSet();
- volatile MachineSet matchedMachines = new MachineSet();
- volatile MachineSet claimedMachines = new MachineSet();
- volatile MachineSet blacklistedMachines = new MachineSet();
-
- public MachinePool(ComputeService computeService) {
- this.computeService = computeService;
- }
-
- protected synchronized void init() {
- if (!refreshNeeded.get()) return;
- refresh();
- }
-
- public void setPoolName(String poolName) {
- if (poolName!=null)
- log.warn("Changing pool name of "+this+" (from "+this.poolName+" to "+poolName+") is discouraged.");
- this.poolName = poolName;
- }
- /** pool name is used as a group/label by jclouds, for convenience only;
- * it has no special properties for detecting matching instances
- * (use explicit tags on the templates, for that).
- * defaults to name of pool class and user name.
- * callers should set pool name before getting, if using a custom name. */
- public synchronized String getPoolName() {
- if (poolName==null)
- poolName = getClass().getSimpleName()+"-"+System.getProperty("user.name");
- return poolName;
- }
-
- /** refreshes the pool of machines from the server (finding all instances matching the registered templates) */
- public synchronized void refresh() {
- refreshNeeded.set(false);
- Set<? extends ComputeMetadata> computes = computeService.listNodes();
- Set<NodeMetadata> nodes = new LinkedHashSet<NodeMetadata>();
- for (ComputeMetadata c: computes) {
- if (c instanceof NodeMetadata) {
- nodes.add((NodeMetadata)c);
- } else {
- // TODO should we try to fetch more info?
- log.warn("MachinePool "+this+" ignoring non-Node record for remote machine: "+c);
- }
- }
-
- MachineSet allNewDetectedMachines = new MachineSet(nodes);
- MachineSet newDetectedMachines = filterForAllowedMachines(allNewDetectedMachines);
- MachineSet oldDetectedMachines = detectedMachines;
- MachineSet newMatchedMachines = new MachineSet();
- detectedMachines = newDetectedMachines;
-
- MachineSet appearedMachinesIncludingBlacklist = allNewDetectedMachines.removed(oldDetectedMachines);
- MachineSet appearedMachines = filterForAllowedMachines(appearedMachinesIncludingBlacklist);
- if (appearedMachinesIncludingBlacklist.size()>appearedMachines.size())
- if (log.isDebugEnabled()) log.debug("Pool "+this+", ignoring "+(appearedMachinesIncludingBlacklist.size()-appearedMachines.size())+" disallowed");
- int matchedAppeared = 0;
- for (NodeMetadata m: appearedMachines) {
- if (m.getStatus() != NodeMetadata.Status.RUNNING) {
- if (log.isDebugEnabled())
- log.debug("Pool "+this+", newly detected machine "+m+", not running ("+m.getStatus()+")");
- } else {
- Set<ReusableMachineTemplate> ts = getTemplatesMatchingInstance(m);
- if (!ts.isEmpty()) {
- matchedAppeared++;
- newMatchedMachines = newMatchedMachines.added(new MachineSet(m));
- if (log.isDebugEnabled())
- log.debug("Pool "+this+", newly detected machine "+m+", matches pool templates "+ts);
- } else {
- if (log.isDebugEnabled())
- log.debug("Pool "+this+", newly detected machine "+m+", does not match any pool templates");
- }
- }
- }
- if (matchedAppeared>0) {
- log.info("Pool "+this+" discovered "+matchedAppeared+" matching machines (of "+appearedMachines.size()+" total new; "+newDetectedMachines.size()+" total including claimed and unmatched)");
- } else {
- if (log.isDebugEnabled())
- log.debug("Pool "+this+" discovered "+matchedAppeared+" matching machines (of "+appearedMachines.size()+" total new; "+newDetectedMachines.size()+" total including claimed and unmatched)");
- }
- matchedMachines = newMatchedMachines;
- }
-
- protected MachineSet filterForAllowedMachines(MachineSet input) {
- return input.removed(blacklistedMachines);
- }
-
- // TODO template registry and claiming from a template could be a separate responsibility
-
- protected ReusableMachineTemplate registerTemplate(ReusableMachineTemplate template) {
- registerTemplates(template);
- return template;
- }
- protected void registerTemplates(ReusableMachineTemplate ...templatesToReg) {
- synchronized (templates) {
- for (ReusableMachineTemplate template: templatesToReg)
- templates.add(template);
- }
- }
-
- protected ReusableMachineTemplate newTemplate(String name) {
- return registerTemplate(new ReusableMachineTemplate(name));
- }
-
-
- public List<ReusableMachineTemplate> getTemplates() {
- List<ReusableMachineTemplate> result;
- synchronized (templates) { result = ImmutableList.copyOf(templates); }
- return result;
- }
-
- /** all machines matching any templates */
- public MachineSet all() {
- init();
- return matchedMachines;
- }
-
- /** machines matching any templates which have not been claimed */
- public MachineSet unclaimed() {
- init();
- synchronized (this) {
- return matchedMachines.removed(claimedMachines);
- }
- }
-
- /** returns all machines matching the given criteria (may be claimed) */
- @SuppressWarnings("unchecked")
- public MachineSet all(Predicate<NodeMetadata> criterion) {
- // To avoid generics complaints in callers caused by varargs, overload here
- return all(new Predicate[] {criterion});
- }
-
- /** returns all machines matching the given criteria (may be claimed) */
- public MachineSet all(Predicate<NodeMetadata> ...ops) {
- return new MachineSet(Iterables.filter(all(), compose(ops)));
- }
-
- /** returns unclaimed machines matching the given criteria */
- @SuppressWarnings("unchecked")
- public MachineSet unclaimed(Predicate<NodeMetadata> criterion) {
- // To avoid generics complaints in callers caused by varargs, overload here
- return unclaimed(new Predicate[] {criterion});
- }
-
- /** returns unclaimed machines matching the given criteria */
- public MachineSet unclaimed(Predicate<NodeMetadata> ...criteria) {
- return new MachineSet(Iterables.filter(unclaimed(), compose(criteria)));
- }
-
- /** creates machines if necessary so that this spec exists (may already be claimed however)
- * returns a set of all matching machines, guaranteed non-empty
- * (but possibly some are already claimed) */
- public MachineSet ensureExists(ReusableMachineTemplate template) {
- return ensureExists(1, template);
- }
-
- public synchronized void addToBlacklist(MachineSet newToBlacklist) {
- setBlacklist(blacklistedMachines.added(newToBlacklist));
- }
-
- /** replaces the blacklist set; callers should generally perform a refresh()
- * afterwards, to trigger re-detection of blacklisted machines
- */
- public synchronized void setBlacklist(MachineSet newBlacklist) {
- blacklistedMachines = newBlacklist;
- detectedMachines = detectedMachines.removed(blacklistedMachines);
- matchedMachines = matchedMachines.removed(blacklistedMachines);
- }
-
- /** creates machines if necessary so that this spec exists (may already be claimed however);
- * returns a set of all matching machines, of size at least count (but possibly some are already claimed).
- * (the pool can change at any point, so this set is a best-effort but may be out of date.
- * see javadoc comments on this class.) */
- public MachineSet ensureExists(int count, ReusableMachineTemplate template) {
- MachineSet current;
- current = all(matching(template));
- if (current.size() >= count)
- return current;
- //have to create more
- MachineSet moreNeeded = create(count-current.size(), template);
- return current.added(moreNeeded);
- }
-
- /** creates machines if necessary so that this spec can subsequently be claimed;
- * returns all such unclaimed machines, guaranteed to be non-empty.
- * (the pool can change at any point, so this set is a best-effort but may be out of date.
- * see javadoc comments on this class.) */
- public MachineSet ensureUnclaimed(ReusableMachineTemplate template) {
- return ensureUnclaimed(1, template);
- }
-
- /** creates machines if necessary so that this spec can subsequently be claimed;
- * returns a set of at least count unclaimed machines */
- public MachineSet ensureUnclaimed(int count, ReusableMachineTemplate template) {
- MachineSet current;
- current = unclaimed(matching(template));
- if (current.size() >= count)
- return current;
- //have to create more
- MachineSet moreNeeded = create(count-current.size(), template);
- return current.added(moreNeeded);
- }
-
- public Set<ReusableMachineTemplate> getTemplatesMatchingInstance(NodeMetadata nm) {
- Set<ReusableMachineTemplate> result = new LinkedHashSet<ReusableMachineTemplate>();
- for (ReusableMachineTemplate t: getTemplates()) {
- if (matching(t).apply(nm)) {
- result.add(t);
- }
- }
- return result;
- }
-
- /** creates the given number of machines of the indicated template */
- public MachineSet create(int count, ReusableMachineTemplate template) {
- Set<? extends NodeMetadata> nodes;
- try {
- Template t = template.newJcloudsTemplate(computeService);
- if (log.isDebugEnabled()) log.debug("Creating "+count+" new instances of "+t);
- nodes = computeService.createNodesInGroup(getPoolName(), count, t);
- } catch (RunNodesException e) {
- throw Throwables.propagate(e);
- }
- MachineSet result = new MachineSet(nodes);
- registerNewNodes(result, template);
- return result;
- }
- protected void registerNewNodes(MachineSet result, ReusableMachineTemplate template) {
- for (NodeMetadata m: result) {
- Set<ReusableMachineTemplate> ts = getTemplatesMatchingInstance(m);
- if (ts.isEmpty()) {
- log.error("Pool "+this+", created machine "+m+" from template "+template+", but no pool templates match!");
- } else {
- if (log.isDebugEnabled())
- log.debug("Pool "+this+", created machine "+m+" from template "+template+", matching templates "+ts);
- }
- }
- synchronized (this) {
- detectedMachines = detectedMachines.added(result);
- matchedMachines = matchedMachines.added(result);
- }
- }
-
- /** claims the indicated number of machines with the indicated spec, creating if necessary */
- public MachineSet claim(int count, ReusableMachineTemplate t) {
- init();
- Set<NodeMetadata> claiming = new LinkedHashSet<NodeMetadata>();
- while (claiming.size() < count) {
- MachineSet mm = ensureUnclaimed(count - claiming.size(), t);
- for (NodeMetadata m : mm) {
- synchronized (this) {
- if (claiming.size() < count && !claimedMachines.contains(m)) {
- claiming.add(m);
- claimedMachines = claimedMachines.added(new MachineSet(m));
- }
- }
- }
- }
- MachineSet result = new MachineSet(claiming);
- return result;
- }
-
-
- /** claims the indicated set of machines;
- * throws exception if cannot all be claimed;
- * returns the set passed in if successful */
- public MachineSet claim(MachineSet set) {
- init();
- synchronized (this) {
- MachineSet originalClaimed = claimedMachines;
- claimedMachines = claimedMachines.added(set);
- MachineSet newlyClaimed = claimedMachines.removed(originalClaimed);
- if (newlyClaimed.size() != set.size()) {
- //did not claim all; unclaim and fail
- claimedMachines = originalClaimed;
- MachineSet unavailable = set.removed(newlyClaimed);
- throw new IllegalArgumentException("Could not claim all requested machines; failed to claim "+unavailable);
- }
- return newlyClaimed;
- }
- }
-
- public int unclaim(MachineSet set) {
- init();
- synchronized (this) {
- MachineSet originalClaimed = claimedMachines;
- claimedMachines = claimedMachines.removed(set);
- return originalClaimed.size() - claimedMachines.size();
- }
- }
-
-
- public int destroy(final MachineSet set) {
- init();
- synchronized (this) {
- detectedMachines = detectedMachines.removed(set);
- matchedMachines = matchedMachines.removed(set);
- claimedMachines = claimedMachines.removed(set);
- }
- Set<? extends NodeMetadata> destroyed = computeService.destroyNodesMatching(new Predicate<NodeMetadata>() {
- @Override
- public boolean apply(NodeMetadata input) {
- return set.contains(input);
- }
- });
- synchronized (this) {
- //in case a rescan happened while we were destroying
- detectedMachines = detectedMachines.removed(set);
- matchedMachines = matchedMachines.removed(set);
- claimedMachines = claimedMachines.removed(set);
- }
- return destroyed.size();
- }
-
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/brooklyn/location/jclouds/pool/MachinePoolPredicates.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/pool/MachinePoolPredicates.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/pool/MachinePoolPredicates.java
deleted file mode 100644
index e2158c1..0000000
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/pool/MachinePoolPredicates.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.location.jclouds.pool;
-
-import java.util.Map;
-
-import org.jclouds.compute.domain.NodeMetadata;
-import org.jclouds.compute.domain.Processor;
-import org.jclouds.domain.Location;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.base.Throwables;
-
-public class MachinePoolPredicates {
-
- private static final Logger log = LoggerFactory.getLogger(MachinePoolPredicates.class);
-
- public static Predicate<NodeMetadata> except(final MachineSet removedItems) {
- return new Predicate<NodeMetadata>() {
- @Override
- public boolean apply(NodeMetadata input) {
- return !removedItems.contains(input);
- }
- };
- }
-
- public static Predicate<NodeMetadata> except(final Predicate<NodeMetadata> predicateToExclude) {
- return Predicates.not(predicateToExclude);
- }
-
- public static Predicate<NodeMetadata> matching(final ReusableMachineTemplate template) {
- return new Predicate<NodeMetadata>() {
- @Override
- public boolean apply(NodeMetadata input) {
- return matches(template, input);
- }
- };
- }
-
- public static Predicate<NodeMetadata> withTag(final String tag) {
- return new Predicate<NodeMetadata>() {
- @Override
- public boolean apply(NodeMetadata input) {
- return input.getTags().contains(tag);
- }
- };
- }
-
- public static Predicate<NodeMetadata> compose(final Predicate<NodeMetadata> ...predicates) {
- return Predicates.and(predicates);
- }
-
- /** True iff the node matches the criteria specified in this template.
- * <p>
- * NB: This only checks some of the most common fields,
- * plus a hashcode (in strict mode).
- * In strict mode you're practically guaranteed to match only machines created by this template.
- * (Add a tag(uid) and you _will_ be guaranteed, strict mode or not.)
- * <p>
- * Outside strict mode, some things (OS and hypervisor) can fall through the gaps.
- * But if that is a problem we can easily add them in.
- * <p>
- * (Caveat: If explicit Hardware, Image, and/or Template were specified in the template,
- * then the hash code probably will not detect it.)
- **/
- public static boolean matches(ReusableMachineTemplate template, NodeMetadata m) {
- try {
- // tags and user metadata
-
- if (! m.getTags().containsAll( template.getTags(false) )) return false;
-
- if (! isSubMapOf(template.getUserMetadata(false), m.getUserMetadata())) return false;
-
-
- // common hardware parameters
-
- if (template.getMinRam()!=null && m.getHardware().getRam() < template.getMinRam()) return false;
-
- if (template.getMinCores()!=null) {
- double numCores = 0;
- for (Processor p: m.getHardware().getProcessors()) numCores += p.getCores();
- if (numCores+0.001 < template.getMinCores()) return false;
- }
-
- if (template.getIs64bit()!=null) {
- if (m.getOperatingSystem().is64Bit() != template.getIs64bit()) return false;
- }
-
- if (template.getOsFamily()!=null) {
- if (m.getOperatingSystem() == null ||
- !template.getOsFamily().equals(m.getOperatingSystem().getFamily())) return false;
- }
- if (template.getOsNameMatchesRegex()!=null) {
- if (m.getOperatingSystem() == null || m.getOperatingSystem().getName()==null ||
- !m.getOperatingSystem().getName().matches(template.getOsNameMatchesRegex())) return false;
- }
-
- if (template.getLocationId()!=null) {
- if (!isLocationContainedIn(m.getLocation(), template.getLocationId())) return false;
- }
-
- // TODO other TemplateBuilder fields and TemplateOptions
-
- return true;
-
- } catch (Exception e) {
- log.warn("Error (rethrowing) trying to match "+m+" against "+template+": "+e, e);
- throw Throwables.propagate(e);
- }
- }
-
- private static boolean isLocationContainedIn(Location location, String locationId) {
- if (location==null) return false;
- if (locationId.equals(location.getId())) return true;
- return isLocationContainedIn(location.getParent(), locationId);
- }
-
- public static boolean isSubMapOf(Map<String, String> sub, Map<String, String> bigger) {
- for (Map.Entry<String, String> e: sub.entrySet()) {
- if (e.getValue()==null) {
- if (!bigger.containsKey(e.getKey())) return false;
- if (bigger.get(e.getKey())!=null) return false;
- } else {
- if (!e.getValue().equals(bigger.get(e.getKey()))) return false;
- }
- }
- return true;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/brooklyn/location/jclouds/pool/MachineSet.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/pool/MachineSet.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/pool/MachineSet.java
deleted file mode 100644
index fe21e2a..0000000
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/pool/MachineSet.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.location.jclouds.pool;
-
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-import javax.annotation.concurrent.Immutable;
-
-import org.jclouds.compute.domain.NodeMetadata;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-
-@Immutable
-public class MachineSet implements Iterable<NodeMetadata> {
-
- final Set<NodeMetadata> members;
-
- public MachineSet(Iterable<? extends NodeMetadata> m) {
- members = ImmutableSet.copyOf(m);
- }
- public MachineSet(NodeMetadata ...nodes) {
- members = ImmutableSet.copyOf(nodes);
- }
-
- @Override
- public Iterator<NodeMetadata> iterator() {
- return members.iterator();
- }
-
- public MachineSet removed(MachineSet toRemove) {
- Set<NodeMetadata> s = new LinkedHashSet<NodeMetadata>(members);
- for (NodeMetadata m: toRemove) s.remove(m);
- return new MachineSet(s);
- }
- public MachineSet added(MachineSet toAdd) {
- Set<NodeMetadata> s = new LinkedHashSet<NodeMetadata>(members);
- for (NodeMetadata m: toAdd) s.add(m);
- return new MachineSet(s);
- }
-
- @SuppressWarnings("unchecked")
- public MachineSet filtered(Predicate<NodeMetadata> criterion) {
- // To avoid generics complaints in callers caused by varargs, overload here
- return filtered(new Predicate[] {criterion});
- }
-
- public MachineSet filtered(Predicate<NodeMetadata> ...criteria) {
- return new MachineSet(Iterables.filter(members, MachinePoolPredicates.compose(criteria)));
- }
-
- public int size() {
- return members.size();
- }
-
- public boolean isEmpty() {
- return members.isEmpty();
- }
-
- public boolean contains(NodeMetadata input) {
- return members.contains(input);
- }
-
- @Override
- public String toString() {
- return members.toString();
- }
-
- @Override
- public int hashCode() {
- return members.hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- return (obj instanceof MachineSet) && (members.equals( ((MachineSet)obj).members ));
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e2c57058/locations/jclouds/src/main/java/brooklyn/location/jclouds/pool/ReusableMachineTemplate.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/pool/ReusableMachineTemplate.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/pool/ReusableMachineTemplate.java
deleted file mode 100644
index d1f3331..0000000
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/pool/ReusableMachineTemplate.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.location.jclouds.pool;
-
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.jclouds.compute.options.TemplateOptions;
-
-import brooklyn.location.jclouds.templates.PortableTemplateBuilder;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-
-/**
- * A facility for having a template we can declare without knowing the provider,
- * then find matching instances, create instances, and generally manipulate them.
- * <p>
- * NB: to be sure of matching a specific template, you should provide a unique id in the constructor.
- * (this will force 'strict' mode.)
- */
-// TODO tags/metadata semantics are not quite right, as they could apply to the server _image_ or _instance_
-
-// TODO we could use a hashcode over the values of template-builder and template-options fields, as a tag/usermetadata,
-// to guarantee (virtually) matching only machines created from this template (instead of asking for unique id)
-public class ReusableMachineTemplate extends PortableTemplateBuilder<ReusableMachineTemplate> {
-
- public static final String PREFIX = "brooklyn:template.";
- public static final String NAME_METADATA_KEY = PREFIX+"name";
- public static final String DESCRIPTION_METADATA_KEY = PREFIX+"name";
- public static final String HASH_METADATA_KEY = PREFIX+"hash";
- public static final String TEMPLATE_OWNER_METADATA_KEY = PREFIX+"owner";
-
- private String name = null;
- private String templateOwner = null;
- private String description = null;
- private boolean strict;
-
- public ReusableMachineTemplate() { strict = false; }
- public ReusableMachineTemplate(String name) { name(name); }
-
- /** see #getName() */
- public ReusableMachineTemplate name(String name) {
- this.name = name;
- strict = true;
- return this;
- }
-
- /** see #getDescription() */
- public ReusableMachineTemplate description(String description) {
- this.description = description;
- return this;
- }
-
- /** whether this template only matches machines instances created from this template;
- * defaults true if a name is set, otherwise false.
- * if false, it will ignore name, owner, and hashcode */
- public ReusableMachineTemplate strict(boolean strict) {
- this.strict = strict;
- return this;
- }
-
- /** no owner, means anyone can pick this up (default) */
- public ReusableMachineTemplate templateUnowned() {
- return templateOwner(null);
- }
- /** adds user.name as owner of this template */
- public ReusableMachineTemplate templateOwnedByMe() {
- return templateOwner(System.getProperty("user.name"));
- }
- /** adds an owner tag to this template */
- public ReusableMachineTemplate templateOwner(String owner) {
- this.templateOwner = owner;
- return this;
- }
-
- /** human-friendly name for this template. should normally be unique, it is the primary differentiator for strict matching. */
- public String getName() {
- return name;
- }
-
- /** a description for this template; this is set on created machines but _not_ used to filter them
- * (so you can change description freely). */
- public String getDescription() {
- return description;
- }
-
- public String getOwner() {
- return templateOwner;
- }
-
- public boolean isStrict() {
- return strict;
- }
-
- @Override
- public List<TemplateOptions> getAdditionalOptions() {
- List<TemplateOptions> result = new ArrayList<TemplateOptions>();
- result.addAll(super.getAdditionalOptions());
- if (isStrict()) addStrictOptions(result);
- return result;
- }
-
- @Override
- public List<TemplateOptions> getAdditionalOptionalOptions() {
- List<TemplateOptions> result = new ArrayList<TemplateOptions>();
- result.addAll(super.getAdditionalOptions());
- addStrictOptions(result);
- return result;
- }
-
- protected void addStrictOptions(List<TemplateOptions> result) {
- if (name!=null) result.add(TemplateOptions.Builder.userMetadata(NAME_METADATA_KEY, name));
- if (templateOwner!=null) result.add(TemplateOptions.Builder.userMetadata(TEMPLATE_OWNER_METADATA_KEY, templateOwner));
- // this is too strict -- the hash code seems to change from run to run (would be nice to fix that)
-// result.add(TemplateOptions.Builder.userMetadata(HASH_METADATA_KEY, ""+hashCode()));
- }
-
- /** computes the user metadata that this template will set (argument true) or required to match (argument false) */
- public Map<String,String> getUserMetadata(boolean includeOptional) {
- return ImmutableMap.copyOf(computeAggregatedOptions(includeOptional).getUserMetadata());
- }
-
- /** computes the tags that this template will set (argument true) or require to match (argument false) */
- public Set<String> getTags(boolean includeOptional) {
- return ImmutableSet.copyOf(computeAggregatedOptions(includeOptional).getTags());
- }
-
- public ReusableMachineTemplate tag(String tag) {
- return tags(tag);
- }
- public ReusableMachineTemplate tags(String ...tags) {
- return addOptions(TemplateOptions.Builder.tags(Arrays.asList(tags)));
- }
-
- public ReusableMachineTemplate metadata(String key, String value) {
- return addOptions(TemplateOptions.Builder.userMetadata(key, value));
- }
- public ReusableMachineTemplate metadata(Map<String,String> m) {
- return addOptions(TemplateOptions.Builder.userMetadata(m));
- }
-
- public ReusableMachineTemplate tagOptional(String tag) {
- return tagsOptional(tag);
- }
- public ReusableMachineTemplate tagsOptional(String ...tags) {
- return addOptionalOptions(TemplateOptions.Builder.tags(Arrays.asList(tags)));
- }
-
- public ReusableMachineTemplate metadataOptional(String key, String value) {
- return addOptionalOptions(TemplateOptions.Builder.userMetadata(key, value));
- }
- public ReusableMachineTemplate metadataOptional(Map<String,String> m) {
- return addOptionalOptions(TemplateOptions.Builder.userMetadata(m));
- }
-
- @Override
- public String toString() {
- String s = makeNonTrivialArgumentsString();
- return (name!=null ? name : "Template") + " [ " + s + " ]";
- }
-
-}