You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by mc...@apache.org on 2014/02/07 22:46:20 UTC
[11/50] [abbrv] Moved the controlling logic for secondary storage vm
into place
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/54f32a8e/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java
----------------------------------------------------------------------
diff --git a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java
new file mode 100755
index 0000000..4a59d8f
--- /dev/null
+++ b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java
@@ -0,0 +1,1388 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.secondarystorage;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.config.ApiServiceConfiguration;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
+import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.framework.security.keystore.KeystoreManager;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
+import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
+import org.apache.cloudstack.utils.identity.ManagementServerNode;
+
+import com.cloud.agent.AgentManager;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.RebootCommand;
+import com.cloud.agent.api.SecStorageFirewallCfgCommand;
+import com.cloud.agent.api.SecStorageSetupAnswer;
+import com.cloud.agent.api.SecStorageSetupCommand;
+import com.cloud.agent.api.SecStorageVMSetupCommand;
+import com.cloud.agent.api.StartupCommand;
+import com.cloud.agent.api.StartupSecondaryStorageCommand;
+import com.cloud.agent.api.check.CheckSshAnswer;
+import com.cloud.agent.api.check.CheckSshCommand;
+import com.cloud.agent.api.to.NfsTO;
+import com.cloud.agent.manager.Commands;
+import com.cloud.capacity.dao.CapacityDao;
+import com.cloud.cluster.ClusterManager;
+import com.cloud.configuration.Config;
+import com.cloud.configuration.ZoneConfig;
+import com.cloud.consoleproxy.ConsoleProxyManager;
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.DataCenter.NetworkType;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.deploy.DataCenterDeployment;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.exception.StorageUnavailableException;
+import com.cloud.host.Host;
+import com.cloud.host.HostVO;
+import com.cloud.host.Status;
+import com.cloud.host.dao.HostDao;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.info.RunningHostCountInfo;
+import com.cloud.info.RunningHostInfoAgregator;
+import com.cloud.info.RunningHostInfoAgregator.ZoneHostInfo;
+import com.cloud.network.Network;
+import com.cloud.network.NetworkModel;
+import com.cloud.network.Networks.TrafficType;
+import com.cloud.network.dao.IPAddressDao;
+import com.cloud.network.dao.IPAddressVO;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.NetworkVO;
+import com.cloud.network.rules.RulesManager;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.offering.ServiceOffering;
+import com.cloud.offerings.dao.NetworkOfferingDao;
+import com.cloud.resource.ResourceManager;
+import com.cloud.resource.ResourceStateAdapter;
+import com.cloud.resource.ServerResource;
+import com.cloud.resource.UnableDeleteHostException;
+import com.cloud.service.ServiceOfferingVO;
+import com.cloud.service.dao.ServiceOfferingDao;
+import com.cloud.storage.UploadVO;
+import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.dao.SnapshotDao;
+import com.cloud.storage.dao.StoragePoolHostDao;
+import com.cloud.storage.dao.UploadDao;
+import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.storage.secondary.SecStorageVmAlertEventArgs;
+import com.cloud.storage.secondary.SecondaryStorageListener;
+import com.cloud.storage.secondary.SecondaryStorageVmAllocator;
+import com.cloud.storage.secondary.SecondaryStorageVmManager;
+import com.cloud.storage.template.TemplateConstants;
+import com.cloud.template.TemplateManager;
+import com.cloud.user.Account;
+import com.cloud.user.AccountService;
+import com.cloud.utils.DateUtil;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.Pair;
+import com.cloud.utils.component.ManagerBase;
+import com.cloud.utils.db.GlobalLock;
+import com.cloud.utils.db.QueryBuilder;
+import com.cloud.utils.db.SearchCriteria.Op;
+import com.cloud.utils.events.SubscriptionMgr;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.net.NetUtils;
+import com.cloud.vm.Nic;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.ReservationContext;
+import com.cloud.vm.SecondaryStorageVm;
+import com.cloud.vm.SecondaryStorageVmVO;
+import com.cloud.vm.SystemVmLoadScanHandler;
+import com.cloud.vm.SystemVmLoadScanner;
+import com.cloud.vm.SystemVmLoadScanner.AfterScanAction;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachine.State;
+import com.cloud.vm.VirtualMachineGuru;
+import com.cloud.vm.VirtualMachineManager;
+import com.cloud.vm.VirtualMachineName;
+import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.dao.SecondaryStorageVmDao;
+import com.cloud.vm.dao.UserVmDetailsDao;
+import com.cloud.vm.dao.VMInstanceDao;
+
+//
+// Possible secondary storage vm state transition cases
+// Creating -> Destroyed
+// Creating -> Stopped --> Starting -> Running
+// HA -> Stopped -> Starting -> Running
+// Migrating -> Running (if previous state is Running before it enters into Migrating state
+// Migrating -> Stopped (if previous state is not Running before it enters into Migrating state)
+// Running -> HA (if agent lost connection)
+// Stopped -> Destroyed
+//
+// Creating state indicates of record creating and IP address allocation are ready, it is a transient
+// state which will soon be switching towards Running if everything goes well.
+// Stopped state indicates the readiness of being able to start (has storage and IP resources allocated)
+// Starting state can only be entered from Stopped states
+//
+// Starting, HA, Migrating, Creating and Running state are all counted as "Open" for available capacity calculation
+// because sooner or later, it will be driven into Running state
+//
+@Local(value = {SecondaryStorageVmManager.class})
+public class SecondaryStorageManagerImpl extends ManagerBase implements SecondaryStorageVmManager, VirtualMachineGuru, SystemVmLoadScanHandler<Long>,
+ ResourceStateAdapter {
+ private static final Logger s_logger = Logger.getLogger(SecondaryStorageManagerImpl.class);
+
+ private static final int DEFAULT_CAPACITY_SCAN_INTERVAL = 30000; // 30
+ // seconds
+ private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC = 180; // 3
+ // minutes
+
+ private static final int STARTUP_DELAY = 60000; // 60 seconds
+
+ private int _mgmtPort = 8250;
+
+ private List<SecondaryStorageVmAllocator> _ssVmAllocators;
+
+ @Inject
+ protected SecondaryStorageVmDao _secStorageVmDao;
+ @Inject
+ private DataCenterDao _dcDao;
+ @Inject
+ private VMTemplateDao _templateDao;
+ @Inject
+ private HostDao _hostDao;
+ @Inject
+ private StoragePoolHostDao _storagePoolHostDao;
+ @Inject
+ private AgentManager _agentMgr;
+ @Inject
+ protected NetworkOrchestrationService _networkMgr;
+ @Inject
+ protected NetworkModel _networkModel;
+ @Inject
+ protected SnapshotDao _snapshotDao;
+ private SecondaryStorageListener _listener;
+
+ private ServiceOfferingVO _serviceOffering;
+
+ @Inject
+ protected ConfigurationDao _configDao;
+ @Inject
+ private ServiceOfferingDao _offeringDao;
+ @Inject
+ private AccountService _accountMgr;
+ @Inject
+ private VirtualMachineManager _itMgr;
+ @Inject
+ protected VMInstanceDao _vmDao;
+ @Inject
+ protected CapacityDao _capacityDao;
+ @Inject
+ UserVmDetailsDao _vmDetailsDao;
+ @Inject
+ protected ResourceManager _resourceMgr;
+ @Inject
+ NetworkDao _networkDao;
+ @Inject
+ NetworkOfferingDao _networkOfferingDao;
+ @Inject
+ protected IPAddressDao _ipAddressDao = null;
+ @Inject
+ protected RulesManager _rulesMgr;
+ @Inject
+ TemplateManager templateMgr;
+ @Inject
+ UploadDao _uploadDao;
+
+ @Inject
+ KeystoreManager _keystoreMgr;
+ @Inject
+ DataStoreManager _dataStoreMgr;
+ @Inject
+ ImageStoreDao _imageStoreDao;
+ @Inject
+ TemplateDataStoreDao _tmplStoreDao;
+ private long _capacityScanInterval = DEFAULT_CAPACITY_SCAN_INTERVAL;
+ private int _secStorageVmMtuSize;
+
+ private String _instance;
+ private boolean _useLocalStorage;
+ private boolean _useSSlCopy;
+ private String _httpProxy;
+ private String _allowedInternalSites;
+ protected long _nodeId = ManagementServerNode.getManagementServerId();
+
+ private SystemVmLoadScanner<Long> _loadScanner;
+ private Map<Long, ZoneHostInfo> _zoneHostInfoMap; // map <zone id, info about running host in zone>
+
+ private final GlobalLock _allocLock = GlobalLock.getInternLock(getAllocLockName());
+
+ public SecondaryStorageManagerImpl() {
+ }
+
+ @Override
+ public SecondaryStorageVmVO startSecStorageVm(long secStorageVmId) {
+ try {
+ SecondaryStorageVmVO secStorageVm = _secStorageVmDao.findById(secStorageVmId);
+ _itMgr.advanceStart(secStorageVm.getUuid(), null, null);
+ return _secStorageVmDao.findById(secStorageVm.getId());
+ } catch (StorageUnavailableException e) {
+ s_logger.warn("Exception while trying to start secondary storage vm", e);
+ return null;
+ } catch (InsufficientCapacityException e) {
+ s_logger.warn("Exception while trying to start secondary storage vm", e);
+ return null;
+ } catch (ResourceUnavailableException e) {
+ s_logger.warn("Exception while trying to start secondary storage vm", e);
+ return null;
+ } catch (Exception e) {
+ s_logger.warn("Exception while trying to start secondary storage vm", e);
+ return null;
+ }
+ }
+
+ SecondaryStorageVmVO getSSVMfromHost(HostVO ssAHost) {
+ if (ssAHost.getType() == Host.Type.SecondaryStorageVM) {
+ return _secStorageVmDao.findByInstanceName(ssAHost.getName());
+ }
+ return null;
+ }
+
+ @Override
+ public boolean generateSetupCommand(Long ssHostId) {
+ HostVO cssHost = _hostDao.findById(ssHostId);
+ Long zoneId = cssHost.getDataCenterId();
+ if (cssHost.getType() == Host.Type.SecondaryStorageVM) {
+
+ SecondaryStorageVmVO secStorageVm = _secStorageVmDao.findByInstanceName(cssHost.getName());
+ if (secStorageVm == null) {
+ s_logger.warn("secondary storage VM " + cssHost.getName() + " doesn't exist");
+ return false;
+ }
+
+ List<DataStore> ssStores = _dataStoreMgr.getImageStoresByScope(new ZoneScope(zoneId));
+ for (DataStore ssStore : ssStores) {
+ if (!(ssStore.getTO() instanceof NfsTO)) {
+ continue; // only do this for Nfs
+ }
+ String secUrl = ssStore.getUri();
+ SecStorageSetupCommand setupCmd = null;
+ if (!_useSSlCopy) {
+ setupCmd = new SecStorageSetupCommand(ssStore.getTO(), secUrl, null);
+ } else {
+ KeystoreManager.Certificates certs = _keystoreMgr.getCertificates(ConsoleProxyManager.CERTIFICATE_NAME);
+ setupCmd = new SecStorageSetupCommand(ssStore.getTO(), secUrl, certs);
+ }
+
+ Answer answer = _agentMgr.easySend(ssHostId, setupCmd);
+ if (answer != null && answer.getResult()) {
+ SecStorageSetupAnswer an = (SecStorageSetupAnswer)answer;
+ if (an.get_dir() != null) {
+ // update the parent path in image_store table for this image store
+ ImageStoreVO svo = _imageStoreDao.findById(ssStore.getId());
+ svo.setParent(an.get_dir());
+ _imageStoreDao.update(ssStore.getId(), svo);
+ }
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Successfully programmed secondary storage " + ssStore.getName() + " in secondary storage VM " + secStorageVm.getInstanceName());
+ }
+ } else {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Successfully programmed secondary storage " + ssStore.getName() + " in secondary storage VM " + secStorageVm.getInstanceName());
+ }
+ return false;
+ }
+ }
+ }
+ /* After removing SecondaryStorage entries from host table, control should never come here!!
+ else if( cssHost.getType() == Host.Type.SecondaryStorage ) {
+ List<SecondaryStorageVmVO> alreadyRunning = _secStorageVmDao.getSecStorageVmListInStates(SecondaryStorageVm.Role.templateProcessor, zoneId, State.Running);
+ String secUrl = cssHost.getStorageUrl();
+ SecStorageSetupCommand setupCmd = new SecStorageSetupCommand(secUrl, null);
+ for ( SecondaryStorageVmVO ssVm : alreadyRunning ) {
+ HostVO host = _resourceMgr.findHostByName(ssVm.getInstanceName());
+ Answer answer = _agentMgr.easySend(host.getId(), setupCmd);
+ if (answer != null && answer.getResult()) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Successfully programmed secondary storage " + host.getName() + " in secondary storage VM " + ssVm.getInstanceName());
+ }
+ } else {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Successfully programmed secondary storage " + host.getName() + " in secondary storage VM " + ssVm.getInstanceName());
+ }
+ return false;
+ }
+ }
+ }
+ */
+ return true;
+ }
+
+ @Override
+ public boolean generateVMSetupCommand(Long ssAHostId) {
+ HostVO ssAHost = _hostDao.findById(ssAHostId);
+ if (ssAHost.getType() != Host.Type.SecondaryStorageVM) {
+ return false;
+ }
+ SecondaryStorageVmVO secStorageVm = _secStorageVmDao.findByInstanceName(ssAHost.getName());
+ if (secStorageVm == null) {
+ s_logger.warn("secondary storage VM " + ssAHost.getName() + " doesn't exist");
+ return false;
+ }
+
+ SecStorageVMSetupCommand setupCmd = new SecStorageVMSetupCommand();
+ if (_allowedInternalSites != null) {
+ List<String> allowedCidrs = new ArrayList<String>();
+ String[] cidrs = _allowedInternalSites.split(",");
+ for (String cidr : cidrs) {
+ if (NetUtils.isValidCIDR(cidr) || NetUtils.isValidIp(cidr) || !cidr.startsWith("0.0.0.0")) {
+ allowedCidrs.add(cidr);
+ }
+ }
+ List<? extends Nic> nics = _networkModel.getNicsForTraffic(secStorageVm.getId(), TrafficType.Management);
+ setupCmd.setAllowedInternalSites(allowedCidrs.toArray(new String[allowedCidrs.size()]));
+ }
+ String copyPasswd = _configDao.getValue("secstorage.copy.password");
+ setupCmd.setCopyPassword(copyPasswd);
+ setupCmd.setCopyUserName(TemplateConstants.DEFAULT_HTTP_AUTH_USER);
+ Answer answer = _agentMgr.easySend(ssAHostId, setupCmd);
+ if (answer != null && answer.getResult()) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Successfully programmed http auth into " + secStorageVm.getHostName());
+ }
+ return true;
+ } else {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("failed to program http auth into secondary storage vm : " + secStorageVm.getHostName());
+ }
+ return false;
+ }
+ }
+
+ @Override
+ public Pair<HostVO, SecondaryStorageVmVO> assignSecStorageVm(long zoneId, Command cmd) {
+ return null;
+ }
+
+ @Override
+ public boolean generateFirewallConfiguration(Long ssAHostId) {
+ if (ssAHostId == null) {
+ return true;
+ }
+ HostVO ssAHost = _hostDao.findById(ssAHostId);
+ SecondaryStorageVmVO thisSecStorageVm = _secStorageVmDao.findByInstanceName(ssAHost.getName());
+
+ if (thisSecStorageVm == null) {
+ s_logger.warn("secondary storage VM " + ssAHost.getName() + " doesn't exist");
+ return false;
+ }
+
+ String copyPort = _useSSlCopy ? "443" : Integer.toString(TemplateConstants.DEFAULT_TMPLT_COPY_PORT);
+ SecStorageFirewallCfgCommand thiscpc = new SecStorageFirewallCfgCommand(true);
+ thiscpc.addPortConfig(thisSecStorageVm.getPublicIpAddress(), copyPort, true, TemplateConstants.DEFAULT_TMPLT_COPY_INTF);
+
+ QueryBuilder<HostVO> sc = QueryBuilder.create(HostVO.class);
+ sc.and(sc.entity().getType(), Op.EQ, Host.Type.SecondaryStorageVM);
+ sc.and(sc.entity().getStatus(), Op.IN, Status.Up, Status.Connecting);
+ List<HostVO> ssvms = sc.list();
+ for (HostVO ssvm : ssvms) {
+ if (ssvm.getId() == ssAHostId) {
+ continue;
+ }
+ Answer answer = _agentMgr.easySend(ssvm.getId(), thiscpc);
+ if (answer != null && answer.getResult()) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Successfully programmed firewall rules into SSVM " + ssvm.getName());
+ }
+ } else {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("failed to program firewall rules into secondary storage vm : " + ssvm.getName());
+ }
+ return false;
+ }
+ }
+
+ SecStorageFirewallCfgCommand allSSVMIpList = new SecStorageFirewallCfgCommand(false);
+ for (HostVO ssvm : ssvms) {
+ if (ssvm.getId() == ssAHostId) {
+ continue;
+ }
+ allSSVMIpList.addPortConfig(ssvm.getPublicIpAddress(), copyPort, true, TemplateConstants.DEFAULT_TMPLT_COPY_INTF);
+ }
+
+ Answer answer = _agentMgr.easySend(ssAHostId, allSSVMIpList);
+ if (answer != null && answer.getResult()) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Successfully programmed firewall rules into " + thisSecStorageVm.getHostName());
+ }
+ } else {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("failed to program firewall rules into secondary storage vm : " + thisSecStorageVm.getHostName());
+ }
+ return false;
+ }
+
+ return true;
+
+ }
+
+ protected boolean isSecondaryStorageVmRequired(long dcId) {
+ DataCenterVO dc = _dcDao.findById(dcId);
+ _dcDao.loadDetails(dc);
+ String ssvmReq = dc.getDetail(ZoneConfig.EnableSecStorageVm.key());
+ if (ssvmReq != null) {
+ return Boolean.parseBoolean(ssvmReq);
+ }
+ return true;
+ }
+
+ public SecondaryStorageVmVO startNew(long dataCenterId, SecondaryStorageVm.Role role) {
+
+ if (!isSecondaryStorageVmRequired(dataCenterId)) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Secondary storage vm not required in zone " + dataCenterId + " acc. to zone config");
+ }
+ return null;
+ }
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Assign secondary storage vm from a newly started instance for request from data center : " + dataCenterId);
+ }
+
+ Map<String, Object> context = createSecStorageVmInstance(dataCenterId, role);
+
+ long secStorageVmId = (Long)context.get("secStorageVmId");
+ if (secStorageVmId == 0) {
+ if (s_logger.isTraceEnabled()) {
+ s_logger.trace("Creating secondary storage vm instance failed, data center id : " + dataCenterId);
+ }
+
+ return null;
+ }
+
+ SecondaryStorageVmVO secStorageVm = _secStorageVmDao.findById(secStorageVmId);
+ // SecondaryStorageVmVO secStorageVm =
+ // allocSecStorageVmStorage(dataCenterId, secStorageVmId);
+ if (secStorageVm != null) {
+ SubscriptionMgr.getInstance().notifySubscribers(ALERT_SUBJECT, this,
+ new SecStorageVmAlertEventArgs(SecStorageVmAlertEventArgs.SSVM_CREATED, dataCenterId, secStorageVmId, secStorageVm, null));
+ return secStorageVm;
+ } else {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Unable to allocate secondary storage vm storage, remove the secondary storage vm record from DB, secondary storage vm id: " +
+ secStorageVmId);
+ }
+
+ SubscriptionMgr.getInstance().notifySubscribers(ALERT_SUBJECT, this,
+ new SecStorageVmAlertEventArgs(SecStorageVmAlertEventArgs.SSVM_CREATE_FAILURE, dataCenterId, secStorageVmId, null, "Unable to allocate storage"));
+ }
+ return null;
+ }
+
+ protected Map<String, Object> createSecStorageVmInstance(long dataCenterId, SecondaryStorageVm.Role role) {
+ DataStore secStore = _dataStoreMgr.getImageStore(dataCenterId);
+ if (secStore == null) {
+ String msg = "No secondary storage available in zone " + dataCenterId + ", cannot create secondary storage vm";
+ s_logger.warn(msg);
+ throw new CloudRuntimeException(msg);
+ }
+
+ long id = _secStorageVmDao.getNextInSequence(Long.class, "id");
+ String name = VirtualMachineName.getSystemVmName(id, _instance, "s").intern();
+ Account systemAcct = _accountMgr.getSystemAccount();
+
+ DataCenterDeployment plan = new DataCenterDeployment(dataCenterId);
+ DataCenter dc = _dcDao.findById(plan.getDataCenterId());
+
+ NetworkVO defaultNetwork = null;
+ if (dc.getNetworkType() == NetworkType.Advanced && dc.isSecurityGroupEnabled()) {
+ List<NetworkVO> networks = _networkDao.listByZoneSecurityGroup(dataCenterId);
+ if (networks == null || networks.size() == 0) {
+ throw new CloudRuntimeException("Can not found security enabled network in SG Zone " + dc);
+ }
+ defaultNetwork = networks.get(0);
+ } else {
+ TrafficType defaultTrafficType = TrafficType.Public;
+
+ if (dc.getNetworkType() == NetworkType.Basic || dc.isSecurityGroupEnabled()) {
+ defaultTrafficType = TrafficType.Guest;
+ }
+ List<NetworkVO> defaultNetworks = _networkDao.listByZoneAndTrafficType(dataCenterId, defaultTrafficType);
+ // api should never allow this situation to happen
+ if (defaultNetworks.size() != 1) {
+ throw new CloudRuntimeException("Found " + defaultNetworks.size() + " networks of type " + defaultTrafficType + " when expect to find 1");
+ }
+ defaultNetwork = defaultNetworks.get(0);
+ }
+
+ List<? extends NetworkOffering> offerings =
+ _networkModel.getSystemAccountNetworkOfferings(NetworkOffering.SystemControlNetwork, NetworkOffering.SystemManagementNetwork,
+ NetworkOffering.SystemStorageNetwork);
+ LinkedHashMap<Network, NicProfile> networks = new LinkedHashMap<Network, NicProfile>(offerings.size() + 1);
+ NicProfile defaultNic = new NicProfile();
+ defaultNic.setDefaultNic(true);
+ defaultNic.setDeviceId(2);
+ try {
+ networks.put(_networkMgr.setupNetwork(systemAcct, _networkOfferingDao.findById(defaultNetwork.getNetworkOfferingId()), plan, null, null, false).get(0),
+ defaultNic);
+ for (NetworkOffering offering : offerings) {
+ networks.put(_networkMgr.setupNetwork(systemAcct, offering, plan, null, null, false).get(0), null);
+ }
+ } catch (ConcurrentOperationException e) {
+ s_logger.info("Unable to setup due to concurrent operation. " + e);
+ return new HashMap<String, Object>();
+ }
+
+ VMTemplateVO template = null;
+ HypervisorType availableHypervisor = _resourceMgr.getAvailableHypervisor(dataCenterId);
+ template = _templateDao.findSystemVMReadyTemplate(dataCenterId, availableHypervisor);
+ if (template == null) {
+ throw new CloudRuntimeException("Not able to find the System templates or not downloaded in zone " + dataCenterId);
+ }
+
+ SecondaryStorageVmVO secStorageVm =
+ new SecondaryStorageVmVO(id, _serviceOffering.getId(), name, template.getId(), template.getHypervisorType(), template.getGuestOSId(), dataCenterId,
+ systemAcct.getDomainId(), systemAcct.getId(), role, _serviceOffering.getOfferHA());
+ secStorageVm.setDynamicallyScalable(template.isDynamicallyScalable());
+ secStorageVm = _secStorageVmDao.persist(secStorageVm);
+ try {
+ _itMgr.allocate(name, template, _serviceOffering, networks, plan, null);
+ secStorageVm = _secStorageVmDao.findById(secStorageVm.getId());
+ } catch (InsufficientCapacityException e) {
+ s_logger.warn("InsufficientCapacity", e);
+ throw new CloudRuntimeException("Insufficient capacity exception", e);
+ }
+
+ Map<String, Object> context = new HashMap<String, Object>();
+ context.put("secStorageVmId", secStorageVm.getId());
+ return context;
+ }
+
+ private SecondaryStorageVmAllocator getCurrentAllocator() {
+
+ // for now, only one adapter is supported
+ if (_ssVmAllocators.size() > 0) {
+ return _ssVmAllocators.get(0);
+ }
+
+ return null;
+ }
+
+ protected String connect(String ipAddress, int port) {
+ return null;
+ }
+
+ public SecondaryStorageVmVO assignSecStorageVmFromRunningPool(long dataCenterId, SecondaryStorageVm.Role role) {
+
+ if (s_logger.isTraceEnabled()) {
+ s_logger.trace("Assign secondary storage vm from running pool for request from data center : " + dataCenterId);
+ }
+
+ SecondaryStorageVmAllocator allocator = getCurrentAllocator();
+ assert (allocator != null);
+ List<SecondaryStorageVmVO> runningList = _secStorageVmDao.getSecStorageVmListInStates(role, dataCenterId, State.Running);
+ if (runningList != null && runningList.size() > 0) {
+ if (s_logger.isTraceEnabled()) {
+ s_logger.trace("Running secondary storage vm pool size : " + runningList.size());
+ for (SecondaryStorageVmVO secStorageVm : runningList) {
+ s_logger.trace("Running secStorageVm instance : " + secStorageVm.getHostName());
+ }
+ }
+
+ Map<Long, Integer> loadInfo = new HashMap<Long, Integer>();
+
+ return allocator.allocSecondaryStorageVm(runningList, loadInfo, dataCenterId);
+ } else {
+ if (s_logger.isTraceEnabled()) {
+ s_logger.trace("Empty running secStorageVm pool for now in data center : " + dataCenterId);
+ }
+ }
+ return null;
+ }
+
+ public SecondaryStorageVmVO assignSecStorageVmFromStoppedPool(long dataCenterId, SecondaryStorageVm.Role role) {
+ List<SecondaryStorageVmVO> l = _secStorageVmDao.getSecStorageVmListInStates(role, dataCenterId, State.Starting, State.Stopped, State.Migrating);
+ if (l != null && l.size() > 0) {
+ return l.get(0);
+ }
+
+ return null;
+ }
+
+ private void allocCapacity(long dataCenterId, SecondaryStorageVm.Role role) {
+ if (s_logger.isTraceEnabled()) {
+ s_logger.trace("Allocate secondary storage vm standby capacity for data center : " + dataCenterId);
+ }
+
+ if (!isSecondaryStorageVmRequired(dataCenterId)) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Secondary storage vm not required in zone " + dataCenterId + " acc. to zone config");
+ }
+ return;
+ }
+
+ boolean secStorageVmFromStoppedPool = false;
+ SecondaryStorageVmVO secStorageVm = assignSecStorageVmFromStoppedPool(dataCenterId, role);
+ if (secStorageVm == null) {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("No stopped secondary storage vm is available, need to allocate a new secondary storage vm");
+ }
+
+ if (_allocLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) {
+ try {
+ secStorageVm = startNew(dataCenterId, role);
+ for (UploadVO upload : _uploadDao.listAll()) {
+ _uploadDao.expunge(upload.getId());
+ }
+ } finally {
+ _allocLock.unlock();
+ }
+ } else {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Unable to acquire synchronization lock to allocate secStorageVm resource for standby capacity, wait for next scan");
+ }
+ return;
+ }
+ } else {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Found a stopped secondary storage vm, bring it up to running pool. secStorageVm vm id : " + secStorageVm.getId());
+ }
+ secStorageVmFromStoppedPool = true;
+ }
+
+ if (secStorageVm != null) {
+ long secStorageVmId = secStorageVm.getId();
+ GlobalLock secStorageVmLock = GlobalLock.getInternLock(getSecStorageVmLockName(secStorageVmId));
+ try {
+ if (secStorageVmLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) {
+ try {
+ secStorageVm = startSecStorageVm(secStorageVmId);
+ } finally {
+ secStorageVmLock.unlock();
+ }
+ } else {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Unable to acquire synchronization lock to start secStorageVm for standby capacity, secStorageVm vm id : " + secStorageVm.getId());
+ }
+ return;
+ }
+ } finally {
+ secStorageVmLock.releaseRef();
+ }
+
+ if (secStorageVm == null) {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Unable to start secondary storage vm for standby capacity, secStorageVm vm Id : " + secStorageVmId +
+ ", will recycle it and start a new one");
+ }
+
+ if (secStorageVmFromStoppedPool) {
+ destroySecStorageVm(secStorageVmId);
+ }
+ } else {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Secondary storage vm " + secStorageVm.getHostName() + " is started");
+ }
+ }
+ }
+ }
+
+ public boolean isZoneReady(Map<Long, ZoneHostInfo> zoneHostInfoMap, long dataCenterId) {
+ ZoneHostInfo zoneHostInfo = zoneHostInfoMap.get(dataCenterId);
+ if (zoneHostInfo != null && (zoneHostInfo.getFlags() & RunningHostInfoAgregator.ZoneHostInfo.ROUTING_HOST_MASK) != 0) {
+ VMTemplateVO template = _templateDao.findSystemVMReadyTemplate(dataCenterId, HypervisorType.Any);
+ if (template == null) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("System vm template is not ready at data center " + dataCenterId + ", wait until it is ready to launch secondary storage vm");
+ }
+ return false;
+ }
+
+ List<DataStore> stores = _dataStoreMgr.getImageStoresByScope(new ZoneScope(dataCenterId));
+ if (stores.size() < 1) {
+ s_logger.debug("No image store added in zone " + dataCenterId + ", wait until it is ready to launch secondary storage vm");
+ return false;
+ }
+
+ DataStore store = templateMgr.getImageStore(dataCenterId, template.getId());
+ if (store == null) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("No secondary storage available in zone " + dataCenterId + ", wait until it is ready to launch secondary storage vm");
+ }
+ return false;
+ }
+
+ List<Pair<Long, Integer>> l = _storagePoolHostDao.getDatacenterStoragePoolHostInfo(dataCenterId, !_useLocalStorage);
+ if (l != null && l.size() > 0 && l.get(0).second().intValue() > 0) {
+ return true;
+ } else {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Primary storage is not ready, wait until it is ready to launch secondary storage vm. dcId: " + dataCenterId +
+ " system.vm.use.local.storage: " + _useLocalStorage +
+ "If you want to use local storage to start ssvm, need to set system.vm.use.local.storage to true");
+ }
+ }
+
+ }
+ return false;
+ }
+
+ private synchronized Map<Long, ZoneHostInfo> getZoneHostInfo() {
+ Date cutTime = DateUtil.currentGMTTime();
+ List<RunningHostCountInfo> l = _hostDao.getRunningHostCounts(new Date(cutTime.getTime() - ClusterManager.HeartbeatThreshold.value()));
+
+ RunningHostInfoAgregator aggregator = new RunningHostInfoAgregator();
+ if (l.size() > 0) {
+ for (RunningHostCountInfo countInfo : l) {
+ aggregator.aggregate(countInfo);
+ }
+ }
+
+ return aggregator.getZoneHostInfoMap();
+ }
+
+ @Override
+ public boolean start() {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Start secondary storage vm manager");
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean stop() {
+ _loadScanner.stop();
+ _allocLock.releaseRef();
+ _resourceMgr.unregisterResourceStateAdapter(this.getClass().getSimpleName());
+ return true;
+ }
+
+ @Override
+ public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Start configuring secondary storage vm manager : " + name);
+ }
+
+ Map<String, String> configs = _configDao.getConfiguration("management-server", params);
+
+ _secStorageVmMtuSize = NumbersUtil.parseInt(configs.get("secstorage.vm.mtu.size"), DEFAULT_SS_VM_MTUSIZE);
+ String useServiceVM = _configDao.getValue("secondary.storage.vm");
+ boolean _useServiceVM = false;
+ if ("true".equalsIgnoreCase(useServiceVM)) {
+ _useServiceVM = true;
+ }
+
+ String sslcopy = _configDao.getValue("secstorage.encrypt.copy");
+ if ("true".equalsIgnoreCase(sslcopy)) {
+ _useSSlCopy = true;
+ }
+
+ _allowedInternalSites = _configDao.getValue("secstorage.allowed.internal.sites");
+
+ String value = configs.get("secstorage.capacityscan.interval");
+ _capacityScanInterval = NumbersUtil.parseLong(value, DEFAULT_CAPACITY_SCAN_INTERVAL);
+
+ _instance = configs.get("instance.name");
+ if (_instance == null) {
+ _instance = "DEFAULT";
+ }
+
+ Map<String, String> agentMgrConfigs = _configDao.getConfiguration("AgentManager", params);
+
+ value = agentMgrConfigs.get("port");
+ _mgmtPort = NumbersUtil.parseInt(value, 8250);
+
+ _listener = new SecondaryStorageListener(this);
+ _agentMgr.registerForHostEvents(_listener, true, false, true);
+
+ _itMgr.registerGuru(VirtualMachine.Type.SecondaryStorageVm, this);
+
+ //check if there is a default service offering configured
+ String ssvmSrvcOffIdStr = configs.get(Config.SecondaryStorageServiceOffering.key());
+ if (ssvmSrvcOffIdStr != null) {
+ Long ssvmSrvcOffId = Long.parseLong(ssvmSrvcOffIdStr);
+ _serviceOffering = _offeringDao.findById(ssvmSrvcOffId);
+ if (_serviceOffering == null || !_serviceOffering.getSystemUse()) {
+ String msg = "Can't find system service offering id=" + ssvmSrvcOffId + " for secondary storage vm";
+ s_logger.error(msg);
+ throw new ConfigurationException(msg);
+ }
+ } else {
+ int ramSize = NumbersUtil.parseInt(_configDao.getValue("ssvm.ram.size"), DEFAULT_SS_VM_RAMSIZE);
+ int cpuFreq = NumbersUtil.parseInt(_configDao.getValue("ssvm.cpu.mhz"), DEFAULT_SS_VM_CPUMHZ);
+ _useLocalStorage = Boolean.parseBoolean(configs.get(Config.SystemVMUseLocalStorage.key()));
+ _serviceOffering =
+ new ServiceOfferingVO("System Offering For Secondary Storage VM", 1, ramSize, cpuFreq, null, null, false, null, _useLocalStorage, true, null, true,
+ VirtualMachine.Type.SecondaryStorageVm, true);
+ _serviceOffering.setUniqueName(ServiceOffering.ssvmDefaultOffUniqueName);
+ _serviceOffering = _offeringDao.persistSystemServiceOffering(_serviceOffering);
+
+ // this can sometimes happen, if DB is manually or programmatically manipulated
+ if (_serviceOffering == null) {
+ String msg = "Data integrity problem : System Offering For Secondary Storage VM has been removed?";
+ s_logger.error(msg);
+ throw new ConfigurationException(msg);
+ }
+ }
+
+ if (_useServiceVM) {
+ _loadScanner = new SystemVmLoadScanner<Long>(this);
+ _loadScanner.initScan(STARTUP_DELAY, _capacityScanInterval);
+ }
+
+ _httpProxy = configs.get(Config.SecStorageProxy.key());
+ if (_httpProxy != null) {
+ boolean valid = true;
+ String errMsg = null;
+ try {
+ URI uri = new URI(_httpProxy);
+ if (!"http".equalsIgnoreCase(uri.getScheme())) {
+ errMsg = "Only support http proxy";
+ valid = false;
+ } else if (uri.getHost() == null) {
+ errMsg = "host can not be null";
+ valid = false;
+ } else if (uri.getPort() == -1) {
+ _httpProxy = _httpProxy + ":3128";
+ }
+ } catch (URISyntaxException e) {
+ errMsg = e.toString();
+ } finally {
+ if (!valid) {
+ s_logger.debug("ssvm http proxy " + _httpProxy + " is invalid: " + errMsg);
+ throw new ConfigurationException("ssvm http proxy " + _httpProxy + "is invalid: " + errMsg);
+ }
+ }
+ }
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Secondary storage vm Manager is configured.");
+ }
+ _resourceMgr.registerResourceStateAdapter(this.getClass().getSimpleName(), this);
+ return true;
+ }
+
+ @Override
+ public boolean stopSecStorageVm(long secStorageVmId) {
+ SecondaryStorageVmVO secStorageVm = _secStorageVmDao.findById(secStorageVmId);
+ if (secStorageVm == null) {
+ String msg = "Stopping secondary storage vm failed: secondary storage vm " + secStorageVmId + " no longer exists";
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug(msg);
+ }
+ return false;
+ }
+ try {
+ if (secStorageVm.getHostId() != null) {
+ GlobalLock secStorageVmLock = GlobalLock.getInternLock(getSecStorageVmLockName(secStorageVm.getId()));
+ try {
+ if (secStorageVmLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_SYNC)) {
+ try {
+ _itMgr.stop(secStorageVm.getUuid());
+ return true;
+ } finally {
+ secStorageVmLock.unlock();
+ }
+ } else {
+ String msg = "Unable to acquire secondary storage vm lock : " + secStorageVm.toString();
+ s_logger.debug(msg);
+ return false;
+ }
+ } finally {
+ secStorageVmLock.releaseRef();
+ }
+ }
+
+ // vm was already stopped, return true
+ return true;
+ } catch (ResourceUnavailableException e) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Stopping secondary storage vm " + secStorageVm.getHostName() + " faled : exception " + e.toString());
+ }
+ return false;
+ }
+ }
+
+ @Override
+ public boolean rebootSecStorageVm(long secStorageVmId) {
+ final SecondaryStorageVmVO secStorageVm = _secStorageVmDao.findById(secStorageVmId);
+
+ if (secStorageVm == null || secStorageVm.getState() == State.Destroyed) {
+ return false;
+ }
+
+ if (secStorageVm.getState() == State.Running && secStorageVm.getHostId() != null) {
+ final RebootCommand cmd = new RebootCommand(secStorageVm.getInstanceName());
+ final Answer answer = _agentMgr.easySend(secStorageVm.getHostId(), cmd);
+
+ if (answer != null && answer.getResult()) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Successfully reboot secondary storage vm " + secStorageVm.getHostName());
+ }
+
+ SubscriptionMgr.getInstance().notifySubscribers(ALERT_SUBJECT, this,
+ new SecStorageVmAlertEventArgs(SecStorageVmAlertEventArgs.SSVM_REBOOTED, secStorageVm.getDataCenterId(), secStorageVm.getId(), secStorageVm, null));
+
+ return true;
+ } else {
+ String msg = "Rebooting Secondary Storage VM failed - " + secStorageVm.getHostName();
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug(msg);
+ }
+ return false;
+ }
+ } else {
+ return startSecStorageVm(secStorageVmId) != null;
+ }
+ }
+
+ @Override
+ public boolean destroySecStorageVm(long vmId) {
+ SecondaryStorageVmVO ssvm = _secStorageVmDao.findById(vmId);
+
+ try {
+ _itMgr.expunge(ssvm.getUuid());
+ _secStorageVmDao.remove(ssvm.getId());
+ HostVO host = _hostDao.findByTypeNameAndZoneId(ssvm.getDataCenterId(), ssvm.getHostName(), Host.Type.SecondaryStorageVM);
+ if (host != null) {
+ s_logger.debug("Removing host entry for ssvm id=" + vmId);
+ _hostDao.remove(host.getId());
+ }
+
+ return true;
+ } catch (ResourceUnavailableException e) {
+ s_logger.warn("Unable to expunge " + ssvm, e);
+ return false;
+ }
+ }
+
+ @Override
+ public void onAgentConnect(Long dcId, StartupCommand cmd) {
+ }
+
+ private String getAllocLockName() {
+ // to improve security, it may be better to return a unique mashed
+ // name(for example MD5 hashed)
+ return "secStorageVm.alloc";
+ }
+
+ private String getSecStorageVmLockName(long id) {
+ return "secStorageVm." + id;
+ }
+
+ @Override
+ public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) {
+
+ SecondaryStorageVmVO vm = _secStorageVmDao.findById(profile.getId());
+ Map<String, String> details = _vmDetailsDao.listDetailsKeyPairs(vm.getId());
+ vm.setDetails(details);
+
+ DataStore secStore = _dataStoreMgr.getImageStore(dest.getDataCenter().getId());
+ assert (secStore != null);
+
+ StringBuilder buf = profile.getBootArgsBuilder();
+ buf.append(" template=domP type=secstorage");
+ buf.append(" host=").append(ApiServiceConfiguration.ManagementHostIPAdr.value());
+ buf.append(" port=").append(_mgmtPort);
+ buf.append(" name=").append(profile.getVirtualMachine().getHostName());
+
+ buf.append(" zone=").append(dest.getDataCenter().getId());
+ buf.append(" pod=").append(dest.getPod().getId());
+
+ buf.append(" guid=").append(profile.getVirtualMachine().getHostName());
+
+ if (_configDao.isPremium()) {
+ s_logger.debug("VmWare hypervisor configured, telling the ssvm to load the PremiumSecondaryStorageResource");
+ buf.append(" resource=com.cloud.storage.resource.PremiumSecondaryStorageResource");
+ } else {
+ buf.append(" resource=org.apache.cloudstack.storage.resource.NfsSecondaryStorageResource");
+ }
+ buf.append(" instance=SecStorage");
+ buf.append(" sslcopy=").append(Boolean.toString(_useSSlCopy));
+ buf.append(" role=").append(vm.getRole().toString());
+ buf.append(" mtu=").append(_secStorageVmMtuSize);
+
+ boolean externalDhcp = false;
+ String externalDhcpStr = _configDao.getValue("direct.attach.network.externalIpAllocator.enabled");
+ if (externalDhcpStr != null && externalDhcpStr.equalsIgnoreCase("true")) {
+ externalDhcp = true;
+ }
+
+ if (Boolean.valueOf(_configDao.getValue("system.vm.random.password"))) {
+ buf.append(" vmpassword=").append(_configDao.getValue("system.vm.password"));
+ }
+
+ for (NicProfile nic : profile.getNics()) {
+ int deviceId = nic.getDeviceId();
+ if (nic.getIp4Address() == null) {
+ buf.append(" eth").append(deviceId).append("mask=").append("0.0.0.0");
+ buf.append(" eth").append(deviceId).append("ip=").append("0.0.0.0");
+ } else {
+ buf.append(" eth").append(deviceId).append("ip=").append(nic.getIp4Address());
+ buf.append(" eth").append(deviceId).append("mask=").append(nic.getNetmask());
+ }
+
+ if (nic.isDefaultNic()) {
+ buf.append(" gateway=").append(nic.getGateway());
+ }
+ if (nic.getTrafficType() == TrafficType.Management) {
+ String mgmt_cidr = _configDao.getValue(Config.ManagementNetwork.key());
+ if (NetUtils.isValidCIDR(mgmt_cidr)) {
+ buf.append(" mgmtcidr=").append(mgmt_cidr);
+ }
+ buf.append(" localgw=").append(dest.getPod().getGateway());
+ buf.append(" private.network.device=").append("eth").append(deviceId);
+ } else if (nic.getTrafficType() == TrafficType.Public) {
+ buf.append(" public.network.device=").append("eth").append(deviceId);
+ } else if (nic.getTrafficType() == TrafficType.Storage) {
+ buf.append(" storageip=").append(nic.getIp4Address());
+ buf.append(" storagenetmask=").append(nic.getNetmask());
+ buf.append(" storagegateway=").append(nic.getGateway());
+ }
+ }
+
+ /* External DHCP mode */
+ if (externalDhcp) {
+ buf.append(" bootproto=dhcp");
+ }
+
+ DataCenterVO dc = _dcDao.findById(profile.getVirtualMachine().getDataCenterId());
+ buf.append(" internaldns1=").append(dc.getInternalDns1());
+ if (dc.getInternalDns2() != null) {
+ buf.append(" internaldns2=").append(dc.getInternalDns2());
+ }
+ buf.append(" dns1=").append(dc.getDns1());
+ if (dc.getDns2() != null) {
+ buf.append(" dns2=").append(dc.getDns2());
+ }
+
+ String bootArgs = buf.toString();
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Boot Args for " + profile + ": " + bootArgs);
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean finalizeDeployment(Commands cmds, VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) {
+
+ finalizeCommandsOnStart(cmds, profile);
+
+ SecondaryStorageVmVO secVm = _secStorageVmDao.findById(profile.getId());
+ DataCenter dc = dest.getDataCenter();
+ List<NicProfile> nics = profile.getNics();
+ for (NicProfile nic : nics) {
+ if ((nic.getTrafficType() == TrafficType.Public && dc.getNetworkType() == NetworkType.Advanced) ||
+ (nic.getTrafficType() == TrafficType.Guest && (dc.getNetworkType() == NetworkType.Basic || dc.isSecurityGroupEnabled()))) {
+ secVm.setPublicIpAddress(nic.getIp4Address());
+ secVm.setPublicNetmask(nic.getNetmask());
+ secVm.setPublicMacAddress(nic.getMacAddress());
+ } else if (nic.getTrafficType() == TrafficType.Management) {
+ secVm.setPrivateIpAddress(nic.getIp4Address());
+ secVm.setPrivateMacAddress(nic.getMacAddress());
+ }
+ }
+ _secStorageVmDao.update(secVm.getId(), secVm);
+ return true;
+ }
+
+ @Override
+ public boolean finalizeCommandsOnStart(Commands cmds, VirtualMachineProfile profile) {
+
+ NicProfile managementNic = null;
+ NicProfile controlNic = null;
+ for (NicProfile nic : profile.getNics()) {
+ if (nic.getTrafficType() == TrafficType.Management) {
+ managementNic = nic;
+ } else if (nic.getTrafficType() == TrafficType.Control && nic.getIp4Address() != null) {
+ controlNic = nic;
+ }
+ }
+
+ if (controlNic == null) {
+ if (managementNic == null) {
+ s_logger.error("Management network doesn't exist for the secondaryStorageVm " + profile.getVirtualMachine());
+ return false;
+ }
+ controlNic = managementNic;
+ }
+
+ // verify ssh access on management nic for system vm running on HyperV
+ if(profile.getHypervisorType() == HypervisorType.Hyperv) {
+ controlNic = managementNic;
+ }
+
+ CheckSshCommand check = new CheckSshCommand(profile.getInstanceName(), controlNic.getIp4Address(), 3922);
+ cmds.addCommand("checkSsh", check);
+
+ return true;
+ }
+
+ @Override
+ public boolean finalizeStart(VirtualMachineProfile profile, long hostId, Commands cmds, ReservationContext context) {
+ CheckSshAnswer answer = (CheckSshAnswer)cmds.getAnswer("checkSsh");
+ if (!answer.getResult()) {
+ s_logger.warn("Unable to ssh to the VM: " + answer.getDetails());
+ return false;
+ }
+
+ try {
+ //get system ip and create static nat rule for the vm in case of basic networking with EIP/ELB
+ _rulesMgr.getSystemIpAndEnableStaticNatForVm(profile.getVirtualMachine(), false);
+ IPAddressVO ipaddr = _ipAddressDao.findByAssociatedVmId(profile.getVirtualMachine().getId());
+ if (ipaddr != null && ipaddr.getSystem()) {
+ SecondaryStorageVmVO secVm = _secStorageVmDao.findById(profile.getId());
+ // override SSVM guest IP with EIP, so that download url's with be prepared with EIP
+ secVm.setPublicIpAddress(ipaddr.getAddress().addr());
+ _secStorageVmDao.update(secVm.getId(), secVm);
+ }
+ } catch (Exception ex) {
+ s_logger.warn("Failed to get system ip and enable static nat for the vm " + profile.getVirtualMachine() + " due to exception ", ex);
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public void finalizeStop(VirtualMachineProfile profile, Answer answer) {
+ //release elastic IP here
+ IPAddressVO ip = _ipAddressDao.findByAssociatedVmId(profile.getId());
+ if (ip != null && ip.getSystem()) {
+ CallContext ctx = CallContext.current();
+ try {
+ _rulesMgr.disableStaticNat(ip.getId(), ctx.getCallingAccount(), ctx.getCallingUserId(), true);
+ } catch (Exception ex) {
+ s_logger.warn("Failed to disable static nat and release system ip " + ip + " as a part of vm " + profile.getVirtualMachine() + " stop due to exception ",
+ ex);
+ }
+ }
+ }
+
+ @Override
+ public void finalizeExpunge(VirtualMachine vm) {
+ SecondaryStorageVmVO ssvm = _secStorageVmDao.findByUuid(vm.getUuid());
+
+ ssvm.setPublicIpAddress(null);
+ ssvm.setPublicMacAddress(null);
+ ssvm.setPublicNetmask(null);
+ _secStorageVmDao.update(ssvm.getId(), ssvm);
+ }
+
+ @Override
+ public String getScanHandlerName() {
+ return "secstorage";
+ }
+
+ @Override
+ public boolean canScan() {
+ return true;
+ }
+
+ @Override
+ public void onScanStart() {
+ _zoneHostInfoMap = getZoneHostInfo();
+ }
+
+ @Override
+ public Long[] getScannablePools() {
+ List<DataCenterVO> zones = _dcDao.listEnabledZones();
+
+ Long[] dcIdList = new Long[zones.size()];
+ int i = 0;
+ for (DataCenterVO dc : zones) {
+ dcIdList[i++] = dc.getId();
+ }
+
+ return dcIdList;
+ }
+
+ @Override
+ public boolean isPoolReadyForScan(Long pool) {
+ // pool is at zone basis
+ long dataCenterId = pool.longValue();
+
+ if (!isZoneReady(_zoneHostInfoMap, dataCenterId)) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Zone " + dataCenterId + " is not ready to launch secondary storage VM yet");
+ }
+ return false;
+ }
+
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Zone " + dataCenterId + " is ready to launch secondary storage VM");
+ }
+ return true;
+ }
+
+ @Override
+ public Pair<AfterScanAction, Object> scanPool(Long pool) {
+ long dataCenterId = pool.longValue();
+
+ List<SecondaryStorageVmVO> ssVms =
+ _secStorageVmDao.getSecStorageVmListInStates(SecondaryStorageVm.Role.templateProcessor, dataCenterId, State.Running, State.Migrating, State.Starting,
+ State.Stopped, State.Stopping);
+ int vmSize = (ssVms == null) ? 0 : ssVms.size();
+ List<DataStore> ssStores = _dataStoreMgr.getImageStoresByScope(new ZoneScope(dataCenterId));
+ int storeSize = (ssStores == null) ? 0 : ssStores.size();
+ if (storeSize > vmSize) {
+ s_logger.info("No secondary storage vms found in datacenter id=" + dataCenterId + ", starting a new one");
+ return new Pair<AfterScanAction, Object>(AfterScanAction.expand, SecondaryStorageVm.Role.templateProcessor);
+ }
+
+ return new Pair<AfterScanAction, Object>(AfterScanAction.nop, SecondaryStorageVm.Role.templateProcessor);
+ }
+
+ @Override
+ public void expandPool(Long pool, Object actionArgs) {
+ long dataCenterId = pool.longValue();
+ allocCapacity(dataCenterId, (SecondaryStorageVm.Role)actionArgs);
+ }
+
+ @Override
+ public void shrinkPool(Long pool, Object actionArgs) {
+ }
+
+ @Override
+ public void onScanEnd() {
+ }
+
+ @Override
+ public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] cmd) {
+ /* Called when Secondary Storage VM connected */
+ StartupCommand firstCmd = cmd[0];
+ if (!(firstCmd instanceof StartupSecondaryStorageCommand)) {
+ return null;
+ }
+
+ host.setType(com.cloud.host.Host.Type.SecondaryStorageVM);
+ return host;
+ }
+
+ @Override
+ public HostVO createHostVOForDirectConnectAgent(HostVO host, StartupCommand[] startup, ServerResource resource, Map<String, String> details, List<String> hostTags) {
+ // Used to be Called when add secondary storage on UI through DummySecondaryStorageResource to update that host entry for Secondary Storage.
+ // Now since we move secondary storage from host table, this code is not needed to be invoked anymore.
+ /*
+ StartupCommand firstCmd = startup[0];
+ if (!(firstCmd instanceof StartupStorageCommand)) {
+ return null;
+ }
+
+ com.cloud.host.Host.Type type = null;
+ StartupStorageCommand ssCmd = ((StartupStorageCommand) firstCmd);
+ if (ssCmd.getHostType() == Host.Type.SecondaryStorageCmdExecutor) {
+ type = ssCmd.getHostType();
+ } else {
+ if (ssCmd.getResourceType() == Storage.StorageResourceType.SECONDARY_STORAGE) {
+ type = Host.Type.SecondaryStorage;
+ if (resource != null && resource instanceof DummySecondaryStorageResource) {
+ host.setResource(null);
+ }
+ } else if (ssCmd.getResourceType() == Storage.StorageResourceType.LOCAL_SECONDARY_STORAGE) {
+ type = Host.Type.LocalSecondaryStorage;
+ } else {
+ type = Host.Type.Storage;
+ }
+
+ final Map<String, String> hostDetails = ssCmd.getHostDetails();
+ if (hostDetails != null) {
+ if (details != null) {
+ details.putAll(hostDetails);
+ } else {
+ details = hostDetails;
+ }
+ }
+
+ host.setDetails(details);
+ host.setParent(ssCmd.getParent());
+ host.setTotalSize(ssCmd.getTotalSize());
+ host.setHypervisorType(HypervisorType.None);
+ host.setType(type);
+ if (ssCmd.getNfsShare() != null) {
+ host.setStorageUrl(ssCmd.getNfsShare());
+ }
+ }
+ */
+ return null; // no need to handle this event anymore since secondary storage is not in host table anymore.
+ }
+
+ @Override
+ public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException {
+ // Since secondary storage is moved out of host table, this class should not handle delete secondary storage anymore.
+ return null;
+ }
+
+ @Override
+ public List<HostVO> listUpAndConnectingSecondaryStorageVmHost(Long dcId) {
+ QueryBuilder<HostVO> sc = QueryBuilder.create(HostVO.class);
+ if (dcId != null) {
+ sc.and(sc.entity().getDataCenterId(), Op.EQ, dcId);
+ }
+ sc.and(sc.entity().getState(), Op.IN, Status.Up, Status.Connecting);
+ sc.and(sc.entity().getType(), Op.EQ, Host.Type.SecondaryStorageVM);
+ return sc.list();
+ }
+
+ @Override
+ public HostVO pickSsvmHost(HostVO ssHost) {
+ if (ssHost.getType() == Host.Type.LocalSecondaryStorage) {
+ return ssHost;
+ } else if (ssHost.getType() == Host.Type.SecondaryStorage) {
+ Long dcId = ssHost.getDataCenterId();
+ List<HostVO> ssAHosts = listUpAndConnectingSecondaryStorageVmHost(dcId);
+ if (ssAHosts == null || ssAHosts.isEmpty()) {
+ return null;
+ }
+ Collections.shuffle(ssAHosts);
+ return ssAHosts.get(0);
+ }
+ return null;
+ }
+
+ @Override
+ public void prepareStop(VirtualMachineProfile profile) {
+
+ }
+
+ public List<SecondaryStorageVmAllocator> getSecondaryStorageVmAllocators() {
+ return _ssVmAllocators;
+ }
+
+ @Inject
+ public void setSecondaryStorageVmAllocators(List<SecondaryStorageVmAllocator> ssVmAllocators) {
+ _ssVmAllocators = ssVmAllocators;
+ }
+}