/******************************************************************************* * Copyright (c) 2011 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.byon; import com.gigaspaces.grid.gsa.GSA; import org.apache.commons.lang.StringUtils; import org.cloudifysource.domain.cloud.Cloud; import org.cloudifysource.domain.cloud.FileTransferModes; import org.cloudifysource.domain.cloud.compute.ComputeTemplate; import org.cloudifysource.dsl.internal.CloudifyConstants; import org.cloudifysource.dsl.internal.CloudifyErrorMessages; import org.cloudifysource.dsl.rest.response.ControllerDetails; import org.cloudifysource.dsl.utils.IPUtils; import org.cloudifysource.esc.byon.ByonDeployer; import org.cloudifysource.esc.byon.ByonUtils; import org.cloudifysource.esc.driver.provisioning.BaseProvisioningDriver; import org.cloudifysource.esc.driver.provisioning.CloudProvisioningException; import org.cloudifysource.esc.driver.provisioning.CustomNode; import org.cloudifysource.esc.driver.provisioning.MachineDetails; import org.cloudifysource.esc.driver.provisioning.ManagementProvisioningContext; import org.cloudifysource.esc.driver.provisioning.ProvisioningContext; import org.cloudifysource.esc.driver.provisioning.context.ValidationContext; import org.cloudifysource.esc.driver.provisioning.validation.ValidationMessageType; import org.cloudifysource.esc.driver.provisioning.validation.ValidationResultType; import org.cloudifysource.esc.util.FileUtils; import org.cloudifysource.esc.util.Utils; import org.cloudifysource.utilitydomain.openspaces.OpenspacesConstants; import org.openspaces.admin.Admin; import org.openspaces.admin.AdminException; import org.openspaces.admin.gsa.GridServiceAgent; import org.openspaces.admin.gsm.GridServiceManager; import org.openspaces.admin.gsm.GridServiceManagers; import org.openspaces.admin.internal.gsa.InternalGridServiceAgent; import org.openspaces.admin.internal.support.NetworkExceptionHelper; import java.io.File; import java.rmi.RemoteException; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.ResourceBundle; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.logging.Level; /************** * A bring-your-own-node (BYON) CloudifyProvisioning implementation. Parses a groovy file as a source of available * machines to operate as cloud nodes, assuming the nodes are Linux machines with SSH installed. If GigaSpaces is not * already installed on a node, this class will install GigaSpaces and run the agent. * * @author noak * @since 2.0.1 * */ public class ByonProvisioningDriver extends BaseProvisioningDriver { private static final int MANAGEMENT_LOCATION_TIMEOUT = 10; private static final int THREAD_WAITING_IDLE_TIME_IN_SECS = 10; private static final String CLEAN_GS_FILES_ON_SHUTDOWN = "cleanGsFilesOnShutdown"; private static final String CLOUDIFY_ITEMS_TO_CLEAN = "itemsToClean"; private static ResourceBundle byonProvisioningDriverMessageBundle; private boolean cleanGsFilesOnShutdown = false; private List<String> cloudifyItems; private ByonDeployer deployer; private Integer restPort; private static final int DEFAULT_STOP_MANAGEMENT_TIMEOUT = 4; private int stopManagementMachinesTimeoutInMinutes = DEFAULT_STOP_MANAGEMENT_TIMEOUT; @Override protected void initDeployer(final Cloud cloud) { try { setDeployer((ByonDeployer) provisioningContext.getOrCreate("UNIQUE_BYON_DEPLOYER_ID", new Callable<Object>() { @Override public Object call() throws Exception { logger.info("Creating BYON context deployer for cloud: " + cloud.getName()); final ByonDeployer newDeployer = new ByonDeployer(); addTemplatesToDeployer(newDeployer, cloud.getCloudCompute().getTemplates()); return newDeployer; } })); this.stopManagementMachinesTimeoutInMinutes = Utils.getInteger(cloud.getCustom().get(CloudifyConstants .STOP_MANAGEMENT_TIMEOUT_IN_MINUTES), DEFAULT_STOP_MANAGEMENT_TIMEOUT); } catch (final Exception e) { publishEvent("connection_to_cloud_api_failed", cloud.getProvider().getProvider()); throw new IllegalStateException("Failed to create cloud deployer", e); } try { updateDeployerTemplates(cloud); } catch (final Exception e) { logger.log(Level.WARNING, "initDeployer - fialed to add tempaltes to deployer", e); throw new IllegalStateException("Failed to update templates", e); } setCustomSettings(cloud); } private void addTemplatesToDeployer(final ByonDeployer deployer, final Map<String, ComputeTemplate> templatesMap) throws CloudProvisioningException { List<Map<String, String>> nodesList = null; for (final Entry<String, ComputeTemplate> templateEntry : templatesMap.entrySet()) { final String templateName = templateEntry.getKey(); try { ComputeTemplate template = templateEntry.getValue(); validateTemplate(templateName, template); nodesList = ByonUtils.getTemplateNodesList(templateEntry.getValue()); } catch (CloudProvisioningException e) { publishEvent(CloudifyErrorMessages.MISSING_NODES_LIST.getName(), templateName); throw new CloudProvisioningException("Failed to create BYON cloud deployer, invalid configuration for " + "tempalte " + templateName + ", reported error: " + e.getMessage(), e); } deployer.addNodesList(templateName, templatesMap.get(templateName), nodesList); } } // if the hosts list include IPv6 addresses - verify the file transfer protocol is SCP private void validateTemplate(final String templateName, final ComputeTemplate template) throws CloudProvisioningException { logger.fine("validating template [" + templateName + "]"); boolean ipv6Used = false; try { List<CustomNode> nodes = ByonUtils.parseCloudNodes(template); for (CustomNode node : nodes) { if (StringUtils.isNotBlank(node.getPrivateIP()) && IPUtils.isIPv6Address(node.getPrivateIP())) { ipv6Used = true; break; } } if (ipv6Used) { //verify file transfer is set to SCP FileTransferModes fileTransferMode = template.getFileTransfer(); if (fileTransferMode == null || !fileTransferMode.equals(FileTransferModes.SCP)) { throw new CloudProvisioningException("Invalid file transfer set for template " + templateName + ". Templates that use IPv6 addresses must use SCP for file transer."); } } } catch (CloudProvisioningException e) { throw new CloudProvisioningException("Invalid configuration for template " + templateName + ", reported error: " + e.getMessage(), e); } } /********** * . * * @param cloud * . * @throws Exception . */ public void updateDeployerTemplates(final Cloud cloud) throws CloudProvisioningException { final Map<String, ComputeTemplate> cloudTemplatesMap = cloud.getCloudCompute().getTemplates(); final List<String> cloudTemplateNames = new LinkedList<String>(cloudTemplatesMap.keySet()); final List<String> deployerTemplateNames = getDeployer().getTemplatesList(); final List<String> redundantTemplates = new LinkedList<String>(deployerTemplateNames); redundantTemplates.removeAll(cloudTemplateNames); if (!redundantTemplates.isEmpty()) { logger.info("initDeployer - found redundant templates: " + redundantTemplates); getDeployer().removeTemplates(redundantTemplates); } final List<String> missingTemplates = new LinkedList<String>(cloudTemplateNames); missingTemplates.removeAll(deployerTemplateNames); if (!missingTemplates.isEmpty()) { logger.info("initDeployer - found missing templates: " + missingTemplates); final Map<String, ComputeTemplate> templatesMap = new HashMap<String, ComputeTemplate>(); for (final String templateName : missingTemplates) { final ComputeTemplate cloudTemplate = cloudTemplatesMap.get(templateName); templatesMap.put(templateName, cloudTemplate); } addTemplatesToDeployer(getDeployer(), templatesMap); } } @SuppressWarnings("unchecked") private void setCustomSettings(final Cloud cloud) { initRestPort(cloud.getConfiguration().getComponents().getDiscovery().getPort()); // set custom settings final Map<String, Object> customSettings = cloud.getCustom(); if (customSettings != null) { // clean GS files on shutdown if (customSettings.containsKey(CLEAN_GS_FILES_ON_SHUTDOWN)) { final Object cleanOnShutdownStr = customSettings.get(CLEAN_GS_FILES_ON_SHUTDOWN); if (cleanOnShutdownStr != null && StringUtils.isNotBlank((String) cleanOnShutdownStr)) { cleanGsFilesOnShutdown = ((String) cleanOnShutdownStr).equalsIgnoreCase("true"); if (cleanGsFilesOnShutdown) { // Cloudify download directory if (customSettings.containsKey(CLOUDIFY_ITEMS_TO_CLEAN)) { final Object cloudifyItemsStr = customSettings.get(CLOUDIFY_ITEMS_TO_CLEAN); if (cloudifyItemsStr != null) { cloudifyItems = (List<String>) cloudifyItemsStr; } } } } } } } private void initRestPort(final Integer port) { if (port != null) { this.restPort = port; } else { this.restPort = CloudifyConstants.DEFAULT_REST_PORT; } } @Override public MachineDetails startMachine(final ProvisioningContext context, final long timeout, final TimeUnit timeUnit) throws TimeoutException, CloudProvisioningException { final long endTime = System.currentTimeMillis() + timeUnit.toMillis(timeout); logger.info(this.getClass().getName() + ": startMachine, management mode: " + management); final Set<String> activeMachinesIPs = admin.getMachines().getHostsByAddress().keySet(); getDeployer().setAllocated(cloudTemplateName, activeMachinesIPs); if (logger.isLoggable(Level.INFO)) { logger.info("Verifying the active machines are not in the free pool: " + "\n Admin reports the currently used machines are: " + Arrays.toString(activeMachinesIPs.toArray()) + "\n Byon deployer reports the free machines for template " + cloudTemplateName + " are: " + Arrays.toString(getDeployer().getFreeNodesByTemplateName(cloudTemplateName).toArray()) + "\n Byon deployer reports the currently used machines for template " + cloudTemplateName + " are:" + Arrays.toString(getDeployer().getAllocatedNodesByTemplateName(cloudTemplateName).toArray()) + "\n Byon deployer reports the invalid used machines for template " + cloudTemplateName + " are: " + Arrays.toString(getDeployer().getInvalidNodesByTemplateName(cloudTemplateName).toArray()) + ")"); } final String newServerName = createNewServerName(); logger.info("Attempting to start a new cloud machine"); final ComputeTemplate template = this.cloud.getCloudCompute().getTemplates().get(cloudTemplateName); return createServer(newServerName, endTime, template); } @Override protected MachineDetails createServer(final String serverName, final long endTime, final ComputeTemplate template) throws CloudProvisioningException, TimeoutException { final CustomNode node; final MachineDetails machineDetails; logger.info("Cloudify Deployer is creating a machine named: " + serverName + ". This may take a few minutes"); node = getDeployer().createServer(cloudTemplateName, serverName); machineDetails = createMachineDetailsFromNode(node); // At this point the machine is starting. Any error beyond this point // must clean up the machine. try { handleServerCredentials(machineDetails, template); } catch (final CloudProvisioningException e) { try { getDeployer().invalidateServer(cloudTemplateName, node); } catch (final CloudProvisioningException ie) { logger.log(Level.SEVERE, "Failed to mark machine [" + machineDetails.getPublicAddress() + "/" + machineDetails.getPrivateAddress() + "] as Invalid.", ie); } throw new CloudProvisioningException(e); } if (System.currentTimeMillis() > endTime) { throw new TimeoutException(); } logger.info("Machine successfully allocated"); return machineDetails; } /********* * Looks for a free server name by appending a counter to the pre-calculated server name prefix. If the max counter * value is reached, code will loop back to 0, so that previously used server names will be reused. * * @return the server name. * @throws org.cloudifysource.esc.driver.provisioning.CloudProvisioningException * Indicated a free server name was not found. */ private String createNewServerName() throws CloudProvisioningException { String serverName = null; int attempts = 0; boolean foundFreeName = false; while (attempts < MAX_SERVERS_LIMIT) { // counter = (counter + 1) % MAX_SERVERS_LIMIT; ++attempts; serverName = serverNamePrefix + BaseProvisioningDriver.counter.incrementAndGet(); // verifying this server name is not already used final CustomNode existingNode = getDeployer().getServerByID(cloudTemplateName, serverName); if (existingNode == null) { foundFreeName = true; break; } } if (!foundFreeName) { publishEvent("prov_servers_limit_reached", MAX_SERVERS_LIMIT); throw new CloudProvisioningException("Number of servers has exceeded allowed server limit (" + MAX_SERVERS_LIMIT + ")"); } return serverName; } @Override public MachineDetails[] startManagementMachines(final ManagementProvisioningContext context, final long duration, final TimeUnit unit) throws TimeoutException, CloudProvisioningException { if (duration < 0) { throw new TimeoutException("Starting a new machine timed out"); } final long endTime = System.currentTimeMillis() + unit.toMillis(duration); logger.info("DefaultCloudProvisioning: startMachine - management == " + management); // first check if management already exists final MachineDetails[] mds = findManagementInAdmin(); if (mds.length != 0) { return mds; } // launch the management machines publishEvent(EVENT_ATTEMPT_START_MGMT_VMS); final int numberOfManagementMachines = this.cloud.getProvider().getNumberOfManagementMachines(); final MachineDetails[] createdMachines = doStartManagementMachines(endTime, numberOfManagementMachines); publishEvent(EVENT_MGMT_VMS_STARTED); return createdMachines; } private MachineDetails[] findManagementInAdmin() throws CloudProvisioningException, TimeoutException { try { final Set<CustomNode> managementServers = getExistingManagementServers(0); if (managementServers != null && !managementServers.isEmpty()) { final MachineDetails[] managementMachines = new MachineDetails[managementServers.size()]; int i = 0; for (final CustomNode node : managementServers) { managementMachines[i] = createMachineDetailsFromNode(node); managementMachines[i].setAgentRunning(true); managementMachines[i].setCloudifyInstalled(true); i++; } logger.info("Found existing management servers (" + Arrays.toString(managementMachines) + ")"); return managementMachines; } else { logger.warning("Failed locating existing management servers"); } return new MachineDetails[0]; } catch (final InterruptedException e) { publishEvent("prov_management_lookup_failed"); throw new CloudProvisioningException("Failed to lookup existing manahement servers.", e); } } /** * {@inheritDoc} */ @Override public boolean stopMachine(final String serverIp, final long duration, final TimeUnit unit) throws CloudProvisioningException, TimeoutException, InterruptedException { boolean stopResult = false; logger.info("Stop Machine - machineIp: " + serverIp); logger.info("Scale IN -- " + serverIp + " --"); logger.info("Looking up cloud server with IP: " + serverIp); final CustomNode cloudNode = getDeployer().getServerByIP(cloudTemplateName, serverIp); if (cloudNode != null) { logger.info("Found server: " + cloudNode.getId() + ". Shutting it down and waiting for shutdown to complete"); shutdownServerGracefully(cloudNode, false); logger.info("Server: " + cloudNode.getId() + " shutdown has finished."); stopResult = true; } else { logger.log(Level.SEVERE, "Recieved scale in request for machine with ip " + serverIp + " but this IP could not be found in the Cloud server list"); stopResult = false; } return stopResult; } @Override public void stopManagementMachines() throws TimeoutException, CloudProvisioningException { Set<CustomNode> managementServers; final String managementMachinePrefix = this.cloud.getProvider().getManagementGroup(); publishEvent(EVENT_RETRIEVE_EXISTING_MANAGEMENT_MACHINES, managementMachinePrefix); try { managementServers = getExistingManagementServers(cloud.getProvider().getNumberOfManagementMachines()); } catch (final Exception e) { publishEvent("prov_management_lookup_failed"); throw new CloudProvisioningException("Failed to lookup existing management servers.", e); } if (managementServers == null || managementServers.size() == 0) { publishEvent("prov_management_lookup_failed"); throw new IllegalStateException("No management servers were found"); } final int stopTimeoutPerAgent = stopManagementMachinesTimeoutInMinutes / managementServers.size(); for (final CustomNode customNode : managementServers) { try { stopAgentAndWait(cloud.getProvider().getNumberOfManagementMachines(), customNode.getPrivateIP(), stopTimeoutPerAgent); } catch (final Exception e) { publishEvent("prov_failed_to_stop_management_machine"); throw new CloudProvisioningException(e); } shutdownServerGracefully(customNode, true); } } private Set<CustomNode> getExistingManagementServers(final int expectedGsmCount) throws CloudProvisioningException, TimeoutException, InterruptedException { // loop all IPs in the pool to find a mgmt machine - open on port 8100 final Set<CustomNode> existingManagementServers = new HashSet<CustomNode>(); final Set<CustomNode> allNodes = getDeployer().getAllNodesByTemplateName(cloudTemplateName); String managementIP = null; for (final CustomNode server : allNodes) { try { IPUtils.validateConnection(server.getPrivateIP(), this.restPort); managementIP = server.getPrivateIP(); break; } catch (final Exception ex) { // the connection to the REST failed because this is not a // management server, continue. } } // If a management server was found - connect to it and get all management machines if (StringUtils.isNotBlank(managementIP)) { logger.fine("found management machine: " + managementIP); // TODO don't fly if timeout reached because expectedGsmCount wasn't reached final Integer discoveryPort = getLusPort(); final Admin admin = Utils.getAdminObject(managementIP, expectedGsmCount, discoveryPort); try { final GridServiceManagers gsms = admin.getGridServiceManagers(); // make sure a GSM is discovered gsms.waitForAtLeastOne(MANAGEMENT_LOCATION_TIMEOUT, TimeUnit.SECONDS); for (final GridServiceManager gsm : gsms) { final CustomNode managementServer = getDeployer().getServerByIP(cloudTemplateName, gsm.getMachine() .getHostAddress()); if (managementServer != null) { existingManagementServers.add(managementServer); } } } catch (Exception e) { logger.info("Exception thrown while trying to discover GSMs, reported error: " + e.getMessage()); } finally { admin.close(); } } return existingManagementServers; } /** * Gets The configured lus port, or the default if no port is configured. * * @return the lus port. */ protected Integer getLusPort() { Integer discoveryPort = cloud.getConfiguration().getComponents().getDiscovery().getDiscoveryPort(); if (discoveryPort == null) { discoveryPort = OpenspacesConstants.DEFAULT_LUS_PORT; } return discoveryPort; } private void stopAgentAndWait(final int expectedGsmCount, final String ipAddress, final int timeoutInMinutes) throws TimeoutException, InterruptedException { if (admin == null) { final Integer discoveryPort = getLusPort(); admin = Utils.getAdminObject(ipAddress, expectedGsmCount, discoveryPort); } final Map<String, GridServiceAgent> agentsMap = admin.getGridServiceAgents().getHostAddress(); GSA agent = null; for (final Entry<String, GridServiceAgent> agentEntry : agentsMap.entrySet()) { if (IPUtils.isSameIpAddress(agentEntry.getKey(), ipAddress) || agentEntry.getKey().equalsIgnoreCase(ipAddress)) { agent = ((InternalGridServiceAgent) agentEntry.getValue()).getGSA(); } } if (agent != null) { logger.info("Shutting down agent on server: " + ipAddress); try { admin.close(); agent.shutdown(); } catch (final RemoteException e) { if (!NetworkExceptionHelper.isConnectOrCloseException(e)) { logger.log(Level.FINER, "Failed to shutdown GSA", e); throw new AdminException("Failed to shutdown GSA", e); } } final long end = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(timeoutInMinutes); boolean agentUp = isAgentUp(agent); while (agentUp && System.currentTimeMillis() < end) { logger.fine("next check in " + TimeUnit.MILLISECONDS.toSeconds(THREAD_WAITING_IDLE_TIME_IN_SECS) + " seconds"); Thread.sleep(TimeUnit.SECONDS.toMillis(THREAD_WAITING_IDLE_TIME_IN_SECS)); agentUp = isAgentUp(agent); } if (!agentUp && System.currentTimeMillis() >= end) { throw new TimeoutException("Agent shutdown timed out (agent IP: " + ipAddress + ")"); } } } private void deleteGsFiles(final CustomNode cloudNode) { MachineDetails machineDetails = null; try { machineDetails = createMachineDetailsFromNode(cloudNode); String keyFile = ""; if (machineDetails.getKeyFile() != null) { keyFile = machineDetails.getKeyFile().getAbsolutePath(); } FileUtils.deleteFileSystemObjects(machineDetails.getPrivateAddress(), machineDetails.getRemoteUsername(), machineDetails.getRemotePassword(), keyFile, cloudifyItems, machineDetails.getFileTransferMode()); } catch (final Exception e) { if (machineDetails != null) { logger.info("ByonProvisioningDriver: Failed to delete system files from server: " + machineDetails.getPrivateAddress() + ", error: " + e.getMessage()); } else { logger.info("ByonProvisioningDriver: Failed to delete system files from server, error: " + e.getMessage()); } } } private boolean isAgentUp(final GSA agent) { boolean agentUp = false; try { agent.ping(); agentUp = true; } catch (final RemoteException e) { // Probably NoSuchObjectException meaning the GSA is going down agentUp = false; } return agentUp; } @Override protected void handleProvisioningFailure(final int numberOfManagementMachines, final int numberOfErrors, final Exception firstCreationException, final MachineDetails[] createdManagementMachines) throws CloudProvisioningException { logger.severe("Of the required " + numberOfManagementMachines + " management machines, " + numberOfErrors + " failed to start."); if (numberOfManagementMachines > numberOfErrors) { logger.severe("Shutting down the other managememnt machines"); for (final MachineDetails machineDetails : createdManagementMachines) { if (machineDetails != null) { logger.severe("Shutting down machine: " + machineDetails); getDeployer().shutdownServerByIp(cloudTemplateName, machineDetails.getPrivateAddress()); } } } publishEvent("prov_management_machines_failed", firstCreationException.getMessage()); throw new CloudProvisioningException( "One or more managememnt machines failed. The first encountered error was: " + firstCreationException.getMessage(), firstCreationException); } private MachineDetails createMachineDetailsFromNode(final CustomNode node) throws CloudProvisioningException { final ComputeTemplate template = this.cloud.getCloudCompute().getTemplates().get(this.cloudTemplateName); final MachineDetails md = createMachineDetailsForTemplate(template); md.setMachineId(node.getId()); // md.setPrivateAddress(node.getHostName()); md.setPrivateAddress(node.getPrivateIP()); md.setPublicAddress(node.getPublicIP()); // prefer node settings over template setting // prefer key file over password if (StringUtils.isNotBlank(node.getUsername()) && StringUtils.isNotBlank(node.getKeyFile())) { md.setRemoteUsername(node.getUsername()); setKeyFile(md, node.getKeyFile(), template.getAbsoluteUploadDir()); } else if (StringUtils.isNotBlank(node.getUsername()) && StringUtils.isNotBlank(node.getCredential())) { md.setRemoteUsername(node.getUsername()); md.setRemotePassword(node.getCredential()); } else if (StringUtils.isNotBlank(template.getUsername()) && StringUtils.isNotBlank(template.getKeyFile())) { md.setRemoteUsername(template.getUsername()); setKeyFile(md, template.getKeyFile(), template.getAbsoluteUploadDir()); } else if (StringUtils.isNotBlank(template.getUsername()) && StringUtils.isNotBlank(template.getPassword())) { md.setRemoteUsername(template.getUsername()); md.setRemotePassword(template.getPassword()); } else { final String nodeStr = node.toString(); logger.severe("Cloud node loading failed, missing credentials for server: " + nodeStr); publishEvent("prov_node_loading_failed", nodeStr); throw new CloudProvisioningException("Cloud node loading failed, missing credentials for server: " + nodeStr); } md.setOpenFilesLimit(template.getOpenFilesLimit()); return md; } private void shutdownServerGracefully(final CustomNode cloudNode, final boolean isManagement) throws CloudProvisioningException { try { if (cleanGsFilesOnShutdown) { deleteGsFiles(cloudNode); } getDeployer().shutdownServer(cloudTemplateName, cloudNode); } catch (final Exception e) { if (isManagement) { publishEvent("prov_failed_to_stop_management_machine"); } else { publishEvent("prov_failed_to_stop_machine"); } throw new CloudProvisioningException(e); } logger.info("Server: " + cloudNode.getId() + " shutdown has finished."); } @Override public void close() { /* * try { if (admin != null) { admin.close(); } } catch (final Exception ex) { * logger.info("ByonProvisioningDriver.close() failed to close agent"); } */ if (getDeployer() != null) { getDeployer().close(); } } public Cloud getCloud() { return this.cloud; } public ByonDeployer getDeployer() { return this.deployer; } @Override public Object getComputeContext() { return null; } @Override public void validateCloudConfiguration(final ValidationContext validationContext) throws CloudProvisioningException { // if the hosts list include IPv6 addresses - verify the file transfer protocol is SCP validationContext.validationOngoingEvent(ValidationMessageType.GROUP_VALIDATION_MESSAGE, getFormattedMessage("validating_all_templates")); ComputeTemplate template = null; Map<String, ComputeTemplate> templatesMap = cloud.getCloudCompute().getTemplates(); validationContext.validationOngoingEvent(ValidationMessageType.GROUP_VALIDATION_MESSAGE, getFormattedMessage("validating_all_templates")); for (Entry<String, ComputeTemplate> templateEntry : templatesMap.entrySet()) { String templateName = templateEntry.getKey(); template = templateEntry.getValue(); validationContext.validationOngoingEvent(ValidationMessageType.ENTRY_VALIDATION_MESSAGE, getFormattedMessage("validating_template", templateName)); try { validateTemplate(templateName, template); validationContext.validationEventEnd(ValidationResultType.OK); } catch (final CloudProvisioningException e) { validationContext.validationEventEnd(ValidationResultType.ERROR); throw e; } } } @Override public MachineDetails[] getExistingManagementServers() throws CloudProvisioningException { throw new UnsupportedOperationException("Cannot retrieve existing management servers after shutting down" + " agents"); } @Override public MachineDetails[] getExistingManagementServers(final ControllerDetails[] controllers) throws CloudProvisioningException, UnsupportedOperationException { final Set<String> ips = new HashSet<String>(); for (final ControllerDetails controllerDetails : controllers) { ips.add(controllerDetails.getPrivateIp()); } final Set<CustomNode> allNodesByTemplateName = this.getDeployer().getAllNodesByTemplateName(this.cloud.getConfiguration().getManagementMachineTemplate()); final Set<CustomNode> managementNodes = new HashSet<CustomNode>(); for (final CustomNode node : allNodesByTemplateName) { if (ips.contains(node.getPrivateIP()) || ips.contains(node.getHostName())) { managementNodes.add(node); } } final MachineDetails[] result = new MachineDetails[managementNodes.size()]; int i = 0; for (final CustomNode node : managementNodes) { result[i] = createMachineDetailsFromNode(node); ++i; } return result; } private void setKeyFile(final MachineDetails md, final String keyFileName, final String parentFolder) throws CloudProvisioningException { File keyFile = new File(keyFileName); if (!keyFile.isAbsolute()) { keyFile = new File(parentFolder, keyFileName); } if (!keyFile.isFile()) { throw new CloudProvisioningException("The specified key file could not be found: " + keyFile.getAbsolutePath()); } md.setKeyFile(keyFile); } /** * returns the message as it appears in the ByonProvisioningDriver message bundle. * * @param msgName * the message key as it is defined in the message bundle. * @param arguments * the message arguments * @return the formatted message according to the message key. */ protected String getFormattedMessage(final String msgName, final Object... arguments) { return getFormattedMessage(getByonProvisioningDriverMessageBundle(), msgName, arguments); } /** * Returns the message bundle of this cloud driver. * * @return the message bundle of this cloud driver. */ protected static ResourceBundle getByonProvisioningDriverMessageBundle() { if (byonProvisioningDriverMessageBundle == null) { byonProvisioningDriverMessageBundle = ResourceBundle.getBundle("ByonProvisioningDriverMessages", Locale.getDefault()); } return byonProvisioningDriverMessageBundle; } public void setDeployer(ByonDeployer deployer) { this.deployer = deployer; } }