/******************************************************************************* * Copyright (c) 2013 GigaSpaces Technologies Ltd. All rights reserved * * 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 org.cloudifysource.esc.driver.provisioning.openstack; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.logging.Logger; import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.StringUtils; import org.cloudifysource.domain.ServiceNetwork; import org.cloudifysource.domain.cloud.Cloud; import org.cloudifysource.domain.cloud.compute.ComputeTemplate; import org.cloudifysource.domain.cloud.compute.ComputeTemplateNetwork; import org.cloudifysource.domain.cloud.network.CloudNetwork; import org.cloudifysource.domain.cloud.network.ManagementNetwork; import org.cloudifysource.domain.cloud.network.NetworkConfiguration; import org.cloudifysource.domain.network.AccessRules; import org.cloudifysource.dsl.utils.ServiceUtils; import org.cloudifysource.dsl.utils.ServiceUtils.FullServiceName; import org.cloudifysource.esc.driver.provisioning.BaseProvisioningDriver; import org.cloudifysource.esc.driver.provisioning.CloudProvisioningException; import org.cloudifysource.esc.driver.provisioning.ComputeDriverConfiguration; /** * This is a utility class to handle network configurations making life easier in the OpenStack driver.<br /> * The implementation is dedicated to the driver and should be instantiate only by the setConfig of the driver.<br /> * <br /> * * @author victor * @since 2.7.0 * */ class OpenStackNetworkConfigurationHelper { private final Logger logger = Logger.getLogger(BaseProvisioningDriver.class.getName()); private static final String ASSOCIATE_FLOATING_IP_ON_BOOTSTRAP = "associateFloatingIpOnBootstrap"; private boolean management; private NetworkConfiguration managementNetworkConfiguration; private NetworkConfiguration applicationNetworkConfiguration; private List<String> computeNetworks; private AccessRules serviceAccessRules; private Map<String, Object> managementNetworkOptions; private String managementNetworkPrefixName; private String applicationNetworkPrefixName; /** * Constructor for testing purpose. * * @param openstackPrefixNames * @param configuration */ OpenStackNetworkConfigurationHelper() { } OpenStackNetworkConfigurationHelper(final ComputeDriverConfiguration configuration) throws CloudProvisioningException { this.management = configuration.isManagement(); final String name = configuration.isManagement() ? "managers" : configuration.getServiceName(); logger.info("Setup network configuration for " + name); this.initManagementNetworkConfig(configuration); this.managementNetworkPrefixName = configuration.getCloud().getProvider().getManagementGroup(); if (!this.management) { final FullServiceName fsn = ServiceUtils.getFullServiceName(configuration.getServiceName()); this.applicationNetworkPrefixName = this.managementNetworkPrefixName + fsn.getApplicationName() + "-"; this.initServiceNetworkConfig(configuration); } } /** * Initialize properties for management network configuration.<br /> * A network must be provided for management either it is configured in <code>cloudNetwork</code> section or in * <code>computeNetwork</code> of the cloudCompute. * * @param configuration * The configuration. * @throws CloudProvisioningException * Thrown if no networks defined for the management machine. * */ private void initManagementNetworkConfig(final ComputeDriverConfiguration configuration) throws CloudProvisioningException { final Cloud cloud = configuration.getCloud(); final String templateName = cloud.getConfiguration().getManagementMachineTemplate(); if (configuration.isManagement()) { // Init management computeNetworks. Check if there is any. final ComputeTemplate computeTemplate = cloud.getCloudCompute().getTemplates().get(templateName); if (computeTemplate != null) { final ComputeTemplateNetwork computeNetwork = computeTemplate.getComputeNetwork(); if (computeNetwork != null) { this.computeNetworks = computeNetwork.getNetworks(); } this.managementNetworkOptions = computeTemplate.getOptions(); } if (computeNetworks == null) { this.computeNetworks = new ArrayList<String>(); } } // Figure out if there is a management network. final NetworkConfiguration mngConfig = cloud.getCloudNetwork().getManagement().getNetworkConfiguration(); if (mngConfig != null && mngConfig.getName() != null && mngConfig.getSubnets() != null && !mngConfig.getSubnets().isEmpty()) { this.managementNetworkConfiguration = mngConfig; } // Logs.. if (this.management) { if (this.useManagementNetwork()) { logger.info("Using management network : " + this.managementNetworkConfiguration.getName()); } else { logger.info("Using computeNetwork of template '" + templateName + "' : " + this.computeNetworks); } } } /** * Initialize properties for service network configuration.<br /> * * @param configuration * The configuration. * @throws CloudProvisioningException * Thrown if the service declared a network template which do not exist in the list of templates or if * no networks has been defined for cloudify communications. */ private void initServiceNetworkConfig(final ComputeDriverConfiguration configuration) throws CloudProvisioningException { // Init the service computeNetworks. Check if there is any. final Map<String, ComputeTemplate> computeTemplates = configuration.getCloud().getCloudCompute().getTemplates(); final ComputeTemplate computeTemplate = computeTemplates.get(configuration.getCloudTemplate()); if (computeTemplate != null) { final ComputeTemplateNetwork computeNetwork = computeTemplate.getComputeNetwork(); if (computeNetwork != null) { this.computeNetworks = computeNetwork.getNetworks(); } } if (this.computeNetworks == null) { this.computeNetworks = new ArrayList<String>(); } // Figure out the application network to use final ServiceNetwork serviceNetwork = configuration.getNetwork(); if (serviceNetwork != null) { this.serviceAccessRules = serviceNetwork.getAccessRules(); } final CloudNetwork cloudNetwork = configuration.getCloud().getCloudNetwork(); if (cloudNetwork != null && serviceNetwork != null && serviceNetwork.getTemplate() != null) { // The service specified a network template to use. final Map<String, NetworkConfiguration> templates = cloudNetwork.getTemplates(); this.applicationNetworkConfiguration = templates.get(serviceNetwork.getTemplate()); if (this.applicationNetworkConfiguration == null) { final String message = "Service network template not found '" + serviceNetwork.getTemplate() + "'"; logger.severe(message); throw new CloudProvisioningException(message); } } // Log private ip network logger.info("Service '" + configuration.getServiceName() + "' using network '" + this.getPrivateIpNetworkName() + "' for private ip"); } /** * Returns the management network template configuration. * * @return The management network template configuration. */ public NetworkConfiguration getManagementNetworkTemplate() { return this.managementNetworkConfiguration; } /** * Returns the application network template configuration. * * @return The application network template configuration. */ public NetworkConfiguration getApplicationNetworkTemplate() { return this.applicationNetworkConfiguration; } /** * Returns <true> if the network configuration uses a management network, returns <code>false</code> otherwise. * * @return Returns <true> if the network configuration uses a management network, returns <code>false</code> * otherwise. */ public boolean useManagementNetwork() { return this.getManagementNetworkPrefixedName() != null; } /** * Returns <true> if the service recipe uses network template otherwise returns <code>false</code>. * * @return Returns <true> if the service recipe uses network template, returns <code>false</code> otherwise. */ public boolean useApplicationNetworkTemplate() { return this.applicationNetworkConfiguration != null; } /** * Returns the management network name prefixed with the management group name.<br /> * * @return Returns the management network prefixed name. */ public String getManagementNetworkPrefixedName() { if (this.managementNetworkConfiguration != null) { return managementNetworkPrefixName + managementNetworkConfiguration.getName(); } return null; } /** * Returns the application network name prefixed with the management group name and application name.<br /> * * @return Returns the application network prefixed name. */ public String getApplicationNetworkPrefixedName() { if (this.applicationNetworkConfiguration != null) { return applicationNetworkPrefixName + applicationNetworkConfiguration.getName(); } return null; } /** * <p> * Returns the name of the private IP network to use. * </p> * <p> * <ol> * <li>The management network if exists.</li> * <li>Otherwise, it's the first network defined in the computeNetwork (from the cloudCompute in groovy DSL).</li> * </ol> * </p> * * @return Returns the name of the private IP network to use. */ public String getPrivateIpNetworkName() { String name = null; if (this.useManagementNetwork()) { // If there is a management network then there it is name = this.getManagementNetworkPrefixedName(); } else { name = computeNetworks.get(0); } return name; } /** * Returns the network names defined in the computeNetworks. * * @return Returns the network names defined in the computeNetworks. */ public List<String> getComputeNetworks() { return this.computeNetworks; } public AccessRules getServiceAccessRules() { return serviceAccessRules; } private boolean isValidDefiniton(final String definition) { if (definition == null || StringUtils.trim(definition).isEmpty()) { return false; } return true; } public boolean isValidSubnetName(final org.cloudifysource.domain.cloud.network.Subnet subnet) { return isValidDefiniton(subnet.getName()); } public boolean isValidSubnetRange(final org.cloudifysource.domain.cloud.network.Subnet subnet) { return isValidDefiniton(subnet.getRange()); } public boolean isValidNetworkName(final NetworkConfiguration networkConfiguration) { return isValidDefiniton(networkConfiguration.getName()); } /** * Verify that all networks and subnets has a name (including management one). * * @param cloudNetwork * Configuration to process. * @throws CloudProvisioningException * If a network or subnet is missing name. */ protected void validateNetworkNames(final CloudNetwork cloudNetwork) throws CloudProvisioningException { final ManagementNetwork mn = cloudNetwork.getManagement(); if (mn != null) { this.validateNetworkName(mn.getNetworkConfiguration()); } final Collection<NetworkConfiguration> templates = cloudNetwork.getTemplates().values(); if (templates != null && !templates.isEmpty()) { for (NetworkConfiguration nc : templates) { this.validateNetworkName(nc); } } } public void validateNetworkName(final NetworkConfiguration networkConfiguration) throws CloudProvisioningException { if (networkConfiguration != null) { if (networkConfiguration.getName() == null && !networkConfiguration.getSubnets().isEmpty()) { throw new CloudProvisioningException("Network templates must have name."); } final List<org.cloudifysource.domain.cloud.network.Subnet> subnets = networkConfiguration.getSubnets(); if (subnets != null && !subnets.isEmpty()) { for (final org.cloudifysource.domain.cloud.network.Subnet sn : subnets) { if (sn.getName() == null || sn.getName().trim().equals("")) { throw new CloudProvisioningException( "The name of the Subnet must be provided, Please check network block :'" + networkConfiguration.getName() + "'"); } } } } } /** * Returns <code>true</code> if the configuration need the creation of an external router. * * @return Returns <code>true</code> if the configuration need the creation of an external router. */ public boolean isCreateExternalRouter() { return this.getExternalRouterName() == null; } /** * Returns the external router name from the configuration. * * @return Returns the external router's name from the configuration. */ public String getExternalRouterName() { if (management) { final String extRouterName = (String) managementNetworkOptions.get(OpenStackCloudifyDriver.OPT_EXTERNAL_ROUTER_NAME); return StringUtils.isEmpty(extRouterName) ? null : extRouterName; } return null; } /*** * Returns <code>true</code> if the configuration specifies an external network to use. * * @return Returns <code>false</code> if the configuration requires creating an external network. */ public boolean isCreateExternalNetwork() { return this.getExternalNetworkName() == null; } /** * Returns the external network name from the configuration. * * @return Returns the external network name from the configuration. */ public String getExternalNetworkName() { if (management) { final String extNetName = (String) managementNetworkOptions.get(OpenStackCloudifyDriver.OPT_EXTERNAL_NETWORK_NAME); return StringUtils.isEmpty(extNetName) ? null : extNetName; } return null; } /*** * Returns <code>false</code> if the configuration requires to create and to configure a router to an external * network. * * @return Returns <code>false</code> if the configuration need has specified an external network to use. */ public boolean skipExternalNetworking() { if (management) { final String skipExtNetStr = (String) managementNetworkOptions.get(OpenStackCloudifyDriver.OPT_SKIP_EXTERNAL_NETWORKING); return BooleanUtils.toBoolean(skipExtNetStr); } return false; } /*** * Returns <code>true</code> if requires floating IP. * * @return Returns <code>true</code> if requires floating IP. */ public boolean associateFloatingIp() { if (management && this.managementNetworkConfiguration != null) { final String associate = this.managementNetworkConfiguration.getCustom().get(ASSOCIATE_FLOATING_IP_ON_BOOTSTRAP); return BooleanUtils.toBoolean(associate); } else if (this.applicationNetworkConfiguration != null) { final String associate = this.applicationNetworkConfiguration.getCustom().get(ASSOCIATE_FLOATING_IP_ON_BOOTSTRAP); return BooleanUtils.toBoolean(associate); } else if (!management && this.applicationNetworkConfiguration == null && this.computeNetworks.isEmpty()) { // We are using management networks only. final String associate = this.managementNetworkConfiguration.getCustom() .get(ASSOCIATE_FLOATING_IP_ON_BOOTSTRAP); return BooleanUtils.toBoolean(associate); } return false; } }