All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.brooklyn.entity.proxy.nginx.UrlMappingImpl Maven / Gradle / Ivy

/*
 * 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.entity.proxy.nginx;

import static org.apache.brooklyn.util.JavaGroovyEquivalents.groovyTruth;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;

import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.mgmt.SubscriptionHandle;
import org.apache.brooklyn.api.sensor.SensorEvent;
import org.apache.brooklyn.api.sensor.SensorEventListener;
import org.apache.brooklyn.core.entity.Attributes;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.entity.EntityPredicates;
import org.apache.brooklyn.core.entity.trait.Changeable;
import org.apache.brooklyn.core.entity.trait.Startable;
import org.apache.brooklyn.entity.group.AbstractGroupImpl;
import org.apache.brooklyn.entity.proxy.ProxySslConfig;
import org.apache.brooklyn.entity.webapp.WebAppServiceConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;

/**
 * This is a group whose members will be made available to a load-balancer / URL forwarding service (such as nginx).
 * 

* Configuration requires a domain and some mechanism for finding members. * The easiest way to find members is using a target whose children will be tracked, * but alternative membership policies can also be used. */ public class UrlMappingImpl extends AbstractGroupImpl implements UrlMapping { private static final Logger log = LoggerFactory.getLogger(UrlMapping.class); public UrlMappingImpl() { super(); } @Override public String getUniqueLabel() { String l = getConfig(LABEL); if (groovyTruth(l)) return getId()+"-"+l; else return getId(); } /** adds a rewrite rule, must be called at config time. see {@link UrlRewriteRule} for more info. */ @Override public synchronized UrlMapping addRewrite(String from, String to) { return addRewrite(new UrlRewriteRule(from, to)); } /** adds a rewrite rule, must be called at config time. see {@link UrlRewriteRule} for more info. */ @Override public synchronized UrlMapping addRewrite(UrlRewriteRule rule) { Collection rewrites = getConfig(REWRITES); if (rewrites==null) { rewrites = new ArrayList(); } rewrites.add(rule); config().set(REWRITES, rewrites); return this; } @Override public String getDomain() { return Preconditions.checkNotNull( getConfig(DOMAIN), "domain config argument required"); } @Override public String getPath() { return getConfig(PATH); } @Override public Entity getTarget() { return getConfig(TARGET_PARENT); } @Override public void setTarget(Entity target) { config().set(TARGET_PARENT, target); recompute(); } @Override public void onManagementStarting() { super.onManagementStarting(); if (getConfig(TARGET_PARENT) != null) { recompute(); // following line could be more efficient (just modify the addresses set, not clearing it each time; // but since addresses is lazy loaded not that big a deal) // subscribe(this, Changeable.GROUP_SIZE, { resetAddresses(true) } as SensorEventListener); // above not needed since our target tracking figures this out } } /** defines how address string, ie hostname:port, is constructed from a given entity. * returns null if not possible. *

* the default is to look at HOSTNAME and HTTPS_PORT or HTTP_PORT attribute sensors (depending on SSL_CONFIG being set with targetIsSsl). *

* this method is suitable (intended) for overriding if needed. */ protected String getAddressOfEntity(Entity s) { String h = s.getAttribute(Attributes.HOSTNAME); Integer p = null; Set protos = s.getAttribute(WebAppServiceConstants.ENABLED_PROTOCOLS); ProxySslConfig sslConfig = getConfig(SSL_CONFIG); if (sslConfig != null && sslConfig.getTargetIsSsl()) { // use ssl if (protos != null && hasProtocol(protos, "https")) { // proto configured correctly } else { // proto not defined; use https anyway, but it might fail log.warn("Misconfiguration for "+this+": ENABLED_PROTOCOLS='"+protos+"' for "+s+" but sslConfig="+sslConfig); } p = s.getAttribute(Attributes.HTTPS_PORT); if (p == null) log.warn("Misconfiguration for "+this+": sslConfig="+sslConfig+" but no HTTPS_PORT on "+s); } if (p == null) { // default to http p = s.getAttribute(Attributes.HTTP_PORT); } if (groovyTruth(h) && p != null) return h+":"+p; log.error("Unable to construct hostname:port representation for "+s+"; skipping in "+this); return null; } protected synchronized void recomputeAddresses() { Set resultM = Sets.newLinkedHashSet(); for (Entity s: getMembers()) { String hp = getAddressOfEntity(s); if (hp != null) resultM.add(hp); } Set result = Collections.unmodifiableSet(resultM); Collection oldAddresses = getAttribute(TARGET_ADDRESSES); if (oldAddresses == null || !result.equals(ImmutableSet.copyOf(oldAddresses))) { sensors().set(TARGET_ADDRESSES, result); } } @Override public Collection getTargetAddresses() { return getAttribute(TARGET_ADDRESSES); } @Override public ProxySslConfig getSsl() { return getConfig(SSL_CONFIG); } // FIXME Do we really need this?! protected SubscriptionHandle getSubscriptionHandle() { return subscriptionHandle; } private SubscriptionHandle subscriptionHandle; private SubscriptionHandle subscriptionHandle2; @Override public synchronized void recompute() { if (subscriptionHandle != null) subscriptions().unsubscribe(subscriptionHandle); if (subscriptionHandle2 != null) subscriptions().unsubscribe(subscriptionHandle2); Entity t = getTarget(); if (t != null) { subscriptionHandle = subscriptions().subscribeToChildren(t, Startable.SERVICE_UP, new SensorEventListener() { @Override public void onEvent(SensorEvent event) { boolean changed = (event.getValue()) ? addMember(event.getSource()) : removeMember(event.getSource()); if (changed) { recomputeAddresses(); } }}); subscriptionHandle2 = subscriptions().subscribe(t, Changeable.MEMBER_REMOVED, new SensorEventListener() { @Override public void onEvent(SensorEvent event) { removeMember(event.getValue()); // recompute, irrespective of change, because framework may have already invoked the removeMember call recomputeAddresses(); }}); setMembers(t.getChildren(), EntityPredicates.attributeEqualTo(Startable.SERVICE_UP, true)); } recomputeAddresses(); } @Override public void discard() { Entities.unmanage(this); } private boolean hasProtocol(Collection protocols, String desired) { for (String contender : protocols) { if ("https".equals(contender.toLowerCase())) return true; } return false; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy