org.apache.brooklyn.entity.dns.geoscaling.GeoscalingDnsServiceImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of brooklyn-software-webapp Show documentation
Show all versions of brooklyn-software-webapp Show documentation
Brooklyn entities for Web App software processes
/*
* 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.dns.geoscaling;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.apache.brooklyn.entity.dns.geoscaling.GeoscalingWebClient.PROVIDE_CITY_INFO;
import java.net.URI;
import java.util.Collection;
import java.util.Set;
import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
import org.apache.brooklyn.core.location.geo.HostGeoInfo;
import org.apache.brooklyn.entity.dns.AbstractGeoDnsServiceImpl;
import org.apache.brooklyn.entity.dns.geoscaling.GeoscalingWebClient.Domain;
import org.apache.brooklyn.entity.dns.geoscaling.GeoscalingWebClient.SmartSubdomain;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.brooklyn.util.collections.MutableSet;
import org.apache.brooklyn.util.http.HttpTool;
import org.apache.brooklyn.util.text.Identifiers;
import org.apache.brooklyn.util.text.Strings;
public class GeoscalingDnsServiceImpl extends AbstractGeoDnsServiceImpl implements GeoscalingDnsService {
private static final Logger log = LoggerFactory.getLogger(GeoscalingDnsServiceImpl.class);
// Must remember any desired redirection targets if they're specified before configure() has been called.
private Set rememberedTargetHosts;
private GeoscalingWebClient webClient;
// These are available only after the configure() method has been invoked.
private boolean randomizeSmartSubdomainName;
private String username;
private String password;
private String primaryDomainName;
private String smartSubdomainName;
public GeoscalingDnsServiceImpl() {
}
@Override
public void init() {
super.init();
// defaulting to randomized subdomains makes deploying multiple applications easier
if (config().get(RANDOMIZE_SUBDOMAIN_NAME) == null) {
config().set(RANDOMIZE_SUBDOMAIN_NAME, true);
}
Boolean trustAll = config().get(SSL_TRUST_ALL);
if (Boolean.TRUE.equals(trustAll)) {
webClient = new GeoscalingWebClient(HttpTool.httpClientBuilder().trustAll().build());
} else {
webClient = new GeoscalingWebClient();
}
}
// Ensure our configure() method gets called; may be able to remove this if/when the framework detects this
// and invokes the configure() method automatically?
@Override
public void onManagementStarted() {
super.onManagementStarted();
try {
applyConfig();
} catch (Exception e) {
// don't prevent management coming up, but do mark it as on fire
log.error("Geoscaling did not come up correctly: "+e, e);
ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
}
}
boolean isConfigured = false;
@Override
public synchronized void applyConfig() {
randomizeSmartSubdomainName = Boolean.TRUE.equals(config().get(RANDOMIZE_SUBDOMAIN_NAME));
username = config().get(GEOSCALING_USERNAME);
password = config().get(GEOSCALING_PASSWORD);
primaryDomainName = config().get(GEOSCALING_PRIMARY_DOMAIN_NAME);
smartSubdomainName = config().get(GEOSCALING_SMART_SUBDOMAIN_NAME);
// Ensure all mandatory configuration is provided.
checkNotNull(username, "The GeoScaling username is not specified");
checkNotNull(password, "The GeoScaling password is not specified");
checkNotNull(primaryDomainName, "The GeoScaling primary domain name is not specified");
if (randomizeSmartSubdomainName) {
// if no smart subdomain specified, but random is, use something random
if (smartSubdomainName != null) smartSubdomainName += "-";
else smartSubdomainName = "";
smartSubdomainName += Identifiers.makeRandomId(8);
}
checkNotNull(smartSubdomainName, "The GeoScaling smart subdomain name is not specified or randomized");
String fullDomain = smartSubdomainName+"."+primaryDomainName;
log.info("GeoScaling service will configure redirection for '"+fullDomain+"' domain");
sensors().set(GEOSCALING_ACCOUNT, username);
sensors().set(MANAGED_DOMAIN, fullDomain);
sensors().set(HOSTNAME, getHostname());
isConfigured = true;
if (rememberedTargetHosts != null) {
reconfigureService(rememberedTargetHosts);
rememberedTargetHosts = null;
}
}
@Override
public String getHostname() {
String result = getAttribute(MANAGED_DOMAIN);
return (Strings.isBlank(result)) ? null : result;
}
/** minimum/default TTL here is 300s = 5m */
@Override
public long getTimeToLiveSeconds() { return 5*60; }
@Override
public void destroy() {
setServiceState(Lifecycle.STOPPING);
if (!isConfigured) return;
// Don't leave randomized subdomains configured on our GeoScaling account.
if (randomizeSmartSubdomainName) {
webClient.login(username, password);
Domain primaryDomain = webClient.getPrimaryDomain(primaryDomainName);
SmartSubdomain smartSubdomain = (primaryDomain != null) ? primaryDomain.getSmartSubdomain(smartSubdomainName) : null;
if (smartSubdomain != null) {
log.info("Deleting randomized GeoScaling smart subdomain '"+smartSubdomainName+"."+primaryDomainName+"'");
smartSubdomain.delete();
}
webClient.logout();
}
super.destroy();
isConfigured = false;
}
@Override
protected void reconfigureService(Collection targetHosts) {
if (!isConfigured) {
this.rememberedTargetHosts = MutableSet.copyOf(targetHosts);
return;
}
webClient.login(username, password);
Domain primaryDomain = webClient.getPrimaryDomain(primaryDomainName);
if (primaryDomain==null)
throw new NullPointerException(this+" got null from web client for primary domain "+primaryDomainName);
SmartSubdomain smartSubdomain = primaryDomain.getSmartSubdomain(smartSubdomainName);
if (smartSubdomain == null) {
log.info("GeoScaling {} smart subdomain '{}.{}' does not exist, creating it now", new Object[] {this, smartSubdomainName, primaryDomainName});
// TODO use WithMutexes to ensure this is single-entrant
primaryDomain.createSmartSubdomain(smartSubdomainName);
smartSubdomain = primaryDomain.getSmartSubdomain(smartSubdomainName);
}
if (smartSubdomain != null) {
log.debug("GeoScaling {} being reconfigured to use {}", this, targetHosts);
String script = GeoscalingScriptGenerator.generateScriptString(targetHosts);
smartSubdomain.configure(PROVIDE_CITY_INFO, script);
if (targetHosts.isEmpty()) {
setServiceState(Lifecycle.CREATED);
sensors().set(ROOT_URL, null);
sensors().set(MAIN_URI, null);
} else {
setServiceState(Lifecycle.RUNNING);
String domain = getAttribute(MANAGED_DOMAIN);
if (!Strings.isEmpty(domain)) {
sensors().set(ROOT_URL, "http://"+domain+"/");
sensors().set(MAIN_URI, URI.create("http://"+domain+"/"));
}
}
} else {
log.warn("Failed to retrieve or create GeoScaling smart subdomain '"+smartSubdomainName+"."+primaryDomainName+
"', aborting attempt to configure service");
setServiceState(Lifecycle.ON_FIRE);
}
webClient.logout();
}
}