brooklyn.networking.sdn.SdnProviderImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of brooklyn-clocker-docker Show documentation
Show all versions of brooklyn-clocker-docker Show documentation
Clocker Brooklyn entities and locations for Docker integration.
/*
* Copyright 2014-2015 by Cloudsoft Corporation Limited
*
* Licensed 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.networking.sdn;
import java.net.InetAddress;
import java.util.Collection;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import brooklyn.config.render.RendererHints;
import brooklyn.entity.Entity;
import brooklyn.entity.Group;
import brooklyn.entity.basic.BasicGroup;
import brooklyn.entity.basic.BasicStartableImpl;
import brooklyn.entity.basic.DelegateEntity;
import brooklyn.entity.basic.DynamicGroup;
import brooklyn.entity.basic.Entities;
import brooklyn.entity.basic.EntityLocal;
import brooklyn.entity.basic.EntityPredicates;
import brooklyn.entity.container.docker.DockerContainer;
import brooklyn.entity.container.docker.DockerHost;
import brooklyn.entity.container.docker.DockerInfrastructure;
import brooklyn.entity.group.AbstractMembershipTrackingPolicy;
import brooklyn.entity.group.DynamicCluster;
import brooklyn.entity.proxying.EntitySpec;
import brooklyn.event.feed.ConfigToAttributes;
import brooklyn.location.Location;
import brooklyn.networking.VirtualNetwork;
import brooklyn.networking.location.NetworkProvisioningExtension;
import brooklyn.policy.PolicySpec;
import brooklyn.util.collections.QuorumCheck.QuorumChecks;
import brooklyn.util.net.Cidr;
import com.google.common.base.Optional;
import com.google.common.base.Predicates;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
public abstract class SdnProviderImpl extends BasicStartableImpl implements SdnProvider{
private static final Logger LOG = LoggerFactory.getLogger(SdnProvider.class);
/** Held while obtaining new IP addresses for containers. */
protected transient final Object addressMutex = new Object[0];
/** Held while adding or removing new {@link SdnAgent} entities on hosts. */
protected transient final Object hostMutex = new Object[0];
/** Mutex for provisioning new networks */
protected transient final Object networkMutex = new Object[0];
@Override
public void init() {
LOG.info("Starting SDN provider id {}", getId());
super.init();
ConfigToAttributes.apply(this, DOCKER_INFRASTRUCTURE);
BasicGroup agents = addChild(EntitySpec.create(BasicGroup.class)
.configure(BasicGroup.RUNNING_QUORUM_CHECK, QuorumChecks.atLeastOneUnlessEmpty())
.configure(BasicGroup.UP_QUORUM_CHECK, QuorumChecks.atLeastOneUnlessEmpty())
.displayName("SDN Host Agents"));
BasicGroup networks = addChild(EntitySpec.create(BasicGroup.class)
.configure(BasicGroup.RUNNING_QUORUM_CHECK, QuorumChecks.atLeastOneUnlessEmpty())
.configure(BasicGroup.UP_QUORUM_CHECK, QuorumChecks.atLeastOneUnlessEmpty())
.configure(BasicGroup.MEMBER_DELEGATE_CHILDREN, true)
.displayName("SDN Managed Networks"));
BasicGroup applications = addChild(EntitySpec.create(BasicGroup.class)
.configure(BasicGroup.RUNNING_QUORUM_CHECK, QuorumChecks.atLeastOneUnlessEmpty())
.configure(BasicGroup.UP_QUORUM_CHECK, QuorumChecks.atLeastOneUnlessEmpty())
.displayName("SDN Networked Applications"));
if (Entities.isManaged(this)) {
Entities.manage(agents);
Entities.manage(networks);
Entities.manage(applications);
}
setAttribute(SDN_AGENTS, agents);
setAttribute(SDN_NETWORKS, networks);
setAttribute(SDN_APPLICATIONS, applications);
synchronized (addressMutex) {
setAttribute(ALLOCATED_IPS, 0);
setAttribute(ALLOCATED_ADDRESSES, Maps.newConcurrentMap());
setAttribute(SUBNET_ADDRESS_ALLOCATIONS, Maps.newConcurrentMap());
}
synchronized (networkMutex) {
setAttribute(ALLOCATED_NETWORKS, 0);
setAttribute(SUBNETS, Maps.newConcurrentMap());
}
setAttribute(SUBNET_ENTITIES, Maps.newConcurrentMap());
setAttribute(CONTAINER_ADDRESSES, HashMultimap.create());
}
@Override
public InetAddress getNextAgentAddress(String agentId) {
synchronized (addressMutex) {
Cidr cidr = config().get(AGENT_CIDR);
Integer allocated = getAttribute(ALLOCATED_IPS);
InetAddress next = cidr.addressAtOffset(allocated + 1);
setAttribute(ALLOCATED_IPS, allocated + 1);
Map addresses = getAttribute(ALLOCATED_ADDRESSES);
addresses.put(agentId, next);
setAttribute(ALLOCATED_ADDRESSES, addresses);
return next;
}
}
@Override
public InetAddress getNextContainerAddress(String subnetId) {
Cidr cidr = getSubnetCidr(subnetId);
synchronized (addressMutex) {
Map allocations = getAttribute(SUBNET_ADDRESS_ALLOCATIONS);
Integer allocated = allocations.get(subnetId);
if (allocated == null) allocated = 1;
InetAddress next = cidr.addressAtOffset(allocated + 1);
allocations.put(subnetId, allocated + 1);
setAttribute(SUBNET_ADDRESS_ALLOCATIONS, allocations);
return next;
}
}
@Override
public Cidr getNextSubnetCidr(String networkId) {
synchronized (networkMutex) {
Cidr networkCidr = getNextSubnetCidr();
recordSubnetCidr(networkId, networkCidr);
return networkCidr;
}
}
@Override
public Cidr getNextSubnetCidr() {
synchronized (networkMutex) {
Cidr networkCidr = config().get(CONTAINER_NETWORK_CIDR);
Integer networkSize = config().get(CONTAINER_NETWORK_SIZE);
Integer allocated = getAttribute(ALLOCATED_NETWORKS);
InetAddress baseAddress = networkCidr.addressAtOffset(allocated * (1 << (32 - networkSize)));
Cidr subnetCidr = new Cidr(baseAddress.getHostAddress() + "/" + networkSize);
LOG.debug("Allocated {} from {} for subnet #{}", new Object[] { subnetCidr, networkCidr, allocated });
setAttribute(ALLOCATED_NETWORKS, allocated + 1);
return subnetCidr;
}
}
@Override
public void recordSubnetCidr(String networkId, Cidr subnetCidr) {
synchronized (networkMutex) {
Map subnets = getAttribute(SdnProvider.SUBNETS);
subnets.put(networkId, subnetCidr);
setAttribute(SdnProvider.SUBNETS, subnets);
}
}
@Override
public void recordSubnetCidr(String networkId, Cidr subnetCidr, int allocated) {
synchronized (networkMutex) {
recordSubnetCidr(networkId, subnetCidr);
Map allocations = getAttribute(SUBNET_ADDRESS_ALLOCATIONS);
allocations.put(networkId, allocated);
setAttribute(SUBNET_ADDRESS_ALLOCATIONS, allocations);
}
}
@Override
public Cidr getSubnetCidr(String networkId) {
synchronized (networkMutex) {
Map subnets = getAttribute(SdnProvider.SUBNETS);
return subnets.get(networkId);
}
}
@Override
public Object getNetworkMutex() { return networkMutex; }
@Override
public DynamicCluster getDockerHostCluster() {
return config().get(DOCKER_INFRASTRUCTURE).getAttribute(DockerInfrastructure.DOCKER_HOST_CLUSTER);
}
@Override
public Group getAgents() { return getAttribute(SDN_AGENTS); }
public static class MemberTrackingPolicy extends AbstractMembershipTrackingPolicy {
@Override protected void onEntityEvent(EventType type, Entity member) {
((SdnProviderImpl) super.entity).onHostChanged(member);
}
}
@Override
public void start(Collection extends Location> locations) {
setAttribute(SERVICE_UP, Boolean.FALSE);
// Add ouserlves as an extension to the Docker location
DockerInfrastructure infrastructure = (DockerInfrastructure) config().get(DOCKER_INFRASTRUCTURE);
infrastructure.getDynamicLocation().addExtension(NetworkProvisioningExtension.class, this);
super.start(locations);
addHostTrackerPolicy();
setAttribute(SERVICE_UP, Boolean.TRUE);
}
@Override
public void stop() {
setAttribute(SERVICE_UP, Boolean.FALSE);
super.stop();
}
@Override
public void rebind() {
super.rebind();
// TODO implement custom SDN provider rebind logic
}
protected void addHostTrackerPolicy() {
Group hosts = getDockerHostCluster();
if (hosts != null) {
MemberTrackingPolicy hostTrackerPolicy = addPolicy(PolicySpec.create(MemberTrackingPolicy.class)
.displayName("Docker host tracker")
.configure("group", hosts));
LOG.info("Added policy {} to {}, during start", hostTrackerPolicy, this);
}
}
private void onHostAdded(Entity item) {
synchronized (hostMutex) {
if (item instanceof DockerHost) {
addHost((DockerHost) item);
}
}
}
private void onHostRemoved(Entity item) {
synchronized (hostMutex) {
if (item instanceof DockerHost) {
removeHost((DockerHost) item);
}
}
}
private void onHostChanged(Entity item) {
synchronized (hostMutex) {
boolean exists = getDockerHostCluster().hasMember(item);
Boolean running = item.getAttribute(SERVICE_UP);
if (exists && running && item.getAttribute(SdnAgent.SDN_AGENT) == null) {
onHostAdded(item);
} else if (!exists) {
onHostRemoved(item);
}
}
}
@Override
public Map listManagedNetworkAddressSpace() {
return ImmutableMap.copyOf(getAttribute(SUBNETS));
}
@Override
public void provisionNetwork(VirtualNetwork network) {
// Call provisionNetwork on one of the agents to create it
SdnAgent agent = (SdnAgent) (getAgents().getMembers().iterator().next());
String networkId = agent.provisionNetwork(network);
// Create a DynamicGroup with all attached entities
EntitySpec networkSpec = EntitySpec.create(DynamicGroup.class)
.configure(DynamicGroup.ENTITY_FILTER, Predicates.and(
Predicates.not(Predicates.or(Predicates.instanceOf(DockerContainer.class), Predicates.instanceOf(DelegateEntity.class))),
EntityPredicates.attributeEqualTo(DockerContainer.DOCKER_INFRASTRUCTURE, getAttribute(DOCKER_INFRASTRUCTURE)),
SdnAttributes.attachedToNetwork(networkId)))
.configure(DynamicGroup.MEMBER_DELEGATE_CHILDREN, true)
.displayName(network.getDisplayName());
DynamicGroup subnet = getAttribute(SDN_APPLICATIONS).addMemberChild(networkSpec);
Entities.manage(subnet);
((EntityLocal) subnet).setAttribute(VirtualNetwork.NETWORK_ID, networkId);
((EntityLocal) network).setAttribute(VirtualNetwork.NETWORKED_APPLICATIONS, subnet);
getAttribute(SDN_NETWORKS).addMember(network);
}
@Override
public void deallocateNetwork(VirtualNetwork network) {
String networkId = network.getAttribute(VirtualNetwork.NETWORK_ID);
Optional found = Iterables.tryFind(getAttribute(SDN_APPLICATIONS).getMembers(), EntityPredicates.attributeEqualTo(VirtualNetwork.NETWORK_ID, networkId));
if (found.isPresent()) {
Entity group = found.get();
getAttribute(SDN_APPLICATIONS).removeMember(group);
getAttribute(SDN_APPLICATIONS).removeChild(group);
Entities.unmanage(group);
} else {
LOG.warn("Cannot find group containing {} network entities", networkId);
}
getAttribute(SDN_NETWORKS).removeMember(network);
// TODO actually deprovision the network if possible?
}
static {
RendererHints.register(SDN_AGENTS, new RendererHints.NamedActionWithUrl("Open", DelegateEntity.EntityUrl.entityUrl()));
RendererHints.register(SDN_NETWORKS, new RendererHints.NamedActionWithUrl("Open", DelegateEntity.EntityUrl.entityUrl()));
RendererHints.register(SDN_APPLICATIONS, new RendererHints.NamedActionWithUrl("Open", DelegateEntity.EntityUrl.entityUrl()));
RendererHints.register(DOCKER_INFRASTRUCTURE, new RendererHints.NamedActionWithUrl("Open", DelegateEntity.EntityUrl.entityUrl()));
}
}