// 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 com.cloud.storage.resource; import java.util.List; import org.apache.log4j.Logger; import org.apache.log4j.NDC; import com.google.gson.Gson; import com.vmware.vim25.ManagedObjectReference; import org.apache.cloudstack.storage.command.StorageSubSystemCommand; import org.apache.cloudstack.storage.resource.SecondaryStorageResourceHandler; import com.cloud.agent.api.Answer; import com.cloud.agent.api.BackupSnapshotCommand; import com.cloud.agent.api.Command; import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand; import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand; import com.cloud.agent.api.CreateVolumeFromSnapshotCommand; import com.cloud.agent.api.storage.CopyVolumeCommand; import com.cloud.agent.api.storage.CreateEntityDownloadURLCommand; import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; import com.cloud.hypervisor.vmware.manager.VmwareHostService; import com.cloud.hypervisor.vmware.manager.VmwareStorageManager; import com.cloud.hypervisor.vmware.manager.VmwareStorageManagerImpl; import com.cloud.hypervisor.vmware.manager.VmwareStorageMount; import com.cloud.hypervisor.vmware.mo.ClusterMO; import com.cloud.hypervisor.vmware.mo.HostMO; import com.cloud.hypervisor.vmware.mo.VmwareHostType; import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost; import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHostNetworkSummary; import com.cloud.hypervisor.vmware.util.VmwareContext; import com.cloud.serializer.GsonHelper; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.StringUtils; public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageResourceHandler, VmwareHostService, VmwareStorageMount { private static final Logger s_logger = Logger.getLogger(VmwareSecondaryStorageResourceHandler.class); private final PremiumSecondaryStorageResource _resource; private final VmwareStorageManager _storageMgr; private final Gson _gson; private final StorageSubsystemCommandHandler storageSubsystemHandler; private static ThreadLocal<VmwareContext> currentContext = new ThreadLocal<VmwareContext>(); /* * private Map<String, HostMO> _activeHosts = new HashMap<String, HostMO>(); */ public VmwareSecondaryStorageResourceHandler(PremiumSecondaryStorageResource resource, Integer nfsVersion) { _resource = resource; _storageMgr = new VmwareStorageManagerImpl(this, nfsVersion); _gson = GsonHelper.getGsonLogger(); VmwareStorageProcessor storageProcessor = new VmwareStorageProcessor(this, true, this, resource.getTimeout(), null, null, _resource, nfsVersion); VmwareStorageSubsystemCommandHandler vmwareStorageSubsystemCommandHandler = new VmwareStorageSubsystemCommandHandler(storageProcessor, nfsVersion); vmwareStorageSubsystemCommandHandler.setStorageResource(_resource); vmwareStorageSubsystemCommandHandler.setStorageManager(_storageMgr); storageSubsystemHandler = vmwareStorageSubsystemCommandHandler; } private static String getCommandLogTitle(Command cmd) { StringBuffer sb = new StringBuffer(); if (cmd.getContextParam("job") != null) { sb.append(cmd.getContextParam("job")); } sb.append(", cmd: ").append(cmd.getClass().getSimpleName()); return sb.toString(); } @Override public Answer executeRequest(Command cmd) { try { Answer answer; NDC.push(getCommandLogTitle(cmd)); if (s_logger.isDebugEnabled()) s_logger.debug("Executing " + _gson.toJson(cmd)); if (cmd instanceof PrimaryStorageDownloadCommand) { answer = execute((PrimaryStorageDownloadCommand)cmd); } else if (cmd instanceof BackupSnapshotCommand) { answer = execute((BackupSnapshotCommand)cmd); } else if (cmd instanceof CreatePrivateTemplateFromVolumeCommand) { answer = execute((CreatePrivateTemplateFromVolumeCommand)cmd); } else if (cmd instanceof CreatePrivateTemplateFromSnapshotCommand) { answer = execute((CreatePrivateTemplateFromSnapshotCommand)cmd); } else if (cmd instanceof CopyVolumeCommand) { answer = execute((CopyVolumeCommand)cmd); } else if (cmd instanceof CreateVolumeFromSnapshotCommand) { answer = execute((CreateVolumeFromSnapshotCommand)cmd); } else if (cmd instanceof StorageSubSystemCommand) { answer = storageSubsystemHandler.handleStorageCommands((StorageSubSystemCommand)cmd); } else if (cmd instanceof CreateEntityDownloadURLCommand) { answer = execute((CreateEntityDownloadURLCommand)cmd); } else { answer = _resource.defaultAction(cmd); } // special handling to pass-back context info for cleanups if (cmd.getContextParam("execid") != null) { answer.setContextParam("execid", cmd.getContextParam("execid")); } if (cmd.getContextParam("checkpoint") != null) { answer.setContextParam("checkpoint", cmd.getContextParam("checkpoint")); } if (cmd.getContextParam("checkpoint2") != null) { answer.setContextParam("checkpoint2", cmd.getContextParam("checkpoint2")); } if (s_logger.isDebugEnabled()) s_logger.debug("Command execution answer: " + _gson.toJson(answer)); return answer; } finally { if (s_logger.isDebugEnabled()) s_logger.debug("Done executing " + _gson.toJson(cmd)); recycleServiceContext(); NDC.pop(); } } protected Answer execute(CreateEntityDownloadURLCommand cmd) { _storageMgr.execute(this, cmd); return _resource.defaultAction(cmd); } private Answer execute(PrimaryStorageDownloadCommand cmd) { return _storageMgr.execute(this, cmd); } private Answer execute(BackupSnapshotCommand cmd) { return _storageMgr.execute(this, cmd); } private Answer execute(CreatePrivateTemplateFromVolumeCommand cmd) { return _storageMgr.execute(this, cmd); } private Answer execute(CreatePrivateTemplateFromSnapshotCommand cmd) { return _storageMgr.execute(this, cmd); } private Answer execute(CopyVolumeCommand cmd) { return _storageMgr.execute(this, cmd); } private Answer execute(CreateVolumeFromSnapshotCommand cmd) { return _storageMgr.execute(this, cmd); } @Override public VmwareContext getServiceContext(Command cmd) { String guid = cmd.getContextParam("guid"); if (guid == null || guid.isEmpty()) { s_logger.error("Invalid command context parameter guid"); return null; } String username = cmd.getContextParam("username"); if (username == null || username.isEmpty()) { s_logger.error("Invalid command context parameter username"); return null; } String password = cmd.getContextParam("password"); // validate command guid parameter String[] tokens = guid.split("@"); if (tokens == null || tokens.length != 2) { s_logger.error("Invalid content in command context parameter guid"); return null; } String vCenterAddress = tokens[1]; String[] hostTokens = tokens[0].split(":"); if (hostTokens == null || hostTokens.length != 2) { s_logger.error("Invalid content in command context parameter guid"); return null; } int vCenterSessionTimeout = NumbersUtil.parseInt(cmd.getContextParam("vCenterSessionTimeout"), 1200000); try { _resource.ensureOutgoingRuleForAddress(vCenterAddress); VmwareContext context = currentContext.get(); if (context != null && !context.validate()) { invalidateServiceContext(context); context = null; } if (context == null) { s_logger.info("Open new VmwareContext. vCenter: " + vCenterAddress + ", user: " + username + ", password: " + StringUtils.getMaskedPasswordForDisplay(password)); VmwareSecondaryStorageContextFactory.setVcenterSessionTimeout(vCenterSessionTimeout); context = VmwareSecondaryStorageContextFactory.getContext(vCenterAddress, username, password); } if (context != null) { context.registerStockObject("serviceconsole", cmd.getContextParam("serviceconsole")); context.registerStockObject("manageportgroup", cmd.getContextParam("manageportgroup")); context.registerStockObject("noderuninfo", cmd.getContextParam("noderuninfo")); } currentContext.set(context); return context; } catch (Exception e) { s_logger.error("Unexpected exception " + e.toString(), e); return null; } } public void recycleServiceContext() { if (currentContext.get() != null) { VmwareContext context = currentContext.get(); currentContext.set(null); assert (context.getPool() != null); context.getPool().registerContext(context); } } @Override public void invalidateServiceContext(VmwareContext context) { currentContext.set(null); VmwareSecondaryStorageContextFactory.invalidate(context); } @Override public VmwareHypervisorHost getHyperHost(VmwareContext context, Command cmd) { String guid = cmd.getContextParam("guid"); assert (guid != null); String[] tokens = guid.split("@"); assert (tokens != null && tokens.length == 2); ManagedObjectReference morHyperHost = new ManagedObjectReference(); String[] hostTokens = tokens[0].split(":"); if (hostTokens == null || hostTokens.length != 2) { s_logger.error("Invalid content in command context parameter guid"); return null; } morHyperHost.setType(hostTokens[0]); morHyperHost.setValue(hostTokens[1]); if (morHyperHost.getType().equalsIgnoreCase("HostSystem")) { HostMO hostMo = new HostMO(context, morHyperHost); try { ManagedObjectReference mor = hostMo.getHyperHostCluster(); ClusterMO clusterMo = new ClusterMO(hostMo.getContext(), mor); List<Pair<ManagedObjectReference, String>> hostsInCluster = clusterMo.getClusterHosts(); for (Pair<ManagedObjectReference, String> hostPair : hostsInCluster) { HostMO hostIteratorMo = new HostMO(hostMo.getContext(), hostPair.first()); VmwareHypervisorHostNetworkSummary netSummary = hostIteratorMo.getHyperHostNetworkSummary(hostIteratorMo.getHostType() == VmwareHostType.ESXi ? cmd.getContextParam("manageportgroup") : cmd.getContextParam("serviceconsole")); _resource.ensureOutgoingRuleForAddress(netSummary.getHostIp()); s_logger.info("Setup firewall rule for host: " + netSummary.getHostIp()); } } catch (Throwable e) { s_logger.warn("Unable to retrive host network information due to exception " + e.toString() + ", host: " + hostTokens[0] + "-" + hostTokens[1]); } return hostMo; } assert (false); return new ClusterMO(context, morHyperHost); } @Override public String getWorkerName(VmwareContext context, Command cmd, int workerSequence) { assert (cmd.getContextParam("worker") != null); assert (workerSequence < 2); if (workerSequence == 0) return cmd.getContextParam("worker"); return cmd.getContextParam("worker2"); } @Override public String getMountPoint(String storageUrl, Integer nfsVersion) { return _resource.getRootDir(storageUrl, nfsVersion); } }