You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by gr...@apache.org on 2014/12/13 02:39:06 UTC

[1/2] incubator-brooklyn git commit: added NginxConfigFileGenerator to pass in custom server.conf templates to NginxController

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master b61dbaa18 -> 3f645fb91


added NginxConfigFileGenerator to pass in custom server.conf templates to NginxController


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/42b5e814
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/42b5e814
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/42b5e814

Branch: refs/heads/master
Commit: 42b5e814a57b8d2b4a6d73e38fe794f3c664c667
Parents: 985b351
Author: ZaidM <za...@cloudsoftcorp.com>
Authored: Fri Dec 12 15:00:52 2014 +0000
Committer: ZaidM <za...@cloudsoftcorp.com>
Committed: Fri Dec 12 16:14:00 2014 +0000

----------------------------------------------------------------------
 .../proxy/nginx/NginxConfigFileGenerator.java   | 250 +-----------------
 .../entity/proxy/nginx/NginxConfigTemplate.java |  79 ------
 .../entity/proxy/nginx/NginxController.java     |   8 +-
 .../entity/proxy/nginx/NginxControllerImpl.java |  13 +-
 .../nginx/NginxDefaultConfigGenerator.java      | 256 +++++++++++++++++++
 .../nginx/NginxTemplateConfigGenerator.java     |  78 ++++++
 6 files changed, 353 insertions(+), 331 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/42b5e814/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxConfigFileGenerator.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxConfigFileGenerator.java b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxConfigFileGenerator.java
index fa74e59..1da0ed8 100644
--- a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxConfigFileGenerator.java
+++ b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxConfigFileGenerator.java
@@ -18,248 +18,16 @@
  */
 package brooklyn.entity.proxy.nginx;
 
-import static java.lang.String.format;
-
-import java.util.Collection;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.proxy.ProxySslConfig;
-import brooklyn.util.text.Strings;
-
-import com.google.common.collect.LinkedHashMultimap;
-import com.google.common.collect.Multimap;
-
 /**
- * Generates a configuration file for {@link NginxController}.
+ * Generates a {@code server.conf} configuration file for an {@link NginxController}.
  */
-public class NginxConfigFileGenerator {
-
-    private static final Logger LOG = LoggerFactory.getLogger(NginxConfigFileGenerator.class);
-
-    private NginxDriver driver;
-    private NginxController nginx;
-
-    public static NginxConfigFileGenerator generator(NginxDriver driver) {
-        return new NginxConfigFileGenerator(driver);
-    }
-
-    private NginxConfigFileGenerator(NginxDriver driver) {
-        this.driver = driver;
-        this.nginx = (NginxController) driver.getEntity();
-    }
-
-    public String configFile() {
-        StringBuilder config = new StringBuilder();
-        config.append("\n");
-        config.append(format("pid %s;\n", driver.getPidFile()));
-        config.append("events {\n");
-        config.append("  worker_connections 8196;\n");
-        config.append("}\n");
-        config.append("http {\n");
-
-        ProxySslConfig globalSslConfig = nginx.getSslConfig();
-
-        if (nginx.isSsl()) {
-            verifyConfig(globalSslConfig);
-            appendSslConfig("global", config, "    ", globalSslConfig, true, true);
-        }
-
-        // If no servers, then defaults to returning 404
-        // TODO Give nicer page back
-        if (nginx.getDomain()!=null || nginx.getServerPoolAddresses() == null || nginx.getServerPoolAddresses().isEmpty()) {
-            config.append("  server {\n");
-            config.append(getCodeForServerConfig());
-            config.append("    listen "+nginx.getPort()+";\n");
-            config.append(getCodeFor404());
-            config.append("  }\n");
-        }
-
-        // For basic round-robin across the server-pool
-        if (nginx.getServerPoolAddresses() != null && nginx.getServerPoolAddresses().size() > 0) {
-            config.append(format("  upstream "+nginx.getId()+" {\n"));
-            if (nginx.isSticky()){
-                config.append("    sticky;\n");
-            }
-            for (String address : nginx.getServerPoolAddresses()) {
-                config.append("    server "+address+";\n");
-            }
-            config.append("  }\n");
-            config.append("  server {\n");
-            config.append(getCodeForServerConfig());
-            config.append("    listen "+nginx.getPort()+";\n");
-            if (nginx.getDomain()!=null)
-                config.append("    server_name "+nginx.getDomain()+";\n");
-            config.append("    location / {\n");
-            config.append("      proxy_pass "+(globalSslConfig != null && globalSslConfig.getTargetIsSsl() ? "https" : "http")+"://"+nginx.getId()+";\n");
-            config.append("    }\n");
-            config.append("  }\n");
-        }
-
-        // For mapping by URL
-        Iterable<UrlMapping> mappings = nginx.getUrlMappings();
-        Multimap<String, UrlMapping> mappingsByDomain = LinkedHashMultimap.create();
-        for (UrlMapping mapping : mappings) {
-            Collection<String> addrs = mapping.getAttribute(UrlMapping.TARGET_ADDRESSES);
-            if (addrs != null && addrs.size() > 0) {
-                mappingsByDomain.put(mapping.getDomain(), mapping);
-            }
-        }
-
-        for (UrlMapping um : mappings) {
-            Collection<String> addrs = um.getAttribute(UrlMapping.TARGET_ADDRESSES);
-            if (addrs != null && addrs.size() > 0) {
-                config.append(format("  upstream "+um.getUniqueLabel()+" {\n"));
-                if (nginx.isSticky()){
-                    config.append("    sticky;\n");
-                }
-                for (String address: addrs) {
-                    config.append("    server "+address+";\n");
-                }
-                config.append("  }\n");
-            }
-        }
-
-        for (String domain : mappingsByDomain.keySet()) {
-            config.append("  server {\n");
-            config.append(getCodeForServerConfig());
-            config.append("    listen "+nginx.getPort()+";\n");
-            config.append("    server_name "+domain+";\n");
-            boolean hasRoot = false;
-
-            // set up SSL
-            ProxySslConfig localSslConfig = null;
-            for (UrlMapping mappingInDomain : mappingsByDomain.get(domain)) {
-                ProxySslConfig sslConfig = mappingInDomain.getConfig(UrlMapping.SSL_CONFIG);
-                if (sslConfig!=null) {
-                    verifyConfig(sslConfig);
-                    if (localSslConfig!=null) {
-                        if (localSslConfig.equals(sslConfig)) {
-                            //ignore identical config specified on multiple mappings
-                        } else {
-                            LOG.warn("{} mapping {} provides SSL config for {} when a different config had already been provided by another mapping, ignoring this one",
-                                    new Object[] {this, mappingInDomain, domain});
-                        }
-                    } else if (globalSslConfig!=null) {
-                        if (globalSslConfig.equals(sslConfig)) {
-                            //ignore identical config specified on multiple mappings
-                        } else {
-                            LOG.warn("{} mapping {} provides SSL config for {} when a different config had been provided at root nginx scope, ignoring this one",
-                                    new Object[] {this, mappingInDomain, domain});
-                        }
-                    } else {
-                        //new config, is okay
-                        localSslConfig = sslConfig;
-                    }
-                }
-            }
-            if (localSslConfig != null) {
-                appendSslConfig(domain, config, "    ", localSslConfig, true, true);
-            }
-
-            for (UrlMapping mappingInDomain : mappingsByDomain.get(domain)) {
-                // TODO Currently only supports "~" for regex. Could add support for other options,
-                // such as "~*", "^~", literals, etc.
-                boolean isRoot = mappingInDomain.getPath()==null || mappingInDomain.getPath().length()==0 || mappingInDomain.getPath().equals("/");
-                if (isRoot && hasRoot) {
-                    LOG.warn(""+this+" mapping "+mappingInDomain+" provides a duplicate / proxy, ignoring");
-                } else {
-                    hasRoot |= isRoot;
-                    String location = isRoot ? "/" : "~ " + mappingInDomain.getPath();
-                    config.append("    location "+location+" {\n");
-                    Collection<UrlRewriteRule> rewrites = mappingInDomain.getConfig(UrlMapping.REWRITES);
-                    if (rewrites != null && rewrites.size() > 0) {
-                        for (UrlRewriteRule rule: rewrites) {
-                            config.append("      rewrite \"^"+rule.getFrom()+"$\" \""+rule.getTo()+"\"");
-                            if (rule.isBreak()) config.append(" break");
-                            config.append(" ;\n");
-                        }
-                    }
-                    config.append("      proxy_pass "+
-                        (localSslConfig != null && localSslConfig.getTargetIsSsl() ? "https" :
-                         (localSslConfig == null && globalSslConfig != null && globalSslConfig.getTargetIsSsl()) ? "https" :
-                         "http")+
-                        "://"+mappingInDomain.getUniqueLabel()+" ;\n");
-                    config.append("    }\n");
-                }
-            }
-            if (!hasRoot) {
-                //provide a root block giving 404 if there isn't one for this server
-                config.append("    location / { \n"+getCodeFor404()+"    }\n");
-            }
-            config.append("  }\n");
-        }
-
-        config.append("}\n");
-
-        return config.toString();
-    }
-
-    protected String getCodeForServerConfig() {
-        // See http://wiki.nginx.org/HttpProxyModule
-        return ""+
-            // this prevents nginx from reporting version number on error pages
-            "    server_tokens off;\n"+
-
-            // this prevents nginx from using the internal proxy_pass codename as Host header passed upstream.
-            // Not using $host, as that causes integration test to fail with a "connection refused" testing
-            // url-mappings, at URL "http://localhost:${port}/atC0" (with a trailing slash it does work).
-            "    proxy_set_header Host $http_host;\n"+
-
-            // following added, as recommended for wordpress in:
-            // http://zeroturnaround.com/labs/wordpress-protips-go-with-a-clustered-approach/#!/
-            "    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n"+
-            "    proxy_set_header X-Real-IP $remote_addr;\n";
-    }
-
-    protected String getCodeFor404() {
-        return "    return 404;\n";
-    }
-
-    protected void verifyConfig(ProxySslConfig proxySslConfig) {
-          if(Strings.isEmpty(proxySslConfig.getCertificateDestination()) && Strings.isEmpty(proxySslConfig.getCertificateSourceUrl())){
-            throw new IllegalStateException("ProxySslConfig can't have a null certificateDestination and null certificateSourceUrl. One or both need to be set");
-        }
-    }
-
-    protected boolean appendSslConfig(String id, StringBuilder out, String prefix, ProxySslConfig ssl,
-                                   boolean sslBlock, boolean certificateBlock) {
-        if (ssl == null) return false;
-        if (sslBlock) {
-            out.append(prefix);
-            out.append("ssl on;\n");
-        }
-        if (ssl.getReuseSessions()) {
-            out.append(prefix);
-            out.append("");
-        }
-        if (certificateBlock) {
-            String cert;
-            if (Strings.isEmpty(ssl.getCertificateDestination())) {
-                cert = "" + id + ".crt";
-            } else {
-                cert = ssl.getCertificateDestination();
-            }
-
-            out.append(prefix);
-            out.append("ssl_certificate " + cert + ";\n");
-
-            String key;
-            if (!Strings.isEmpty(ssl.getKeyDestination())) {
-                key = ssl.getKeyDestination();
-            } else if (!Strings.isEmpty(ssl.getKeySourceUrl())) {
-                key = "" + id + ".key";
-            } else {
-                key = null;
-            }
-
-            if (key != null) {
-                out.append(prefix);
-                out.append("ssl_certificate_key " + key + ";\n");
-            }
-        }
-        return true;
-    }
+public interface NginxConfigFileGenerator {
+
+    /**
+     * Entry point for the generator.
+     *
+     * @return The contents of the {@code server.conf} file
+     */
+    String generateConfigFile(NginxDriver driver, NginxController entity);
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/42b5e814/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxConfigTemplate.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxConfigTemplate.java b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxConfigTemplate.java
deleted file mode 100644
index 4c36042..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxConfigTemplate.java
+++ /dev/null
@@ -1,79 +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.entity.proxy.nginx;
-
-import java.util.Collection;
-import java.util.Map;
-
-import brooklyn.entity.proxy.ProxySslConfig;
-import brooklyn.util.ResourceUtils;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.text.Strings;
-import brooklyn.util.text.TemplateProcessor;
-
-import com.google.common.collect.LinkedHashMultimap;
-import com.google.common.collect.Multimap;
-
-/**
- * Processes a FreeMarker template for an {@link NginxController} configuration file.
- */
-public class NginxConfigTemplate {
-
-    private NginxDriver driver;
-
-    public static NginxConfigTemplate generator(NginxDriver driver) {
-        return new NginxConfigTemplate(driver);
-    }
-
-    private NginxConfigTemplate(NginxDriver driver) {
-        this.driver = driver;
-    }
-
-    public String configFile() {
-        // Check template URL exists
-        String templateUrl = driver.getEntity().getConfig(NginxController.SERVER_CONF_TEMPLATE_URL);
-        ResourceUtils.create(this).checkUrlExists(templateUrl);
-
-        // Check SSL configuration
-        ProxySslConfig ssl = driver.getEntity().getConfig(NginxController.SSL_CONFIG);
-        if (ssl != null && Strings.isEmpty(ssl.getCertificateDestination()) && Strings.isEmpty(ssl.getCertificateSourceUrl())) {
-            throw new IllegalStateException("ProxySslConfig can't have a null certificateDestination and null certificateSourceUrl. One or both need to be set");
-        }
-
-        // For mapping by URL
-        Iterable<UrlMapping> mappings = ((NginxController) driver.getEntity()).getUrlMappings();
-        Multimap<String, UrlMapping> mappingsByDomain = LinkedHashMultimap.create();
-        for (UrlMapping mapping : mappings) {
-            Collection<String> addrs = mapping.getAttribute(UrlMapping.TARGET_ADDRESSES);
-            if (addrs != null && addrs.size() > 0) {
-                mappingsByDomain.put(mapping.getDomain(), mapping);
-            }
-        }
-        Map<String, Object> substitutions = MutableMap.<String, Object>builder()
-                .putIfNotNull("ssl", ssl)
-                .put("urlMappings", mappings)
-                .put("domainMappings", mappingsByDomain)
-                .build();
-
-        // Get template contents and process
-        String contents = ResourceUtils.create(driver.getEntity()).getResourceAsString(templateUrl);
-        return TemplateProcessor.processTemplateContents(contents, driver, substitutions);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/42b5e814/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxController.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxController.java b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxController.java
index 88d1bb9..c645dd2 100644
--- a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxController.java
+++ b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxController.java
@@ -37,6 +37,7 @@ import brooklyn.event.basic.Sensors;
 import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableMap;
+import com.google.common.reflect.TypeToken;
 
 /**
  * An entity that represents an Nginx proxy (e.g. for routing requests to servers in a cluster).
@@ -104,9 +105,12 @@ public interface NginxController extends AbstractController, HasShortName {
     ConfigKey<String> WITH_CC_OPT = ConfigKeys.newStringConfigKey(
             "nginx.install.withCcOpt", "String to pass in with --with-cc-opt=\"<val>\"", "-I /usr/local/include");
 
+    @SetFromFlag("configGenerator")
+    ConfigKey<NginxConfigFileGenerator> SERVER_CONF_GENERATOR = ConfigKeys.newConfigKey(NginxConfigFileGenerator.class,
+            "nginx.config.generator", "The server.conf generator class", new NginxDefaultConfigGenerator());
+
     @SetFromFlag("configTemplate")
-    ConfigKey<String> SERVER_CONF_TEMPLATE_URL = ConfigKeys.newStringConfigKey(
-            "nginx.config.templateUrl", "The server.conf configuration file URL (FreeMarker template)");
+    ConfigKey<String> SERVER_CONF_TEMPLATE_URL = NginxTemplateConfigGenerator.SERVER_CONF_TEMPLATE_URL;
 
     @SetFromFlag("staticContentArchive")
     ConfigKey<String> STATIC_CONTENT_ARCHIVE_URL = ConfigKeys.newStringConfigKey(

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/42b5e814/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
index 74727fb..041b8f6 100644
--- a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
@@ -262,18 +262,13 @@ public class NginxControllerImpl extends AbstractControllerImpl implements Nginx
     public String getConfigFile() {
         NginxSshDriver driver = (NginxSshDriver) getDriver();
         if (driver==null) {
-            if (LOG.isDebugEnabled())
-                LOG.debug("No driver for {}, so not generating config file (is entity stopping? state={})",
-                        this, getAttribute(NginxController.SERVICE_STATE_ACTUAL));
+            LOG.debug("No driver for {}, so not generating config file (is entity stopping? state={})",
+                    this, getAttribute(NginxController.SERVICE_STATE_ACTUAL));
             return null;
         }
 
-        String templateUrl = getConfig(NginxController.SERVER_CONF_TEMPLATE_URL);
-        if (templateUrl != null) {
-            return NginxConfigTemplate.generator(driver).configFile();
-        } else {
-            return NginxConfigFileGenerator.generator(driver).configFile();
-        }
+        NginxConfigFileGenerator templateGenerator = getConfig(NginxController.SERVER_CONF_GENERATOR);
+        return templateGenerator.generateConfigFile(driver, this);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/42b5e814/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxDefaultConfigGenerator.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxDefaultConfigGenerator.java b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxDefaultConfigGenerator.java
new file mode 100644
index 0000000..7ba069e
--- /dev/null
+++ b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxDefaultConfigGenerator.java
@@ -0,0 +1,256 @@
+/*
+ * 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.entity.proxy.nginx;
+
+import static java.lang.String.format;
+
+import java.util.Collection;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
+
+import brooklyn.entity.proxy.ProxySslConfig;
+import brooklyn.util.text.Strings;
+
+/**
+ * Generates the {@code server.conf} configuration file using sensors on an {@link NginxController}.
+ */
+public class NginxDefaultConfigGenerator implements NginxConfigFileGenerator {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NginxDefaultConfigGenerator.class);
+
+    public NginxDefaultConfigGenerator() { }
+
+    @Override
+    public String generateConfigFile(NginxDriver driver, NginxController nginx) {
+        StringBuilder config = new StringBuilder();
+        config.append("\n");
+        config.append(format("pid %s;\n", driver.getPidFile()));
+        config.append("events {\n");
+        config.append("  worker_connections 8196;\n");
+        config.append("}\n");
+        config.append("http {\n");
+
+        ProxySslConfig globalSslConfig = nginx.getSslConfig();
+
+        if (nginx.isSsl()) {
+            verifyConfig(globalSslConfig);
+            appendSslConfig("global", config, "    ", globalSslConfig, true, true);
+        }
+
+        // If no servers, then defaults to returning 404
+        // TODO Give nicer page back
+        if (nginx.getDomain()!=null || nginx.getServerPoolAddresses() == null || nginx.getServerPoolAddresses().isEmpty()) {
+            config.append("  server {\n");
+            config.append(getCodeForServerConfig());
+            config.append("    listen "+nginx.getPort()+";\n");
+            config.append(getCodeFor404());
+            config.append("  }\n");
+        }
+
+        // For basic round-robin across the server-pool
+        if (nginx.getServerPoolAddresses() != null && nginx.getServerPoolAddresses().size() > 0) {
+            config.append(format("  upstream "+nginx.getId()+" {\n"));
+            if (nginx.isSticky()){
+                config.append("    sticky;\n");
+            }
+            for (String address : nginx.getServerPoolAddresses()) {
+                config.append("    server "+address+";\n");
+            }
+            config.append("  }\n");
+            config.append("  server {\n");
+            config.append(getCodeForServerConfig());
+            config.append("    listen "+nginx.getPort()+";\n");
+            if (nginx.getDomain()!=null)
+                config.append("    server_name "+nginx.getDomain()+";\n");
+            config.append("    location / {\n");
+            config.append("      proxy_pass "+(globalSslConfig != null && globalSslConfig.getTargetIsSsl() ? "https" : "http")+"://"+nginx.getId()+";\n");
+            config.append("    }\n");
+            config.append("  }\n");
+        }
+
+        // For mapping by URL
+        Iterable<UrlMapping> mappings = nginx.getUrlMappings();
+        Multimap<String, UrlMapping> mappingsByDomain = LinkedHashMultimap.create();
+        for (UrlMapping mapping : mappings) {
+            Collection<String> addrs = mapping.getAttribute(UrlMapping.TARGET_ADDRESSES);
+            if (addrs != null && addrs.size() > 0) {
+                mappingsByDomain.put(mapping.getDomain(), mapping);
+            }
+        }
+
+        for (UrlMapping um : mappings) {
+            Collection<String> addrs = um.getAttribute(UrlMapping.TARGET_ADDRESSES);
+            if (addrs != null && addrs.size() > 0) {
+                config.append(format("  upstream "+um.getUniqueLabel()+" {\n"));
+                if (nginx.isSticky()){
+                    config.append("    sticky;\n");
+                }
+                for (String address: addrs) {
+                    config.append("    server "+address+";\n");
+                }
+                config.append("  }\n");
+            }
+        }
+
+        for (String domain : mappingsByDomain.keySet()) {
+            config.append("  server {\n");
+            config.append(getCodeForServerConfig());
+            config.append("    listen "+nginx.getPort()+";\n");
+            config.append("    server_name "+domain+";\n");
+            boolean hasRoot = false;
+
+            // set up SSL
+            ProxySslConfig localSslConfig = null;
+            for (UrlMapping mappingInDomain : mappingsByDomain.get(domain)) {
+                ProxySslConfig sslConfig = mappingInDomain.getConfig(UrlMapping.SSL_CONFIG);
+                if (sslConfig!=null) {
+                    verifyConfig(sslConfig);
+                    if (localSslConfig!=null) {
+                        if (localSslConfig.equals(sslConfig)) {
+                            //ignore identical config specified on multiple mappings
+                        } else {
+                            LOG.warn("{} mapping {} provides SSL config for {} when a different config had already been provided by another mapping, ignoring this one",
+                                    new Object[] {this, mappingInDomain, domain});
+                        }
+                    } else if (globalSslConfig!=null) {
+                        if (globalSslConfig.equals(sslConfig)) {
+                            //ignore identical config specified on multiple mappings
+                        } else {
+                            LOG.warn("{} mapping {} provides SSL config for {} when a different config had been provided at root nginx scope, ignoring this one",
+                                    new Object[] {this, mappingInDomain, domain});
+                        }
+                    } else {
+                        //new config, is okay
+                        localSslConfig = sslConfig;
+                    }
+                }
+            }
+            if (localSslConfig != null) {
+                appendSslConfig(domain, config, "    ", localSslConfig, true, true);
+            }
+
+            for (UrlMapping mappingInDomain : mappingsByDomain.get(domain)) {
+                // TODO Currently only supports "~" for regex. Could add support for other options,
+                // such as "~*", "^~", literals, etc.
+                boolean isRoot = mappingInDomain.getPath()==null || mappingInDomain.getPath().length()==0 || mappingInDomain.getPath().equals("/");
+                if (isRoot && hasRoot) {
+                    LOG.warn(""+this+" mapping "+mappingInDomain+" provides a duplicate / proxy, ignoring");
+                } else {
+                    hasRoot |= isRoot;
+                    String location = isRoot ? "/" : "~ " + mappingInDomain.getPath();
+                    config.append("    location "+location+" {\n");
+                    Collection<UrlRewriteRule> rewrites = mappingInDomain.getConfig(UrlMapping.REWRITES);
+                    if (rewrites != null && rewrites.size() > 0) {
+                        for (UrlRewriteRule rule: rewrites) {
+                            config.append("      rewrite \"^"+rule.getFrom()+"$\" \""+rule.getTo()+"\"");
+                            if (rule.isBreak()) config.append(" break");
+                            config.append(" ;\n");
+                        }
+                    }
+                    config.append("      proxy_pass "+
+                        (localSslConfig != null && localSslConfig.getTargetIsSsl() ? "https" :
+                         (localSslConfig == null && globalSslConfig != null && globalSslConfig.getTargetIsSsl()) ? "https" :
+                         "http")+
+                        "://"+mappingInDomain.getUniqueLabel()+" ;\n");
+                    config.append("    }\n");
+                }
+            }
+            if (!hasRoot) {
+                //provide a root block giving 404 if there isn't one for this server
+                config.append("    location / { \n"+getCodeFor404()+"    }\n");
+            }
+            config.append("  }\n");
+        }
+
+        config.append("}\n");
+
+        return config.toString();
+    }
+
+    protected String getCodeForServerConfig() {
+        // See http://wiki.nginx.org/HttpProxyModule
+        return ""+
+            // this prevents nginx from reporting version number on error pages
+            "    server_tokens off;\n"+
+
+            // this prevents nginx from using the internal proxy_pass codename as Host header passed upstream.
+            // Not using $host, as that causes integration test to fail with a "connection refused" testing
+            // url-mappings, at URL "http://localhost:${port}/atC0" (with a trailing slash it does work).
+            "    proxy_set_header Host $http_host;\n"+
+
+            // following added, as recommended for wordpress in:
+            // http://zeroturnaround.com/labs/wordpress-protips-go-with-a-clustered-approach/#!/
+            "    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n"+
+            "    proxy_set_header X-Real-IP $remote_addr;\n";
+    }
+
+    protected String getCodeFor404() {
+        return "    return 404;\n";
+    }
+
+    protected void verifyConfig(ProxySslConfig proxySslConfig) {
+          if(Strings.isEmpty(proxySslConfig.getCertificateDestination()) && Strings.isEmpty(proxySslConfig.getCertificateSourceUrl())){
+            throw new IllegalStateException("ProxySslConfig can't have a null certificateDestination and null certificateSourceUrl. One or both need to be set");
+        }
+    }
+
+    protected boolean appendSslConfig(String id, StringBuilder out, String prefix, ProxySslConfig ssl,
+                                   boolean sslBlock, boolean certificateBlock) {
+        if (ssl == null) return false;
+        if (sslBlock) {
+            out.append(prefix);
+            out.append("ssl on;\n");
+        }
+        if (ssl.getReuseSessions()) {
+            out.append(prefix);
+            out.append("");
+        }
+        if (certificateBlock) {
+            String cert;
+            if (Strings.isEmpty(ssl.getCertificateDestination())) {
+                cert = "" + id + ".crt";
+            } else {
+                cert = ssl.getCertificateDestination();
+            }
+
+            out.append(prefix);
+            out.append("ssl_certificate " + cert + ";\n");
+
+            String key;
+            if (!Strings.isEmpty(ssl.getKeyDestination())) {
+                key = ssl.getKeyDestination();
+            } else if (!Strings.isEmpty(ssl.getKeySourceUrl())) {
+                key = "" + id + ".key";
+            } else {
+                key = null;
+            }
+
+            if (key != null) {
+                out.append(prefix);
+                out.append("ssl_certificate_key " + key + ";\n");
+            }
+        }
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/42b5e814/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxTemplateConfigGenerator.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxTemplateConfigGenerator.java b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxTemplateConfigGenerator.java
new file mode 100644
index 0000000..d141ecf
--- /dev/null
+++ b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxTemplateConfigGenerator.java
@@ -0,0 +1,78 @@
+/*
+ * 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.entity.proxy.nginx;
+
+import java.util.Collection;
+import java.util.Map;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.proxy.ProxySslConfig;
+import brooklyn.util.ResourceUtils;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.flags.SetFromFlag;
+import brooklyn.util.text.Strings;
+import brooklyn.util.text.TemplateProcessor;
+
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
+
+/**
+ * Processes a FreeMarker template to generate the {@code server.conf} configuration file for an {@link NginxController}.
+ */
+public class NginxTemplateConfigGenerator implements NginxConfigFileGenerator {
+
+    public static final ConfigKey<String> SERVER_CONF_TEMPLATE_URL = ConfigKeys.newStringConfigKey(
+            "nginx.config.templateUrl", "The server.conf configuration file URL (FreeMarker template)");
+
+    public NginxTemplateConfigGenerator() { }
+
+    @Override
+    public String generateConfigFile(NginxDriver driver, NginxController nginx) {
+        // Check template URL exists
+        String templateUrl = driver.getEntity().getConfig(NginxController.SERVER_CONF_TEMPLATE_URL);
+        ResourceUtils.create(this).checkUrlExists(templateUrl);
+
+        // Check SSL configuration
+        ProxySslConfig ssl = driver.getEntity().getConfig(NginxController.SSL_CONFIG);
+        if (ssl != null && Strings.isEmpty(ssl.getCertificateDestination()) && Strings.isEmpty(ssl.getCertificateSourceUrl())) {
+            throw new IllegalStateException("ProxySslConfig can't have a null certificateDestination and null certificateSourceUrl. One or both need to be set");
+        }
+
+        // For mapping by URL
+        Iterable<UrlMapping> mappings = ((NginxController) driver.getEntity()).getUrlMappings();
+        Multimap<String, UrlMapping> mappingsByDomain = LinkedHashMultimap.create();
+        for (UrlMapping mapping : mappings) {
+            Collection<String> addrs = mapping.getAttribute(UrlMapping.TARGET_ADDRESSES);
+            if (addrs != null && addrs.size() > 0) {
+                mappingsByDomain.put(mapping.getDomain(), mapping);
+            }
+        }
+        Map<String, Object> substitutions = MutableMap.<String, Object>builder()
+                .putIfNotNull("ssl", ssl)
+                .put("urlMappings", mappings)
+                .put("domainMappings", mappingsByDomain)
+                .build();
+
+        // Get template contents and process
+        String contents = ResourceUtils.create(driver.getEntity()).getResourceAsString(templateUrl);
+        return TemplateProcessor.processTemplateContents(contents, driver, substitutions);
+    }
+
+}


[2/2] incubator-brooklyn git commit: This closes #392

Posted by gr...@apache.org.
This closes #392

* github/pr/392:
  added NginxConfigFileGenerator to pass in custom server.conf templates to NginxController


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/3f645fb9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/3f645fb9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/3f645fb9

Branch: refs/heads/master
Commit: 3f645fb914c30695cf0082716edb9e762e6214b3
Parents: b61dbaa 42b5e81
Author: Andrew Kennedy <gr...@apache.org>
Authored: Sat Dec 13 01:39:01 2014 +0000
Committer: Andrew Kennedy <gr...@apache.org>
Committed: Sat Dec 13 01:39:01 2014 +0000

----------------------------------------------------------------------
 .../proxy/nginx/NginxConfigFileGenerator.java   | 250 +-----------------
 .../entity/proxy/nginx/NginxConfigTemplate.java |  79 ------
 .../entity/proxy/nginx/NginxController.java     |   8 +-
 .../entity/proxy/nginx/NginxControllerImpl.java |  13 +-
 .../nginx/NginxDefaultConfigGenerator.java      | 256 +++++++++++++++++++
 .../nginx/NginxTemplateConfigGenerator.java     |  78 ++++++
 6 files changed, 353 insertions(+), 331 deletions(-)
----------------------------------------------------------------------