From ba6b2ca670e21657e838f34d8467eedb38d05bc6 Mon Sep 17 00:00:00 2001 From: anthony Date: Fri, 13 May 2011 21:19:39 -0700 Subject: [PATCH] initial checkin for multiple secondary storage --- .../agent/api/SecStorageSetupCommand.java | 42 +- .../agent/api/SecStorageVMSetupCommand.java | 58 ++ .../api/StartupSecondaryStorageCommand.java | 33 ++ .../agent/api/StartupStorageCommand.java | 6 +- .../api/storage/AbstractDownloadCommand.java | 10 +- .../api/storage/DeleteTemplateCommand.java | 11 +- .../agent/api/storage/DownloadCommand.java | 15 +- .../agent/api/storage/ListTemplateAnswer.java | 55 ++ .../api/storage/ListTemplateCommand.java | 43 ++ .../cloud/agent/api/storage/ssCommand.java | 50 ++ api/src/com/cloud/host/Host.java | 4 +- api/src/com/cloud/storage/Storage.java | 2 +- core/src/com/cloud/storage/SnapshotVO.java | 14 +- .../LocalSecondaryStorageResource.java | 29 +- .../resource/NfsSecondaryStorageResource.java | 275 ++++----- .../resource/SecondaryStorageResource.java | 30 + .../storage/template/DownloadManager.java | 13 +- .../storage/template/DownloadManagerImpl.java | 89 +-- .../cloud/storage/template/UploadManager.java | 3 +- .../storage/template/UploadManagerImpl.java | 3 +- server/src/com/cloud/agent/AgentManager.java | 3 + .../cloud/agent/manager/AgentManagerImpl.java | 555 +++++++++++++++++- server/src/com/cloud/host/dao/HostDao.java | 4 + .../src/com/cloud/host/dao/HostDaoImpl.java | 61 +- .../src/com/cloud/server/StatsCollector.java | 14 +- .../com/cloud/storage/StorageManagerImpl.java | 19 +- .../com/cloud/storage/dao/SnapshotDao.java | 1 + .../cloud/storage/dao/SnapshotDaoImpl.java | 18 + .../storage/download/DownloadListener.java | 25 +- .../storage/download/DownloadMonitor.java | 6 +- .../storage/download/DownloadMonitorImpl.java | 188 +++--- .../DummySecondaryStorageResource.java | 6 +- .../secondary/SecondaryStorageListener.java | 30 +- .../SecondaryStorageManagerImpl.java | 197 ++++--- .../secondary/SecondaryStorageVmManager.java | 5 +- .../storage/snapshot/SnapshotManager.java | 2 + .../storage/snapshot/SnapshotManagerImpl.java | 64 +- .../cloud/vm/dao/SecondaryStorageVmDao.java | 1 + .../vm/dao/SecondaryStorageVmDaoImpl.java | 20 +- setup/db/create-schema.sql | 1 + 40 files changed, 1475 insertions(+), 530 deletions(-) create mode 100644 api/src/com/cloud/agent/api/SecStorageVMSetupCommand.java create mode 100644 api/src/com/cloud/agent/api/StartupSecondaryStorageCommand.java create mode 100644 api/src/com/cloud/agent/api/storage/ListTemplateAnswer.java create mode 100644 api/src/com/cloud/agent/api/storage/ListTemplateCommand.java create mode 100644 api/src/com/cloud/agent/api/storage/ssCommand.java create mode 100755 core/src/com/cloud/storage/resource/SecondaryStorageResource.java diff --git a/api/src/com/cloud/agent/api/SecStorageSetupCommand.java b/api/src/com/cloud/agent/api/SecStorageSetupCommand.java index 1c15eb8087d..73a9d4e350b 100644 --- a/api/src/com/cloud/agent/api/SecStorageSetupCommand.java +++ b/api/src/com/cloud/agent/api/SecStorageSetupCommand.java @@ -18,22 +18,15 @@ package com.cloud.agent.api; public class SecStorageSetupCommand extends Command { - private Long dcId; - String [] allowedInternalSites = new String[0]; - String copyUserName; - String copyPassword; + private String secUrl; public SecStorageSetupCommand() { super(); } - public SecStorageSetupCommand(Long dcId) { + public SecStorageSetupCommand(String secUrl) { super(); - this.dcId = dcId; - } - - public Long getDataCenterId() { - return dcId; + this.secUrl = secUrl; } @Override @@ -41,28 +34,11 @@ public class SecStorageSetupCommand extends Command { return true; } - public String[] getAllowedInternalSites() { - return allowedInternalSites; - } - - public void setAllowedInternalSites(String[] allowedInternalSites) { - this.allowedInternalSites = allowedInternalSites; - } - - public String getCopyUserName() { - return copyUserName; - } - - public void setCopyUserName(String copyUserName) { - this.copyUserName = copyUserName; - } - - public String getCopyPassword() { - return copyPassword; - } - - public void setCopyPassword(String copyPassword) { - this.copyPassword = copyPassword; - } + public String getSecUrl() { + return secUrl; + } + public void setSecUrl(String secUrl) { + this.secUrl = secUrl; + } } diff --git a/api/src/com/cloud/agent/api/SecStorageVMSetupCommand.java b/api/src/com/cloud/agent/api/SecStorageVMSetupCommand.java new file mode 100644 index 00000000000..57755ced82b --- /dev/null +++ b/api/src/com/cloud/agent/api/SecStorageVMSetupCommand.java @@ -0,0 +1,58 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.cloud.agent.api; + +public class SecStorageVMSetupCommand extends Command { + String [] allowedInternalSites = new String[0]; + String copyUserName; + String copyPassword; + + public SecStorageVMSetupCommand() { + super(); + } + + @Override + public boolean executeInSequence() { + return true; + } + + public String[] getAllowedInternalSites() { + return allowedInternalSites; + } + + public void setAllowedInternalSites(String[] allowedInternalSites) { + this.allowedInternalSites = allowedInternalSites; + } + + public String getCopyUserName() { + return copyUserName; + } + + public void setCopyUserName(String copyUserName) { + this.copyUserName = copyUserName; + } + + public String getCopyPassword() { + return copyPassword; + } + + public void setCopyPassword(String copyPassword) { + this.copyPassword = copyPassword; + } + +} diff --git a/api/src/com/cloud/agent/api/StartupSecondaryStorageCommand.java b/api/src/com/cloud/agent/api/StartupSecondaryStorageCommand.java new file mode 100644 index 00000000000..6fbf34e1b13 --- /dev/null +++ b/api/src/com/cloud/agent/api/StartupSecondaryStorageCommand.java @@ -0,0 +1,33 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.cloud.agent.api; + +import com.cloud.host.Host; + +public class StartupSecondaryStorageCommand extends StartupCommand { + + public StartupSecondaryStorageCommand() { + super(Host.Type.ConsoleProxy); + setIqn("NoIqn"); + } + + @Override + public boolean executeInSequence() { + return true; + } +} diff --git a/api/src/com/cloud/agent/api/StartupStorageCommand.java b/api/src/com/cloud/agent/api/StartupStorageCommand.java index 65137528d88..5fabd64e66f 100755 --- a/api/src/com/cloud/agent/api/StartupStorageCommand.java +++ b/api/src/com/cloud/agent/api/StartupStorageCommand.java @@ -64,7 +64,11 @@ public class StartupStorageCommand extends StartupCommand { return parent; } - public void setNfsShare(String nfsShare) { + public void setParent(String parent) { + this.parent = parent; + } + + public void setNfsShare(String nfsShare) { this.nfsShare = nfsShare; } diff --git a/api/src/com/cloud/agent/api/storage/AbstractDownloadCommand.java b/api/src/com/cloud/agent/api/storage/AbstractDownloadCommand.java index 135dc80a33d..da008458af2 100644 --- a/api/src/com/cloud/agent/api/storage/AbstractDownloadCommand.java +++ b/api/src/com/cloud/agent/api/storage/AbstractDownloadCommand.java @@ -19,7 +19,7 @@ package com.cloud.agent.api.storage; import com.cloud.storage.Storage.ImageFormat; -public abstract class AbstractDownloadCommand extends StorageCommand { +public abstract class AbstractDownloadCommand extends ssCommand { private String url; private ImageFormat format; @@ -40,7 +40,13 @@ public abstract class AbstractDownloadCommand extends StorageCommand { } protected AbstractDownloadCommand(AbstractDownloadCommand that) { - this(that.name, that.url, that.format, that.accountId); + super(that); + assert(that.url != null); + + this.url = that.url.replace('\\', '/'); + this.format = that.format; + this.accountId = that.accountId; + this.name = that.name; } public String getUrl() { diff --git a/api/src/com/cloud/agent/api/storage/DeleteTemplateCommand.java b/api/src/com/cloud/agent/api/storage/DeleteTemplateCommand.java index 5d09d3dd9d8..16efb3f83f9 100644 --- a/api/src/com/cloud/agent/api/storage/DeleteTemplateCommand.java +++ b/api/src/com/cloud/agent/api/storage/DeleteTemplateCommand.java @@ -18,16 +18,16 @@ package com.cloud.agent.api.storage; -import com.cloud.agent.api.Command; -public class DeleteTemplateCommand extends Command { - - String templatePath; +public class DeleteTemplateCommand extends ssCommand { + private String templatePath; + public DeleteTemplateCommand() { } - public DeleteTemplateCommand(String templatePath) { + public DeleteTemplateCommand(String secUrl, String templatePath) { + this.setSecUrl(secUrl); this.templatePath = templatePath; } @@ -39,5 +39,4 @@ public class DeleteTemplateCommand extends Command { public String getTemplatePath() { return templatePath; } - } diff --git a/api/src/com/cloud/agent/api/storage/DownloadCommand.java b/api/src/com/cloud/agent/api/storage/DownloadCommand.java index 700eb0e40a4..17a1f87887b 100644 --- a/api/src/com/cloud/agent/api/storage/DownloadCommand.java +++ b/api/src/com/cloud/agent/api/storage/DownloadCommand.java @@ -64,23 +64,20 @@ public class DownloadCommand extends AbstractDownloadCommand { this.maxDownloadSizeInBytes = that.getMaxDownloadSizeInBytes(); } - public DownloadCommand(VirtualMachineTemplate template, Long maxDownloadSizeInBytes) { + public DownloadCommand(String secUrl, VirtualMachineTemplate template, Long maxDownloadSizeInBytes) { super(template.getUniqueName(), template.getUrl(), template.getFormat(), template.getAccountId()); this.hvm = template.isRequiresHvm(); this.checksum = template.getChecksum(); this.id = template.getId(); this.description = template.getDisplayText(); + this.setSecUrl(secUrl); this.maxDownloadSizeInBytes = maxDownloadSizeInBytes; } - public DownloadCommand(String url, String name, ImageFormat format, boolean isHvm, Long accountId, Long templateId, String descr, String cksum, String user, String passwd, Long maxDownloadSizeInBytes) { - super(name, url, format, accountId); - this.setHvm(isHvm); - this.description = descr; - this.checksum = cksum; - this.id = templateId; + public DownloadCommand(String secUrl, String url, VirtualMachineTemplate template, String user, String passwd, Long maxDownloadSizeInBytes) { + this(secUrl, template, maxDownloadSizeInBytes); + this.setUrl(url); auth = new PasswordAuth(user, passwd); - this.maxDownloadSizeInBytes = maxDownloadSizeInBytes; } public long getId() { @@ -103,7 +100,7 @@ public class DownloadCommand extends AbstractDownloadCommand { return checksum; } - public void setDescription(String description) { + public void setDescription(String description) { this.description = description; } diff --git a/api/src/com/cloud/agent/api/storage/ListTemplateAnswer.java b/api/src/com/cloud/agent/api/storage/ListTemplateAnswer.java new file mode 100644 index 00000000000..cba3c1f3217 --- /dev/null +++ b/api/src/com/cloud/agent/api/storage/ListTemplateAnswer.java @@ -0,0 +1,55 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.cloud.agent.api.storage; + +import java.util.Map; + +import com.cloud.agent.api.Answer; + +import com.cloud.storage.template.TemplateInfo; + +public class ListTemplateAnswer extends Answer { + private String secUrl; + private Map templateInfos; + + public ListTemplateAnswer() { + + } + + public ListTemplateAnswer(String secUrl, Map templateInfos) { + super(null, true, "success"); + this.setSecUrl(secUrl); + this.templateInfos = templateInfos; + } + + public Map getTemplateInfo() { + return templateInfos; + } + + public void setTemplateInfo(Map templateInfos) { + this.templateInfos = templateInfos; + } + + public void setSecUrl(String secUrl) { + this.secUrl = secUrl; + } + + public String getSecUrl() { + return secUrl; + } +} diff --git a/api/src/com/cloud/agent/api/storage/ListTemplateCommand.java b/api/src/com/cloud/agent/api/storage/ListTemplateCommand.java new file mode 100644 index 00000000000..ea9200e7033 --- /dev/null +++ b/api/src/com/cloud/agent/api/storage/ListTemplateCommand.java @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.cloud.agent.api.storage; + +public class ListTemplateCommand extends StorageCommand { + private String secUrl; + + public ListTemplateCommand() { + } + + public ListTemplateCommand(String secUrl) { + this.secUrl = secUrl; + } + + @Override + public boolean executeInSequence() { + return false; + } + + public String getSecUrl() { + return secUrl; + } + + public void setSecUrl(String secUrl) { + this.secUrl = secUrl; + } + +} diff --git a/api/src/com/cloud/agent/api/storage/ssCommand.java b/api/src/com/cloud/agent/api/storage/ssCommand.java new file mode 100644 index 00000000000..e99fe74e6f6 --- /dev/null +++ b/api/src/com/cloud/agent/api/storage/ssCommand.java @@ -0,0 +1,50 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.cloud.agent.api.storage; + +import com.cloud.agent.api.Command; + +public abstract class ssCommand extends Command { + private String secUrl; + + + public ssCommand() { + } + + protected ssCommand(ssCommand that) { + this.secUrl = that.secUrl; + } + public ssCommand(String secUrl) { + this.secUrl = secUrl; + } + + @Override + public boolean executeInSequence() { + return true; + } + + public String getSecUrl() { + return secUrl; + } + + public void setSecUrl(String secUrl) { + this.secUrl = secUrl; + } + +} diff --git a/api/src/com/cloud/host/Host.java b/api/src/com/cloud/host/Host.java index 69b3cccc8db..280ad33d72b 100755 --- a/api/src/com/cloud/host/Host.java +++ b/api/src/com/cloud/host/Host.java @@ -36,8 +36,10 @@ public interface Host { ExternalLoadBalancer(false), PxeServer(false), TrafficMonitor(false), - ExternalDhcp(false); + ExternalDhcp(false), + SecondaryStorageVM(true), + LocalSecondaryStorage(false); boolean _virtual; private Type(boolean virtual) { _virtual = virtual; diff --git a/api/src/com/cloud/storage/Storage.java b/api/src/com/cloud/storage/Storage.java index 66b4c1c0a8e..91213fa1f30 100644 --- a/api/src/com/cloud/storage/Storage.java +++ b/api/src/com/cloud/storage/Storage.java @@ -110,5 +110,5 @@ public class Storage { } } - public static enum StorageResourceType {STORAGE_POOL, STORAGE_HOST, SECONDARY_STORAGE} + public static enum StorageResourceType {STORAGE_POOL, STORAGE_HOST, SECONDARY_STORAGE, LOCAL_SECONDARY_STORAGE} } diff --git a/core/src/com/cloud/storage/SnapshotVO.java b/core/src/com/cloud/storage/SnapshotVO.java index 8e476007d7e..287c554d1ef 100644 --- a/core/src/com/cloud/storage/SnapshotVO.java +++ b/core/src/com/cloud/storage/SnapshotVO.java @@ -91,6 +91,9 @@ public class SnapshotVO implements Snapshot { @Column(name="swift_id") long swiftId; + @Column(name="sechost_id") + Long secHostId; + @Column(name="swift_name") String swiftName; @@ -121,7 +124,8 @@ public class SnapshotVO implements Snapshot { this.status = Status.Creating; this.prevSnapshotId = 0; this.hypervisorType = hypervisorType; - this.version = "2.2"; + this.version = "2.2"; + this.secHostId = null; } @@ -190,6 +194,14 @@ public class SnapshotVO implements Snapshot { this.swiftId = swiftId; } + public Long getSecHostId() { + return secHostId; + } + + public void setSecHostId(Long secHostId) { + this.secHostId = secHostId; + } + public String getSwiftName() { return swiftName; } diff --git a/core/src/com/cloud/storage/resource/LocalSecondaryStorageResource.java b/core/src/com/cloud/storage/resource/LocalSecondaryStorageResource.java index a19c2de700a..0833279caa7 100644 --- a/core/src/com/cloud/storage/resource/LocalSecondaryStorageResource.java +++ b/core/src/com/cloud/storage/resource/LocalSecondaryStorageResource.java @@ -32,13 +32,14 @@ import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.PingStorageCommand; import com.cloud.agent.api.ReadyAnswer; import com.cloud.agent.api.ReadyCommand; +import com.cloud.agent.api.SecStorageSetupCommand; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupStorageCommand; +import com.cloud.agent.api.storage.ssCommand; import com.cloud.agent.api.storage.DownloadCommand; import com.cloud.agent.api.storage.DownloadProgressCommand; import com.cloud.host.Host; import com.cloud.host.Host.Type; -import com.cloud.resource.ServerResource; import com.cloud.resource.ServerResourceBase; import com.cloud.storage.Storage; import com.cloud.storage.Storage.StoragePoolType; @@ -48,7 +49,7 @@ import com.cloud.storage.template.DownloadManagerImpl; import com.cloud.storage.template.TemplateInfo; import com.cloud.utils.component.ComponentLocator; -public class LocalSecondaryStorageResource extends ServerResourceBase implements ServerResource { +public class LocalSecondaryStorageResource extends ServerResourceBase implements SecondaryStorageResource { private static final Logger s_logger = Logger.getLogger(LocalSecondaryStorageResource.class); int _timeout; @@ -70,11 +71,13 @@ public class LocalSecondaryStorageResource extends ServerResourceBase implements @Override public Answer executeRequest(Command cmd) { if (cmd instanceof DownloadProgressCommand) { - return _dlMgr.handleDownloadCommand((DownloadProgressCommand)cmd); + return _dlMgr.handleDownloadCommand(this, (DownloadProgressCommand)cmd); } else if (cmd instanceof DownloadCommand) { - return _dlMgr.handleDownloadCommand((DownloadCommand)cmd); + return _dlMgr.handleDownloadCommand(this, (DownloadCommand)cmd); } else if (cmd instanceof CheckHealthCommand) { return new CheckHealthAnswer((CheckHealthCommand)cmd, true); + } else if (cmd instanceof SecStorageSetupCommand){ + return new Answer(cmd, true, "success"); } else if (cmd instanceof ReadyCommand) { return new ReadyAnswer((ReadyCommand)cmd); } else { @@ -84,7 +87,7 @@ public class LocalSecondaryStorageResource extends ServerResourceBase implements @Override public Type getType() { - return Host.Type.SecondaryStorage; + return Host.Type.LocalSecondaryStorage; } @Override @@ -92,6 +95,12 @@ public class LocalSecondaryStorageResource extends ServerResourceBase implements return new PingStorageCommand(Host.Type.Storage, id, new HashMap()); } + @Override + public String getRootDir(ssCommand cmd){ + return null; + + } + @Override @SuppressWarnings("unchecked") public boolean configure(String name, Map params) throws ConfigurationException { @@ -159,8 +168,8 @@ public class LocalSecondaryStorageResource extends ServerResourceBase implements @Override public StartupCommand[] initialize() { - final StartupStorageCommand cmd = new StartupStorageCommand(_parent, StoragePoolType.Filesystem, 1024l*1024l*1024l*1024l, _dlMgr.gatherTemplateInfo()); - cmd.setResourceType(Storage.StorageResourceType.SECONDARY_STORAGE); + final StartupStorageCommand cmd = new StartupStorageCommand(_parent, StoragePoolType.Filesystem, 1024l*1024l*1024l*1024l, _dlMgr.gatherTemplateInfo(_parent)); + cmd.setResourceType(Storage.StorageResourceType.LOCAL_SECONDARY_STORAGE); cmd.setIqn("local://"); fillNetworkInformation(cmd); cmd.setDataCenter(_dc); @@ -168,11 +177,7 @@ public class LocalSecondaryStorageResource extends ServerResourceBase implements cmd.setGuid(_guid); cmd.setName(_guid); cmd.setVersion(LocalSecondaryStorageResource.class.getPackage().getImplementationVersion()); - - /* gather TemplateInfo in second storage */ - final Map tInfo = _dlMgr.gatherTemplateInfo(); - cmd.setTemplateInfo(tInfo); - + return new StartupCommand [] {cmd}; } diff --git a/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java b/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java index 52a6a1473d5..72156a04121 100755 --- a/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java +++ b/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java @@ -26,11 +26,13 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; +import java.util.UUID; import javax.naming.ConfigurationException; @@ -48,28 +50,30 @@ import com.cloud.agent.api.PingStorageCommand; import com.cloud.agent.api.ReadyAnswer; import com.cloud.agent.api.ReadyCommand; import com.cloud.agent.api.SecStorageFirewallCfgCommand; -import com.cloud.agent.api.SecStorageFirewallCfgCommand.PortConfig; import com.cloud.agent.api.SecStorageSetupCommand; +import com.cloud.agent.api.StartupSecondaryStorageCommand; +import com.cloud.agent.api.SecStorageFirewallCfgCommand.PortConfig; +import com.cloud.agent.api.SecStorageVMSetupCommand; import com.cloud.agent.api.StartupCommand; -import com.cloud.agent.api.StartupStorageCommand; import com.cloud.agent.api.storage.CreateEntityDownloadURLCommand; import com.cloud.agent.api.storage.DeleteEntityDownloadURLCommand; import com.cloud.agent.api.storage.DeleteTemplateCommand; +import com.cloud.agent.api.storage.ListTemplateAnswer; +import com.cloud.agent.api.storage.ListTemplateCommand; +import com.cloud.agent.api.storage.ssCommand; import com.cloud.agent.api.storage.DownloadCommand; import com.cloud.agent.api.storage.DownloadProgressCommand; import com.cloud.agent.api.storage.UploadCommand; import com.cloud.host.Host; import com.cloud.host.Host.Type; -import com.cloud.resource.ServerResource; import com.cloud.resource.ServerResourceBase; -import com.cloud.storage.Storage; -import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StorageLayer; import com.cloud.storage.template.DownloadManager; import com.cloud.storage.template.DownloadManagerImpl; import com.cloud.storage.template.TemplateInfo; import com.cloud.storage.template.UploadManager; import com.cloud.storage.template.UploadManagerImpl; +import com.cloud.storage.template.DownloadManagerImpl.ZfsPathParser; import com.cloud.utils.NumbersUtil; import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.exception.CloudRuntimeException; @@ -78,18 +82,14 @@ import com.cloud.utils.net.NfsUtils; import com.cloud.utils.script.Script; import com.cloud.vm.SecondaryStorageVm; -public class NfsSecondaryStorageResource extends ServerResourceBase implements ServerResource { +public class NfsSecondaryStorageResource extends ServerResourceBase implements SecondaryStorageResource { private static final Logger s_logger = Logger.getLogger(NfsSecondaryStorageResource.class); int _timeout; - String _instance; - String _parent; - + String _instance; String _dc; String _pod; String _guid; - String _nfsPath; - String _mountParent; String _role; Map _params; StorageLayer _storage; @@ -111,24 +111,16 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S @Override public void disconnected() { - if (_parent != null && !_inSystemVM) { - Script script = new Script(!_inSystemVM, "umount", _timeout, s_logger); - script.add(_parent); - script.execute(); - - File file = new File(_parent); - file.delete(); - } } @Override public Answer executeRequest(Command cmd) { if (cmd instanceof DownloadProgressCommand) { - return _dlMgr.handleDownloadCommand((DownloadProgressCommand)cmd); + return _dlMgr.handleDownloadCommand(this, (DownloadProgressCommand)cmd); } else if (cmd instanceof DownloadCommand) { - return _dlMgr.handleDownloadCommand((DownloadCommand)cmd); + return _dlMgr.handleDownloadCommand(this, (DownloadCommand)cmd); } else if (cmd instanceof UploadCommand) { - return _upldMgr.handleUploadCommand((UploadCommand)cmd); + return _upldMgr.handleUploadCommand(this, (UploadCommand)cmd); } else if (cmd instanceof CreateEntityDownloadURLCommand){ return _upldMgr.handleCreateEntityURLCommand((CreateEntityDownloadURLCommand)cmd); } else if(cmd instanceof DeleteEntityDownloadURLCommand){ @@ -143,10 +135,14 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S return new ReadyAnswer((ReadyCommand)cmd); } else if (cmd instanceof SecStorageFirewallCfgCommand){ return execute((SecStorageFirewallCfgCommand)cmd); + } else if (cmd instanceof SecStorageVMSetupCommand){ + return execute((SecStorageVMSetupCommand)cmd); } else if (cmd instanceof SecStorageSetupCommand){ - return execute((SecStorageSetupCommand)cmd); + return execute((SecStorageSetupCommand)cmd); } else if (cmd instanceof ComputeChecksumCommand){ return execute((ComputeChecksumCommand)cmd); + } else if (cmd instanceof ListTemplateCommand){ + return execute((ListTemplateCommand)cmd); } else { return Answer.createUnsupportedCommandAnswer(cmd); } @@ -210,7 +206,40 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S return new Answer(cmd, true, checksum); } + private Answer execute(SecStorageSetupCommand cmd) { + if (!_inSystemVM){ + return new Answer(cmd, true, null); + } + String secUrl = cmd.getSecUrl(); + try { + URI uri = new URI(secUrl); + String nfsHost = uri.getHost(); + + InetAddress nfsHostAddr = InetAddress.getByName(nfsHost); + String nfsHostIp = nfsHostAddr.getHostAddress(); + + addRouteToInternalIpOrCidr(_localgw, _eth1ip, _eth1mask, nfsHostIp); + return new Answer(cmd, true, "success"); + } catch (Exception e) { + String msg = "GetRootDir for " + secUrl + " failed due to " + e.toString(); + s_logger.error(msg); + return new Answer(cmd, false, msg); + + } + } + + + private Answer execute(ListTemplateCommand cmd) { + if (!_inSystemVM){ + return new Answer(cmd, true, null); + } + String root = getRootDir(cmd.getSecUrl()); + Map templateInfos = _dlMgr.gatherTemplateInfo(root); + return new ListTemplateAnswer(cmd.getSecUrl(), templateInfos); + } + + private Answer execute(SecStorageVMSetupCommand cmd) { if (!_inSystemVM){ return new Answer(cmd, true, null); } @@ -274,8 +303,9 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S } protected GetStorageStatsAnswer execute(final GetStorageStatsCommand cmd) { - final long usedSize = getUsedSize(); - final long totalSize = getTotalSize(); + String rootDir = getRootDir(cmd.getLocalPath()); + final long usedSize = getUsedSize(rootDir); + final long totalSize = getTotalSize(rootDir); if (usedSize == -1 || totalSize == -1) { return new GetStorageStatsAnswer(cmd, "Unable to get storage stats"); } else { @@ -285,7 +315,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S protected Answer execute(final DeleteTemplateCommand cmd) { String relativeTemplatePath = cmd.getTemplatePath(); - String parent = _parent; + String parent = getRootDir(cmd); if (relativeTemplatePath.startsWith(File.separator)) { relativeTemplatePath = relativeTemplatePath.substring(1); @@ -331,12 +361,39 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S return new Answer(cmd, true, null); } - protected long getUsedSize() { - return _storage.getUsedSpace(_parent); + + public String getRootDir(String secUrl) { + try { + URI uri = new URI(secUrl); + String nfsHost = uri.getHost(); + + InetAddress nfsHostAddr = InetAddress.getByName(nfsHost); + String nfsHostIp = nfsHostAddr.getHostAddress(); + String nfsPath = nfsHostIp + ":" + uri.getPath(); + String dir = UUID.nameUUIDFromBytes(nfsPath.getBytes()).toString(); + String root = "/mnt/SecStorage/" + dir; + mount(root, nfsPath); + return root; + } catch (Exception e) { + String msg = "GetRootDir for " + secUrl + " failed due to " + e.toString(); + s_logger.error(msg, e); + throw new CloudRuntimeException(msg); + } } - protected long getTotalSize() { - return _storage.getTotalSpace(_parent); + + @Override + public String getRootDir(ssCommand cmd){ + return getRootDir(cmd.getSecUrl()); + + } + + protected long getUsedSize(String rootDir) { + return _storage.getUsedSpace(rootDir); + } + + protected long getTotalSize(String rootDir) { + return _storage.getTotalSpace(rootDir); } protected long convertFilesystemSize(final String size) { @@ -440,22 +497,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S _pod = (String)params.get("pod"); _instance = (String)params.get("instance"); - - _mountParent = (String)params.get("mount.parent"); - if (_mountParent == null) { - _mountParent = File.separator + "mnt"; - } - - if (_instance != null) { - _mountParent = _mountParent + File.separator + _instance; - } - - _nfsPath = (String)params.get("mount.path"); - if (_nfsPath == null) { - throw new ConfigurationException("Unable to find mount.path"); - } - - + String inSystemVM = (String)params.get("secondary.storage.vm"); if (inSystemVM == null || "true".equalsIgnoreCase(inSystemVM)) { @@ -473,19 +515,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S } String mgmtHost = (String)params.get("host"); - String nfsHost = NfsUtils.getHostPart(_nfsPath); - if (nfsHost == null) { - s_logger.error("Invalid or corrupt nfs url " + _nfsPath); - throw new CloudRuntimeException("Unable to determine host part of nfs path"); - } - try { - InetAddress nfsHostAddr = InetAddress.getByName(nfsHost); - nfsHost = nfsHostAddr.getHostAddress(); - } catch (UnknownHostException uhe) { - s_logger.error("Unable to resolve nfs host " + nfsHost); - throw new CloudRuntimeException("Unable to resolve nfs host to an ip address " + nfsHost); - } - addRouteToInternalIpOrCidr(_localgw, _eth1ip, _eth1mask, nfsHost); + addRouteToInternalIpOrCidr(_localgw, _eth1ip, _eth1mask, mgmtHost); if (internalDns2 != null) { addRouteToInternalIpOrCidr(_localgw, _eth1ip, _eth1mask, internalDns2); @@ -503,16 +533,8 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S _params.put("install.numthreads", "50"); _params.put("secondary.storage.vm", "true"); } - _parent = mount(_nfsPath, _mountParent); - if (_parent == null) { - throw new ConfigurationException("Unable to create mount point"); - } - - - s_logger.info("Mount point established at " + _parent); try { - _params.put("template.parent", _parent); _params.put(StorageLayer.InstanceConfigKey, _storage); _dlMgr = new DownloadManagerImpl(); _dlMgr.configure("DownloadManager", _params); @@ -615,67 +637,58 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S return result; } - protected String mount(String path, String parent) { - String mountPoint = null; - for (int i = 0; i < 10; i++) { - String mntPt = parent + File.separator + Integer.toHexString(_rand.nextInt(Integer.MAX_VALUE)); - File file = new File(mntPt); - if (!file.exists()) { - if (_storage.mkdir(mntPt)) { - mountPoint = mntPt; - break; - } + protected String mount(String root, String nfsPath) { + File file = new File(root); + if (!file.exists()) { + if (!_storage.mkdir(root)) { + s_logger.debug("create mount point: " + root); + } else { + s_logger.debug("Unable to create mount point: " + root); + return null; } - s_logger.debug("Unable to create mount: " + mntPt); - } - - if (mountPoint == null) { - s_logger.warn("Unable to create a mount point"); - return null; - } + } Script script = null; String result = null; - script = new Script(!_inSystemVM, "umount", _timeout, s_logger); - script.add(path); - result = script.execute(); - - if( _parent != null ) { - script = new Script("rmdir", _timeout, s_logger); - script.add(_parent); - result = script.execute(); + script = new Script(!_inSystemVM, "mount", _timeout, s_logger); + List res = new ArrayList(); + ZfsPathParser parser = new ZfsPathParser(root); + script.execute(parser); + res.addAll(parser.getPaths()); + for( String s : res ) { + if ( s.contains(root)) { + return root; + } } - + Script command = new Script(!_inSystemVM, "mount", _timeout, s_logger); command.add("-t", "nfs"); if (_inSystemVM) { //Fedora Core 12 errors out with any -o option executed from java command.add("-o", "soft,timeo=133,retrans=2147483647,tcp,acdirmax=0,acdirmin=0"); } - command.add(path); - command.add(mountPoint); + command.add(nfsPath); + command.add(root); result = command.execute(); if (result != null) { - s_logger.warn("Unable to mount " + path + " due to " + result); - File file = new File(mountPoint); + s_logger.warn("Unable to mount " + nfsPath + " due to " + result); + file = new File(root); if (file.exists()) file.delete(); return null; } - - // XXX: Adding the check for creation of snapshots dir here. Might have to move it somewhere more logical later. - if (!checkForSnapshotsDir(mountPoint)) { + if (!checkForSnapshotsDir(root)) { return null; } // Create the volumes dir - if (!checkForVolumesDir(mountPoint)) { + if (!checkForVolumesDir(root)) { return null; } - return mountPoint; + return root; } @Override @@ -690,62 +703,12 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S @Override public StartupCommand[] initialize() { - /*disconnected(); - - _parent = mount(_nfsPath, _mountParent); - - if( _parent == null ) { - s_logger.warn("Unable to mount the nfs server"); - return null; - } - - try { - _params.put("template.parent", _parent); - _params.put(StorageLayer.InstanceConfigKey, _storage); - _dlMgr = new DownloadManagerImpl(); - _dlMgr.configure("DownloadManager", _params); - } catch (ConfigurationException e) { - s_logger.warn("Caught problem while configuring folers", e); - return null; - }*/ - - final StartupStorageCommand cmd = new StartupStorageCommand(_parent, StoragePoolType.NetworkFilesystem, getTotalSize(), new HashMap()); - - cmd.setHostType(getType()); - cmd.setResourceType(Storage.StorageResourceType.SECONDARY_STORAGE); - cmd.setIqn(null); + final StartupSecondaryStorageCommand cmd = new StartupSecondaryStorageCommand(); fillNetworkInformation(cmd); - cmd.setDataCenter(_dc); - cmd.setPod(_pod); - cmd.setGuid(_guid); - cmd.setName(_guid); - cmd.setVersion(NfsSecondaryStorageResource.class.getPackage().getImplementationVersion()); - /* gather TemplateInfo in second storage */ - - Map tInfo = new HashMap(); - if(SecondaryStorageVm.Role.templateProcessor.toString().equals(_role)) - tInfo = _dlMgr.gatherTemplateInfo(); - cmd.setTemplateInfo(tInfo); - cmd.getHostDetails().put("mount.parent", _mountParent); - cmd.getHostDetails().put("mount.path", _nfsPath); - String tok[] = _nfsPath.split(":"); - cmd.setNfsShare("nfs://" + tok[0] + tok[1]); - if (cmd.getHostDetails().get("orig.url") == null) { - if (tok.length != 2) { - throw new CloudRuntimeException("Not valid NFS path" + _nfsPath); - } - String nfsUrl = "nfs://" + tok[0] + tok[1]; - cmd.getHostDetails().put("orig.url", nfsUrl); - } - InetAddress addr; - try { - addr = InetAddress.getByName(tok[0]); - cmd.setPrivateIpAddress(addr.getHostAddress()); - } catch (UnknownHostException e) { - cmd.setPrivateIpAddress(tok[0]); - } - return new StartupCommand [] {cmd}; + if(_publicIp != null) + cmd.setPublicIpAddress(_publicIp); + return new StartupCommand[] {cmd}; } protected boolean checkForSnapshotsDir(String mountPoint) { diff --git a/core/src/com/cloud/storage/resource/SecondaryStorageResource.java b/core/src/com/cloud/storage/resource/SecondaryStorageResource.java new file mode 100755 index 00000000000..61b730d0990 --- /dev/null +++ b/core/src/com/cloud/storage/resource/SecondaryStorageResource.java @@ -0,0 +1,30 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.cloud.storage.resource; +import com.cloud.agent.api.storage.ssCommand; +import com.cloud.resource.ServerResource; +/** + * + * SecondaryStorageServerResource is a generic container to execute commands sent + * to the agent. + */ +public interface SecondaryStorageResource extends ServerResource { + + public String getRootDir(ssCommand cmd); + +} diff --git a/core/src/com/cloud/storage/template/DownloadManager.java b/core/src/com/cloud/storage/template/DownloadManager.java index e3838f4f95c..e13894dd9e5 100644 --- a/core/src/com/cloud/storage/template/DownloadManager.java +++ b/core/src/com/cloud/storage/template/DownloadManager.java @@ -24,6 +24,7 @@ import com.cloud.agent.api.storage.DownloadAnswer; import com.cloud.agent.api.storage.DownloadCommand; import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.resource.SecondaryStorageResource; import com.cloud.utils.component.Manager; /** @@ -90,20 +91,12 @@ public interface DownloadManager extends Manager { * @param cmd cmd from server * @return answer representing status of download. */ - public DownloadAnswer handleDownloadCommand(DownloadCommand cmd); + public DownloadAnswer handleDownloadCommand(SecondaryStorageResource resource, DownloadCommand cmd); - /** - * List the paths of the public templates successfully installed in the public templates location - * @return - */ - public List listPublicTemplates(); /** /** * @return list of template info for installed templates */ - public Map gatherTemplateInfo(); - - public String getPublicTemplateRepo(); - + public Map gatherTemplateInfo(String templateDir); } \ No newline at end of file diff --git a/core/src/com/cloud/storage/template/DownloadManagerImpl.java b/core/src/com/cloud/storage/template/DownloadManagerImpl.java index f141a2610e9..4a37f6e5100 100755 --- a/core/src/com/cloud/storage/template/DownloadManagerImpl.java +++ b/core/src/com/cloud/storage/template/DownloadManagerImpl.java @@ -47,6 +47,7 @@ import com.cloud.exception.InternalErrorException; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; import com.cloud.storage.VMTemplateHostVO; +import com.cloud.storage.resource.SecondaryStorageResource; import com.cloud.storage.template.Processor.FormatInfo; import com.cloud.storage.template.TemplateDownloader.DownloadCompleteCallback; import com.cloud.storage.template.TemplateDownloader.Status; @@ -125,14 +126,6 @@ public class DownloadManagerImpl implements DownloadManager { return checksum; } - public DownloadJob(TemplateDownloader td, String jobId, DownloadCommand cmd) { - this.td = td; - this.jobId = jobId; - this.tmpltName = cmd.getName(); - this.format = cmd.getFormat(); - this.hvm = cmd.isHvm(); - } - public TemplateDownloader getTemplateDownloader() { return td; } @@ -205,8 +198,7 @@ public class DownloadManagerImpl implements DownloadManager { } public static final Logger s_logger = Logger.getLogger(DownloadManagerImpl.class); - private String parentDir; - private String publicTemplateRepo; + private String _templateDir; private String createTmpltScr; private Adapters processors; @@ -284,7 +276,7 @@ public class DownloadManagerImpl implements DownloadManager { _storage.mkdirs(templatePath); // once template path is set, remove the parent dir so that the template is installed with a relative path - String finalTemplatePath = templatePath.substring(parentDir.length()); + String finalTemplatePath = _templateDir + File.separator + dnld.getAccountId() + File.separator + dnld.getId() + File.separator; dnld.setTmpltPath(finalTemplatePath); int imgSizeGigs = (int) Math.ceil(_storage.getSize(td.getDownloadLocalPath()) * 1.0d / (1024 * 1024 * 1024)); @@ -438,11 +430,6 @@ public class DownloadManagerImpl implements DownloadManager { } } - @Override - public String getPublicTemplateRepo() { - return publicTemplateRepo; - } - @Override public String getDownloadError(String jobId) { DownloadJob dj = jobs.get(jobId); @@ -515,9 +502,9 @@ public class DownloadManagerImpl implements DownloadManager { } @Override - public DownloadAnswer handleDownloadCommand(DownloadCommand cmd) { + public DownloadAnswer handleDownloadCommand(SecondaryStorageResource resource, DownloadCommand cmd) { if (cmd instanceof DownloadProgressCommand) { - return handleDownloadProgressCmd((DownloadProgressCommand) cmd); + return handleDownloadProgressCmd( resource, (DownloadProgressCommand) cmd); } if (cmd.getUrl() == null) { @@ -527,9 +514,9 @@ public class DownloadManagerImpl implements DownloadManager { if (cmd.getName() == null) { return new DownloadAnswer("Invalid Name", VMTemplateStorageResourceAssoc.Status.DOWNLOAD_ERROR); } - + String installPathPrefix = null; - installPathPrefix = publicTemplateRepo; + installPathPrefix = resource.getRootDir(cmd) + File.separator + _templateDir; String user = null; String password = null; @@ -556,7 +543,7 @@ public class DownloadManagerImpl implements DownloadManager { } } - private DownloadAnswer handleDownloadProgressCmd(DownloadProgressCommand cmd) { + private DownloadAnswer handleDownloadProgressCmd(SecondaryStorageResource resource, DownloadProgressCommand cmd) { String jobId = cmd.getJobId(); DownloadAnswer answer; DownloadJob dj = null; @@ -565,7 +552,7 @@ public class DownloadManagerImpl implements DownloadManager { if (dj == null) { if (cmd.getRequest() == RequestType.GET_OR_RESTART) { DownloadCommand dcmd = new DownloadCommand(cmd); - return handleDownloadCommand(dcmd); + return handleDownloadCommand(resource, dcmd); } else { return new DownloadAnswer("Cannot find job", VMTemplateStorageResourceAssoc.Status.DOWNLOAD_ERROR.UNKNOWN); } @@ -614,11 +601,6 @@ public class DownloadManagerImpl implements DownloadManager { } - @Override - public List listPublicTemplates() { - return listTemplates(publicTemplateRepo); - } - private List listTemplates(String rootdir) { List result = new ArrayList(); Script script = new Script(listTmpltScr, s_logger); @@ -631,9 +613,10 @@ public class DownloadManagerImpl implements DownloadManager { } @Override - public Map gatherTemplateInfo() { + public Map gatherTemplateInfo(String rootDir) { Map result = new HashMap(); - List publicTmplts = listPublicTemplates(); + String templateDir = rootDir + File.separator + _templateDir; + List publicTmplts = listTemplates(templateDir); for (String tmplt : publicTmplts) { String path = tmplt.substring(0, tmplt.lastIndexOf(File.separator)); TemplateLocation loc = new TemplateLocation(_storage, path); @@ -641,14 +624,14 @@ public class DownloadManagerImpl implements DownloadManager { if (!loc.load()) { s_logger.warn("Post download installation was not completed for " + path); loc.purge(); - _storage.cleanup(path, publicTemplateRepo); + _storage.cleanup(path, templateDir); continue; } } catch (IOException e) { s_logger.warn("Unable to load template location " + path, e); loc.purge(); try { - _storage.cleanup(path, publicTemplateRepo); + _storage.cleanup(path, templateDir); } catch (IOException e1) { s_logger.warn("Unable to cleanup " + path, e1); } @@ -747,7 +730,6 @@ public class DownloadManagerImpl implements DownloadManager { _sslCopy = Boolean.parseBoolean(useSsl); } - configureFolders(name, params); String inSystemVM = (String)params.get("secondary.storage.vm"); if (inSystemVM != null && "true".equalsIgnoreCase(inSystemVM)) { s_logger.info("DownloadManager: starting additional services since we are inside system vm"); @@ -797,6 +779,12 @@ public class DownloadManagerImpl implements DownloadManager { processors.add(new ComponentInfo("VMDK Processor", VmdkProcessor.class, processor)); _processors = new Adapters("processors", processors); + + _templateDir = (String) params.get("public.templates.root.dir"); + if (_templateDir == null) { + _templateDir = TemplateConstants.DEFAULT_TMPLT_ROOT_DIR; + } + _templateDir += File.separator + TemplateConstants.DEFAULT_TMPLT_FIRST_LEVEL_DIR; // Add more processors here. threadPool = Executors.newFixedThreadPool(numInstallThreads); return true; @@ -816,34 +804,6 @@ public class DownloadManagerImpl implements DownloadManager { } } - protected void configureFolders(String name, Map params) throws ConfigurationException { - parentDir = (String) params.get("template.parent"); - if (parentDir == null) { - throw new ConfigurationException("Unable to find the parent root for the templates"); - } - - String value = (String) params.get("public.templates.root.dir"); - if (value == null) { - value = TemplateConstants.DEFAULT_TMPLT_ROOT_DIR; - } - - if (value.startsWith(File.separator)) { - publicTemplateRepo = value; - } else { - publicTemplateRepo = parentDir + File.separator + value; - } - - if (!publicTemplateRepo.endsWith(File.separator)) { - publicTemplateRepo += File.separator; - } - - publicTemplateRepo += TemplateConstants.DEFAULT_TMPLT_FIRST_LEVEL_DIR; - - if (!_storage.mkdirs(publicTemplateRepo)) { - throw new ConfigurationException("Unable to create public templates directory"); - } - } - @Override public String getName() { return _name; @@ -898,14 +858,5 @@ public class DownloadManagerImpl implements DownloadManager { s_logger.warn("Error in creating directory =" + result ); return; } - - command = new Script("/bin/bash", s_logger); - command.add("-c"); - command.add("ln -sf " + publicTemplateRepo + " /var/www/html/copy/template"); - result = command.execute(); - if (result != null) { - s_logger.warn("Error in linking err=" + result ); - return; - } } } diff --git a/core/src/com/cloud/storage/template/UploadManager.java b/core/src/com/cloud/storage/template/UploadManager.java index d06cb6bd35e..4745bfbcfd2 100755 --- a/core/src/com/cloud/storage/template/UploadManager.java +++ b/core/src/com/cloud/storage/template/UploadManager.java @@ -26,6 +26,7 @@ import com.cloud.agent.api.storage.UploadAnswer; import com.cloud.agent.api.storage.UploadCommand; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Upload.Status; +import com.cloud.storage.resource.SecondaryStorageResource; import com.cloud.utils.component.Manager; public interface UploadManager extends Manager { @@ -70,7 +71,7 @@ public interface UploadManager extends Manager { * @param cmd cmd from server * @return answer representing status of upload. */ - public UploadAnswer handleUploadCommand(UploadCommand cmd); + public UploadAnswer handleUploadCommand(SecondaryStorageResource resource, UploadCommand cmd); public String getPublicTemplateRepo(); diff --git a/core/src/com/cloud/storage/template/UploadManagerImpl.java b/core/src/com/cloud/storage/template/UploadManagerImpl.java index 10b2a3fecdf..4dd2269cbe1 100755 --- a/core/src/com/cloud/storage/template/UploadManagerImpl.java +++ b/core/src/com/cloud/storage/template/UploadManagerImpl.java @@ -44,6 +44,7 @@ import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageLayer; import com.cloud.storage.Upload; import com.cloud.storage.UploadVO; +import com.cloud.storage.resource.SecondaryStorageResource; import com.cloud.storage.template.TemplateUploader.Status; import com.cloud.storage.template.TemplateUploader.UploadCompleteCallback; import com.cloud.utils.NumbersUtil; @@ -319,7 +320,7 @@ public class UploadManagerImpl implements UploadManager { } @Override - public UploadAnswer handleUploadCommand(UploadCommand cmd) { + public UploadAnswer handleUploadCommand(SecondaryStorageResource resource, UploadCommand cmd) { s_logger.warn("Handling the upload " +cmd.getInstallPath() + " " + cmd.getId()); if (cmd instanceof UploadProgressCommand) { return handleUploadProgressCmd((UploadProgressCommand) cmd); diff --git a/server/src/com/cloud/agent/AgentManager.java b/server/src/com/cloud/agent/AgentManager.java index cda55e06791..ac85a36f189 100755 --- a/server/src/com/cloud/agent/AgentManager.java +++ b/server/src/com/cloud/agent/AgentManager.java @@ -264,4 +264,7 @@ public interface AgentManager extends Manager { boolean updateHostPassword(UpdateHostPasswordCmd upasscmd); + long sendToSecStorage(HostVO ssHost, Command cmd, Listener listener); + + Answer sendToSecStorage(HostVO ssHost, Command cmd); } diff --git a/server/src/com/cloud/agent/manager/AgentManagerImpl.java b/server/src/com/cloud/agent/manager/AgentManagerImpl.java index 1550b30b5b4..1e06f546353 100755 --- a/server/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/server/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -65,6 +65,7 @@ import com.cloud.agent.api.StartupExternalLoadBalancerCommand; import com.cloud.agent.api.StartupProxyCommand; import com.cloud.agent.api.StartupPxeServerCommand; import com.cloud.agent.api.StartupRoutingCommand; +import com.cloud.agent.api.StartupSecondaryStorageCommand; import com.cloud.agent.api.StartupStorageCommand; import com.cloud.agent.api.StartupTrafficMonitorCommand; import com.cloud.agent.api.UnsupportedAnswer; @@ -501,6 +502,549 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager { return attache; } + @Override + public List discoverCluster(AddClusterCmd cmd) throws IllegalArgumentException, DiscoveryException { + Long dcId = cmd.getZoneId(); + Long podId = cmd.getPodId(); + String clusterName = cmd.getClusterName(); + String url = cmd.getUrl(); + String username = cmd.getUsername(); + String password = cmd.getPassword(); + + if(url != null) { + url = URLDecoder.decode(url); + } + + URI uri = null; + + // Check if the zone exists in the system + DataCenterVO zone = _dcDao.findById(dcId); + if (zone == null) { + throw new InvalidParameterValueException("Can't find zone by id " + dcId); + } + + Account account = UserContext.current().getCaller(); + if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(account.getType())) { + throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + dcId); + } + + // Check if the pod exists in the system + if (podId != null) { + if (_podDao.findById(podId) == null) { + throw new InvalidParameterValueException("Can't find pod by id " + podId); + } + // check if pod belongs to the zone + HostPodVO pod = _podDao.findById(podId); + if (!Long.valueOf(pod.getDataCenterId()).equals(dcId)) { + throw new InvalidParameterValueException("Pod " + podId + " doesn't belong to the zone " + dcId); + } + } + + // Verify cluster information and create a new cluster if needed + if (clusterName == null || clusterName.isEmpty()) { + throw new InvalidParameterValueException("Please specify cluster name"); + } + + if (cmd.getHypervisor() == null || cmd.getHypervisor().isEmpty()) { + throw new InvalidParameterValueException("Please specify a hypervisor"); + } + + Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.getType(cmd.getHypervisor()); + if (hypervisorType == null) { + s_logger.error("Unable to resolve " + cmd.getHypervisor() + " to a valid supported hypervisor type"); + throw new InvalidParameterValueException("Unable to resolve " + cmd.getHypervisor() + " to a supported "); + } + + Cluster.ClusterType clusterType = null; + if (cmd.getClusterType() != null && !cmd.getClusterType().isEmpty()) { + clusterType = Cluster.ClusterType.valueOf(cmd.getClusterType()); + } + if (clusterType == null) { + clusterType = Cluster.ClusterType.CloudManaged; + } + + Grouping.AllocationState allocationState = null; + if (cmd.getAllocationState() != null && !cmd.getAllocationState().isEmpty()) { + try { + allocationState = Grouping.AllocationState.valueOf(cmd.getAllocationState()); + } catch (IllegalArgumentException ex) { + throw new InvalidParameterValueException("Unable to resolve Allocation State '" + cmd.getAllocationState() + "' to a supported state"); + } + } + if (allocationState == null) { + allocationState = Grouping.AllocationState.Enabled; + } + + Discoverer discoverer = getMatchingDiscover(hypervisorType); + if (discoverer == null) { + + throw new InvalidParameterValueException("Could not find corresponding resource manager for " + cmd.getHypervisor()); + } + + List result = new ArrayList(); + + long clusterId = 0; + ClusterVO cluster = new ClusterVO(dcId, podId, clusterName); + cluster.setHypervisorType(cmd.getHypervisor()); + + cluster.setClusterType(clusterType); + cluster.setAllocationState(allocationState); + try { + cluster = _clusterDao.persist(cluster); + } catch (Exception e) { + // no longer tolerate exception during the cluster creation phase + throw new CloudRuntimeException("Unable to create cluster " + clusterName + " in pod " + podId + " and data center " + dcId, e); + } + clusterId = cluster.getId(); + result.add(cluster); + + if (clusterType == Cluster.ClusterType.CloudManaged) { + return result; + } + + // save cluster details for later cluster/host cross-checking + Map details = new HashMap(); + details.put("url", url); + details.put("username", username); + details.put("password", password); + _clusterDetailsDao.persist(cluster.getId(), details); + + boolean success = false; + try { + try { + uri = new URI(UriUtils.encodeURIComponent(url)); + if (uri.getScheme() == null) { + throw new InvalidParameterValueException("uri.scheme is null " + url + ", add http:// as a prefix"); + } else if (uri.getScheme().equalsIgnoreCase("http")) { + if (uri.getHost() == null || uri.getHost().equalsIgnoreCase("") || uri.getPath() == null || uri.getPath().equalsIgnoreCase("")) { + throw new InvalidParameterValueException("Your host and/or path is wrong. Make sure it's of the format http://hostname/path"); + } + } + } catch (URISyntaxException e) { + throw new InvalidParameterValueException(url + " is not a valid uri"); + } + + List hosts = new ArrayList(); + Map> resources = null; + + try { + resources = discoverer.find(dcId, podId, clusterId, uri, username, password); + } catch (Exception e) { + s_logger.info("Exception in external cluster discovery process with discoverer: " + discoverer.getName()); + } + if (resources != null) { + for (Map.Entry> entry : resources.entrySet()) { + ServerResource resource = entry.getKey(); + + // For Hyper-V, we are here means agent have already started and connected to management server + if (hypervisorType == Hypervisor.HypervisorType.Hyperv) { + break; + } + + AgentAttache attache = simulateStart(null, resource, entry.getValue(), true, null, null); + if (attache != null) { + hosts.add(_hostDao.findById(attache.getId())); + } + discoverer.postDiscovery(hosts, _nodeId); + } + s_logger.info("External cluster has been successfully discovered by " + discoverer.getName()); + success = true; + return result; + } + + s_logger.warn("Unable to find the server resources at " + url); + throw new DiscoveryException("Unable to add the external cluster"); + } catch (Throwable e) { + s_logger.error("Unexpected exception ", e); + throw new DiscoveryException("Unable to add the external cluster due to unhandled exception"); + } finally { + if (!success) { + _clusterDetailsDao.deleteDetails(clusterId); + _clusterDao.remove(clusterId); + } + } + } + + private Discoverer getMatchingDiscover(Hypervisor.HypervisorType hypervisorType) { + Enumeration en = _discoverers.enumeration(); + while (en.hasMoreElements()) { + Discoverer discoverer = en.nextElement(); + if (discoverer.getHypervisorType() == hypervisorType) { + return discoverer; + } + } + return null; + } + + @Override + public List discoverHosts(AddHostCmd cmd) throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException { + Long dcId = cmd.getZoneId(); + Long podId = cmd.getPodId(); + Long clusterId = cmd.getClusterId(); + String clusterName = cmd.getClusterName(); + String url = cmd.getUrl(); + String username = cmd.getUsername(); + String password = cmd.getPassword(); + Long memCapacity = cmd.getMemCapacity(); + Long cpuSpeed = cmd.getCpuSpeed(); + Long cpuNum = cmd.getCpuNum(); + String mac = cmd.getMac(); + List hostTags = cmd.getHostTags(); + Map bareMetalParams = new HashMap(); + + dcId = _accountMgr.checkAccessAndSpecifyAuthority(UserContext.current().getCaller(), dcId); + + // this is for standalone option + if (clusterName == null && clusterId == null) { + clusterName = "Standalone-" + url; + } + + if ( clusterId != null ) { + ClusterVO cluster = _clusterDao.findById(clusterId); + if ( cluster == null ) { + throw new InvalidParameterValueException("can not fine cluster for clusterId " + clusterId); + } else { + if ( cluster.getGuid() == null ) { + List hosts = _hostDao.listByCluster(clusterId); + if ( ! hosts.isEmpty() ) { + throw new CloudRuntimeException("Guid is not updated for cluster " + clusterId + " need to wait hosts in this cluster up"); + } + } + } + } + + if (cmd.getHypervisor().equalsIgnoreCase(Hypervisor.HypervisorType.BareMetal.toString())) { + if (memCapacity == null) { + memCapacity = Long.valueOf(0); + } + if (cpuSpeed == null) { + cpuSpeed = Long.valueOf(0); + } + if (cpuNum == null) { + cpuNum = Long.valueOf(0); + } + if (mac == null) { + mac = "unknown"; + } + + bareMetalParams.put("cpuNum", cpuNum.toString()); + bareMetalParams.put("cpuCapacity", cpuSpeed.toString()); + bareMetalParams.put("memCapacity", memCapacity.toString()); + bareMetalParams.put("mac", mac); + if (hostTags != null) { + bareMetalParams.put("hostTag", hostTags.get(0)); + } + } + String allocationState = cmd.getAllocationState(); + if (allocationState == null) { + allocationState = Host.HostAllocationState.Enabled.toString(); + } + + return discoverHostsFull(dcId, podId, clusterId, clusterName, url, username, password, cmd.getHypervisor(), hostTags, bareMetalParams, allocationState); + } + + @Override + public List discoverHosts(AddSecondaryStorageCmd cmd) throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException { + Long dcId = cmd.getZoneId(); + String url = cmd.getUrl(); + return discoverHosts(dcId, null, null, null, url, null, null, "SecondaryStorage", null); + } + + @Override + public List discoverHosts(Long dcId, Long podId, Long clusterId, String clusterName, String url, String username, String password, String hypervisorType, List hostTags) + throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException { + return discoverHostsFull(dcId, podId, clusterId, clusterName, url, username, password, hypervisorType, hostTags, null, null); + } + + private List discoverHostsFull(Long dcId, Long podId, Long clusterId, String clusterName, String url, String username, String password, String hypervisorType, List hostTags, + Map params, String allocationState) throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException { + URI uri = null; + + // Check if the zone exists in the system + DataCenterVO zone = _dcDao.findById(dcId); + if (zone == null) { + throw new InvalidParameterValueException("Can't find zone by id " + dcId); + } + + Account account = UserContext.current().getCaller(); + if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(account.getType())) { + throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + dcId); + } + + // Check if the pod exists in the system + if (podId != null) { + if (_podDao.findById(podId) == null) { + throw new InvalidParameterValueException("Can't find pod by id " + podId); + } + // check if pod belongs to the zone + HostPodVO pod = _podDao.findById(podId); + if (!Long.valueOf(pod.getDataCenterId()).equals(dcId)) { + throw new InvalidParameterValueException("Pod " + podId + " doesn't belong to the zone " + dcId); + } + } + + // Verify cluster information and create a new cluster if needed + if (clusterName != null && clusterId != null) { + throw new InvalidParameterValueException("Can't specify cluster by both id and name"); + } + + if (hypervisorType == null || hypervisorType.isEmpty()) { + throw new InvalidParameterValueException("Need to specify Hypervisor Type"); + } + + if ((clusterName != null || clusterId != null) && podId == null) { + throw new InvalidParameterValueException("Can't specify cluster without specifying the pod"); + } + + if (clusterId != null) { + if (_clusterDao.findById(clusterId) == null) { + throw new InvalidParameterValueException("Can't find cluster by id " + clusterId); + } + } + + if (clusterName != null) { + ClusterVO cluster = new ClusterVO(dcId, podId, clusterName); + cluster.setHypervisorType(hypervisorType); + try { + cluster = _clusterDao.persist(cluster); + } catch (Exception e) { + cluster = _clusterDao.findBy(clusterName, podId); + if (cluster == null) { + throw new CloudRuntimeException("Unable to create cluster " + clusterName + " in pod " + podId + " and data center " + dcId, e); + } + } + clusterId = cluster.getId(); + } + + try { + uri = new URI(UriUtils.encodeURIComponent(url)); + if (uri.getScheme() == null) { + throw new InvalidParameterValueException("uri.scheme is null " + url + ", add nfs:// as a prefix"); + } else if (uri.getScheme().equalsIgnoreCase("nfs")) { + if (uri.getHost() == null || uri.getHost().equalsIgnoreCase("") || uri.getPath() == null || uri.getPath().equalsIgnoreCase("")) { + throw new InvalidParameterValueException("Your host and/or path is wrong. Make sure it's of the format nfs://hostname/path"); + } + } + } catch (URISyntaxException e) { + throw new InvalidParameterValueException(url + " is not a valid uri"); + } + + List hosts = new ArrayList(); + s_logger.info("Trying to add a new host at " + url + " in data center " + dcId); + Enumeration en = _discoverers.enumeration(); + boolean isHypervisorTypeSupported = false; + while (en.hasMoreElements()) { + Discoverer discoverer = en.nextElement(); + if (params != null) { + discoverer.putParam(params); + } + + if (!discoverer.matchHypervisor(hypervisorType)) { + continue; + } + isHypervisorTypeSupported = true; + Map> resources = null; + + try { + resources = discoverer.find(dcId, podId, clusterId, uri, username, password); + } catch (DiscoveredWithErrorException e) { + throw e; + } catch (Exception e) { + s_logger.info("Exception in host discovery process with discoverer: " + discoverer.getName() + ", skip to another discoverer if there is any"); + } + if (resources != null) { + for (Map.Entry> entry : resources.entrySet()) { + ServerResource resource = entry.getKey(); + /* + * For KVM, if we go to here, that means kvm agent is already connected to mgt svr. + */ + if (resource instanceof KvmDummyResourceBase) { + Map details = entry.getValue(); + String guid = details.get("guid"); + List kvmHosts = _hostDao.listBy(Host.Type.Routing, clusterId, podId, dcId); + for (HostVO host : kvmHosts) { + if (host.getGuid().equalsIgnoreCase(guid)) { + hosts.add(host); + return hosts; + } + } + return null; + } + AgentAttache attache = simulateStart(null, resource, entry.getValue(), true, hostTags, allocationState); + if (attache != null) { + hosts.add(_hostDao.findById(attache.getId())); + } + discoverer.postDiscovery(hosts, _nodeId); + + } + s_logger.info("server resources successfully discovered by " + discoverer.getName()); + return hosts; + } + } + if (!isHypervisorTypeSupported) { + String msg = "Do not support HypervisorType " + hypervisorType + " for " + url; + s_logger.warn(msg); + throw new DiscoveryException(msg); + } + s_logger.warn("Unable to find the server resources at " + url); + throw new DiscoveryException("Unable to add the host"); + } + + @Override + @DB + public boolean deleteCluster(DeleteClusterCmd cmd) { + Transaction txn = Transaction.currentTxn(); + try { + txn.start(); + ClusterVO cluster = _clusterDao.lockRow(cmd.getId(), true); + if (cluster == null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Cluster: " + cmd.getId() + " does not even exist. Delete call is ignored."); + } + txn.rollback(); + return true; + } + + List hosts = _hostDao.listByCluster(cmd.getId()); + if (hosts.size() > 0) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Cluster: " + cmd.getId() + " still has hosts"); + } + txn.rollback(); + return false; + } + + _clusterDao.remove(cmd.getId()); + + txn.commit(); + return true; + } catch (Throwable t) { + s_logger.error("Unable to delete cluster: " + cmd.getId(), t); + txn.rollback(); + return false; + } + } + + @Override + @DB + public Cluster updateCluster(Cluster clusterToUpdate, String clusterType, String hypervisor, String allocationState) { + + ClusterVO cluster = (ClusterVO) clusterToUpdate; + // Verify cluster information and update the cluster if needed + boolean doUpdate = false; + + if (hypervisor != null && !hypervisor.isEmpty()) { + Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.getType(hypervisor); + if (hypervisorType == null) { + s_logger.error("Unable to resolve " + hypervisor + " to a valid supported hypervisor type"); + throw new InvalidParameterValueException("Unable to resolve " + hypervisor + " to a supported type"); + } else { + cluster.setHypervisorType(hypervisor); + doUpdate = true; + } + } + + Cluster.ClusterType newClusterType = null; + if (clusterType != null && !clusterType.isEmpty()) { + try { + newClusterType = Cluster.ClusterType.valueOf(clusterType); + } catch (IllegalArgumentException ex) { + throw new InvalidParameterValueException("Unable to resolve " + clusterType + " to a supported type"); + } + if (newClusterType == null) { + s_logger.error("Unable to resolve " + clusterType + " to a valid supported cluster type"); + throw new InvalidParameterValueException("Unable to resolve " + clusterType + " to a supported type"); + } else { + cluster.setClusterType(newClusterType); + doUpdate = true; + } + } + + Grouping.AllocationState newAllocationState = null; + if (allocationState != null && !allocationState.isEmpty()) { + try { + newAllocationState = Grouping.AllocationState.valueOf(allocationState); + } catch (IllegalArgumentException ex) { + throw new InvalidParameterValueException("Unable to resolve Allocation State '" + allocationState + "' to a supported state"); + } + if (newAllocationState == null) { + s_logger.error("Unable to resolve " + allocationState + " to a valid supported allocation State"); + throw new InvalidParameterValueException("Unable to resolve " + allocationState + " to a supported state"); + } else { + cluster.setAllocationState(newAllocationState); + doUpdate = true; + } + } + if (doUpdate) { + Transaction txn = Transaction.currentTxn(); + try { + txn.start(); + _clusterDao.update(cluster.getId(), cluster); + txn.commit(); + } catch (Exception e) { + s_logger.error("Unable to update cluster due to " + e.getMessage(), e); + throw new CloudRuntimeException("Failed to update cluster. Please contact Cloud Support."); + } + } + return cluster; + } + + @Override + public Cluster getCluster(Long clusterId) { + return _clusterDao.findById(clusterId); + } + + @Override + public Answer sendToSecStorage(HostVO ssHost, Command cmd) { + if( ssHost.getType() == Host.Type.LocalSecondaryStorage ) { + return easySend(ssHost.getId(), cmd); + } else if ( ssHost.getType() == Host.Type.SecondaryStorage) { + return sendToSSVM(ssHost.getDataCenterId(), cmd); + } else { + String msg = "do not support Secondary Storage type " + ssHost.getType(); + s_logger.warn(msg); + return new Answer(cmd, false, msg); + } + } + + @Override + public long sendToSecStorage(HostVO ssHost, Command cmd, Listener listener) { + if( ssHost.getType() == Host.Type.LocalSecondaryStorage ) { + return gatherStats(ssHost.getId(), cmd, listener); + } else if ( ssHost.getType() == Host.Type.SecondaryStorage) { + return sendToSSVM(ssHost.getDataCenterId(), cmd, listener); + } else { + s_logger.warn("do not support Secondary Storage type " + ssHost.getType()); + } + return -1; + } + + + private long sendToSSVM(final long dcId, final Command cmd, final Listener listener) { + List ssAHosts = _hostDao.listByTypeDataCenter(Host.Type.SecondaryStorageVM, dcId); + if (ssAHosts == null || ssAHosts.isEmpty() ) { + return -1; + } + int size = ssAHosts.size(); + Random rn = new Random(System.currentTimeMillis()); + HostVO ssAhost = ssAHosts.get(rn.nextInt(size)); + try { + return send(ssAhost.getId(), new Commands(cmd), listener); + } catch (final AgentUnavailableException e) { + return -1; + } + } + + private Answer sendToSSVM(final long dcId, final Command cmd) { + List ssAHosts = _hostDao.listByTypeDataCenter(Host.Type.SecondaryStorageVM, dcId); + if (ssAHosts == null || ssAHosts.isEmpty() ) { + return new Answer(cmd, false, "can not find secondary storage VM agent for data center " + dcId); + } + int size = ssAHosts.size(); + Random rn = new Random(System.currentTimeMillis()); + HostVO ssAhost = ssAHosts.get(rn.nextInt(size)); + return easySend(ssAhost.getId(), cmd); + } @Override public Answer sendTo(Long dcId, HypervisorType type, Command cmd) { @@ -889,6 +1433,9 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager { return seq; } + + + @Override public long gatherStats(final Long hostId, final Command cmd, final Listener listener) { try { @@ -1738,9 +2285,13 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager { if (resource != null && resource instanceof DummySecondaryStorageResource) { resource = null; } + }else if (ssCmd.getResourceType() == Storage.StorageResourceType.LOCAL_SECONDARY_STORAGE) { + type = Host.Type.LocalSecondaryStorage; + } else { type = Host.Type.Storage; } + final Map hostDetails = ssCmd.getHostDetails(); if (hostDetails != null) { if (details != null) { @@ -1761,10 +2312,10 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, Manager { details = hostDetails; } } + } else if (startup instanceof StartupSecondaryStorageCommand) { + type = Host.Type.SecondaryStorageVM; } else if (startup instanceof StartupProxyCommand) { type = Host.Type.ConsoleProxy; - } else if (startup instanceof StartupRoutingCommand) { - type = Host.Type.Routing; } else if (startup instanceof StartupExternalFirewallCommand) { type = Host.Type.ExternalFirewall; } else if (startup instanceof StartupExternalLoadBalancerCommand) { diff --git a/server/src/com/cloud/host/dao/HostDao.java b/server/src/com/cloud/host/dao/HostDao.java index 663376ca143..54f2214c4a1 100644 --- a/server/src/com/cloud/host/dao/HostDao.java +++ b/server/src/com/cloud/host/dao/HostDao.java @@ -169,4 +169,8 @@ public interface HostDao extends GenericDao { boolean directConnect(HostVO host, long msId, boolean secondConnect); HostVO findTrafficMonitorHost(); + + List listLocalSecondaryStorageHosts(); + + List listLocalSecondaryStorageHosts(long dataCenterId); } diff --git a/server/src/com/cloud/host/dao/HostDaoImpl.java b/server/src/com/cloud/host/dao/HostDaoImpl.java index 569ac3888cd..75f11285b12 100644 --- a/server/src/com/cloud/host/dao/HostDaoImpl.java +++ b/server/src/com/cloud/host/dao/HostDaoImpl.java @@ -54,6 +54,8 @@ import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; import com.cloud.utils.db.UpdateBuilder; import com.cloud.utils.exception.CloudRuntimeException; + +import edu.emory.mathcs.backport.java.util.Collections; @Local(value = { HostDao.class }) @DB(txn=false) @TableGenerator(name="host_req_sq", table="op_host", pkColumnName="id", valueColumnName="sequence", allocationSize=1) @@ -271,28 +273,51 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao } @Override - public HostVO findSecondaryStorageHost(long dcId) { - SearchCriteria sc = TypeDcSearch.create(); - sc.setParameters("type", Host.Type.SecondaryStorage); - sc.setParameters("dc", dcId); - List storageHosts = listBy(sc); - - if (storageHosts == null || storageHosts.size() < 1) { - return null; - } else { - return storageHosts.get(0); - } + public HostVO findSecondaryStorageHost(long dcId) { + SearchCriteria sc = TypeDcSearch.create(); + sc.setParameters("type", Host.Type.SecondaryStorage); + sc.setParameters("dc", dcId); + List storageHosts = listBy(sc); + if (storageHosts == null || storageHosts.size() < 1) { + return null; + } else { + Collections.shuffle(storageHosts); + return storageHosts.get(0); + } } @Override public List listSecondaryStorageHosts() { - SearchCriteria sc = TypeSearch.create(); - sc.setParameters("type", Host.Type.SecondaryStorage); - List secondaryStorageHosts = listIncludingRemovedBy(sc); - - return secondaryStorageHosts; - } - + SearchCriteria sc = createSearchCriteria(); + sc.addAnd("type", SearchCriteria.Op.EQ, Host.Type.SecondaryStorage); + return search(sc, null); + } + + @Override + public List listSecondaryStorageHosts(long dataCenterId) { + SearchCriteria sc = createSearchCriteria(); + sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, dataCenterId); + sc.addAnd("type", SearchCriteria.Op.EQ, Host.Type.SecondaryStorage); + return search(sc, null); + + } + + @Override + public List listLocalSecondaryStorageHosts() { + SearchCriteria sc = createSearchCriteria(); + sc.addAnd("type", SearchCriteria.Op.EQ, Host.Type.LocalSecondaryStorage); + return search(sc, null); + } + + @Override + public List listLocalSecondaryStorageHosts(long dataCenterId) { + SearchCriteria sc = createSearchCriteria(); + sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, dataCenterId); + sc.addAnd("type", SearchCriteria.Op.EQ, Host.Type.LocalSecondaryStorage); + return search(sc, null); + + } + @Override public List findDirectlyConnectedHosts() { SearchCriteria sc = DirectlyConnectedSearch.create(); diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index 404eda7124a..2059b81aff0 100755 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -248,17 +248,11 @@ public class StatsCollector { class StorageCollector implements Runnable { @Override public void run() { - try { - SearchCriteria sc = _hostDao.createSearchCriteria(); - ConcurrentHashMap storageStats = new ConcurrentHashMap(); - List hosts = _hostDao.search(sc, null); - - sc.addAnd("status", SearchCriteria.Op.EQ, Status.Up.toString()); - sc.addAnd("type", SearchCriteria.Op.EQ, Host.Type.SecondaryStorage.toString()); - - hosts = _hostDao.search(sc, null); + try { + List hosts = _hostDao.listSecondaryStorageHosts(); + ConcurrentHashMap storageStats = new ConcurrentHashMap(); for (HostVO host : hosts) { - GetStorageStatsCommand command = new GetStorageStatsCommand(host.getGuid()); + GetStorageStatsCommand command = new GetStorageStatsCommand(host.getStorageUrl()); long hostId = host.getId(); Answer answer = _agentMgr.easySend(hostId, command); if (answer != null && answer.getResult()) { diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 2ae4c8c8867..41a7be9338c 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -182,6 +182,7 @@ import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.SecondaryStorageVmDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; +import java.util.Random; @Local(value = { StorageManager.class, StorageService.class }) public class StorageManagerImpl implements StorageManager, StorageService, Manager, ClusterManagerListener { @@ -221,6 +222,8 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag @Inject protected SnapshotDao _snapshotDao; @Inject + protected SnapshotManager _snapMgr; + @Inject protected SnapshotPolicyDao _snapshotPolicyDao; @Inject protected StoragePoolHostDao _storagePoolHostDao; @@ -590,7 +593,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag Long volumeId = snapshot.getVolumeId(); String primaryStoragePoolNameLabel = pool.getUuid(); // pool's uuid is actually the namelabel. Long dcId = snapshot.getDataCenterId(); - String secondaryStoragePoolUrl = getSecondaryStorageURL(dcId); + String secondaryStoragePoolUrl = _snapMgr.getSecondaryStorageURL(snapshot); long accountId = snapshot.getAccountId(); String backedUpSnapshotUuid = snapshot.getBackupSnapshotId(); @@ -928,7 +931,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag @Override public String getSecondaryStorageURL(long zoneId) { // Determine the secondary storage URL - HostVO secondaryStorageHost = _hostDao.findSecondaryStorageHost(zoneId); + HostVO secondaryStorageHost = getSecondaryStorageHost(zoneId); if (secondaryStorageHost == null) { return null; @@ -939,7 +942,15 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag @Override public HostVO getSecondaryStorageHost(long zoneId) { - return _hostDao.findSecondaryStorageHost(zoneId); + List hosts = _hostDao.listSecondaryStorageHosts(zoneId); + if( hosts == null) { + return null; + } + + int size = hosts.size(); + Random rn = new Random(); + int index = rn.nextInt(size); + return hosts.get(index); } @Override @@ -1884,7 +1895,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag String installPath = destroyedTemplateHostVO.getInstallPath(); if (installPath != null) { - Answer answer = _agentMgr.easySend(hostId, new DeleteTemplateCommand(destroyedTemplateHostVO.getInstallPath())); + Answer answer = _agentMgr.sendToSecStorage(secondaryStorageHost, new DeleteTemplateCommand(secondaryStorageHost.getStorageUrl(),destroyedTemplateHostVO.getInstallPath())); if (answer == null || !answer.getResult()) { s_logger.debug("Failed to delete " + destroyedTemplateHostVO + " due to " + ((answer == null) ? "answer is null" : answer.getDetails())); diff --git a/server/src/com/cloud/storage/dao/SnapshotDao.java b/server/src/com/cloud/storage/dao/SnapshotDao.java index e5731b00359..e88cb60db7f 100644 --- a/server/src/com/cloud/storage/dao/SnapshotDao.java +++ b/server/src/com/cloud/storage/dao/SnapshotDao.java @@ -35,5 +35,6 @@ public interface SnapshotDao extends GenericDao { List listByBackupUuid(long volumeId, String backupUuid); long updateSnapshotVersion(long volumeId, String from, String to); List listByVolumeIdVersion(long volumeId, String version); + Long getSecHostId(long volumeId); } diff --git a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java b/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java index fce66e1c66f..2cc8efce3f9 100644 --- a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java +++ b/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java @@ -39,6 +39,7 @@ public class SnapshotDaoImpl extends GenericDaoBase implements public static final Logger s_logger = Logger.getLogger(SnapshotDaoImpl.class.getName()); private static final String GET_LAST_SNAPSHOT = "SELECT id FROM snapshots where volume_id = ? AND id != ? AND path IS NOT NULL ORDER BY created DESC"; private static final String UPDATE_SNAPSHOT_VERSION = "UPDATE snapshots SET version = ? WHERE volume_id = ? AND version = ?"; + private static final String GET_SECHOST_ID = "SELECT sechost_id FROM snapshots where volume_id = ? AND backup_snap_id IS NOT NULL AND sechost_id IS NOT NULL LIMIT 1"; private final SearchBuilder VolumeIdSearch; private final SearchBuilder VolumeIdTypeSearch; @@ -129,6 +130,23 @@ public class SnapshotDaoImpl extends GenericDaoBase implements } + @Override + public Long getSecHostId(long volumeId) { + + Transaction txn = Transaction.currentTxn(); + PreparedStatement pstmt = null; + String sql = GET_SECHOST_ID; + try { + pstmt = txn.prepareAutoCloseStatement(sql); + pstmt.setLong(1, volumeId); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) { + return rs.getLong(1); + } + } catch (Exception ex) { + } + return null; + } @Override public long getLastSnapshot(long volumeId, long snapId) { Transaction txn = Transaction.currentTxn(); diff --git a/server/src/com/cloud/storage/download/DownloadListener.java b/server/src/com/cloud/storage/download/DownloadListener.java index 152ee474cd4..1ecf2de530f 100644 --- a/server/src/com/cloud/storage/download/DownloadListener.java +++ b/server/src/com/cloud/storage/download/DownloadListener.java @@ -33,6 +33,7 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupRoutingCommand; +import com.cloud.agent.api.StartupSecondaryStorageCommand; import com.cloud.agent.api.StartupStorageCommand; import com.cloud.agent.api.storage.DownloadAnswer; import com.cloud.agent.api.storage.DownloadCommand; @@ -48,6 +49,7 @@ import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.dao.VMTemplateHostDao; import com.cloud.storage.download.DownloadState.DownloadEvent; +import com.cloud.storage.template.TemplateInfo; import com.cloud.utils.exception.CloudRuntimeException; /** @@ -277,25 +279,16 @@ public class DownloadListener implements Listener { @Override public void processConnect(HostVO agent, StartupCommand cmd) throws ConnectionException { - if (!((cmd instanceof StartupStorageCommand) || (cmd instanceof StartupRoutingCommand))) { - return; - } if (cmd instanceof StartupRoutingCommand) { downloadMonitor.handleSysTemplateDownload(agent); - } else { - if (cmd.getGuid().startsWith("iso:")) { - //FIXME: do not download template for ISO secondary - return; - } - - long agentId = agent.getId(); - + } else if ( cmd instanceof StartupStorageCommand) { StartupStorageCommand storage = (StartupStorageCommand)cmd; - if (storage.getResourceType() == Storage.StorageResourceType.STORAGE_HOST || - storage.getResourceType() == Storage.StorageResourceType.SECONDARY_STORAGE ) - { - downloadMonitor.handleTemplateSync(agentId, storage.getTemplateInfo()); - } + if( storage.getResourceType() == Storage.StorageResourceType.SECONDARY_STORAGE ) { + downloadMonitor.addSystemVMTemplatesToHost(agent, storage.getTemplateInfo()); + downloadMonitor.handleTemplateSync(agent.getId()); + } + } else if ( cmd instanceof StartupSecondaryStorageCommand ) { + downloadMonitor.handleTemplateSync(agent.getDataCenterId()); } } diff --git a/server/src/com/cloud/storage/download/DownloadMonitor.java b/server/src/com/cloud/storage/download/DownloadMonitor.java index dd5dbe67094..db62749a7c0 100644 --- a/server/src/com/cloud/storage/download/DownloadMonitor.java +++ b/server/src/com/cloud/storage/download/DownloadMonitor.java @@ -38,7 +38,7 @@ public interface DownloadMonitor extends Manager{ public void cancelAllDownloads(Long templateId); - public void handleTemplateSync(long id, Map templateInfo); + public void handleTemplateSync(HostVO host); public void copyTemplate(VMTemplateVO template, HostVO sourceServer, HostVO destServer) throws StorageUnavailableException; @@ -46,4 +46,8 @@ public interface DownloadMonitor extends Manager{ /*When new host added, take a look at if there are templates needed to be downloaded for the same hypervisor as the host*/ void handleSysTemplateDownload(HostVO hostId); + void handleTemplateSync(long dcId); + + void addSystemVMTemplatesToHost(HostVO host, Map templateInfos); + } \ No newline at end of file diff --git a/server/src/com/cloud/storage/download/DownloadMonitorImpl.java b/server/src/com/cloud/storage/download/DownloadMonitorImpl.java index 278ce402fff..56751b7cc66 100755 --- a/server/src/com/cloud/storage/download/DownloadMonitorImpl.java +++ b/server/src/com/cloud/storage/download/DownloadMonitorImpl.java @@ -19,9 +19,11 @@ package com.cloud.storage.download; import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.Set; import java.util.Timer; import java.util.concurrent.ConcurrentHashMap; @@ -32,10 +34,13 @@ import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; +import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; import com.cloud.agent.api.storage.DeleteTemplateCommand; import com.cloud.agent.api.storage.DownloadCommand; import com.cloud.agent.api.storage.DownloadProgressCommand; +import com.cloud.agent.api.storage.ListTemplateAnswer; +import com.cloud.agent.api.storage.ListTemplateCommand; import com.cloud.agent.api.storage.DownloadProgressCommand.RequestType; import com.cloud.alert.AlertManager; import com.cloud.configuration.dao.ConfigurationDao; @@ -101,8 +106,6 @@ public class DownloadMonitorImpl implements DownloadMonitor { @Inject AlertManager _alertMgr; - @Inject - HostDao _serverDao = null; @Inject private final DataCenterDao _dcDao = null; @Inject @@ -133,7 +136,6 @@ public class DownloadMonitorImpl implements DownloadMonitor { final Map _listenerMap = new ConcurrentHashMap(); - public long send(Long hostId, Command cmd, Listener listener) { return _agentMgr.gatherStats(hostId, cmd, listener); } @@ -229,7 +231,7 @@ public class DownloadMonitorImpl implements DownloadMonitor { if(destTmpltHost != null) { start(); - DownloadCommand dcmd = new DownloadCommand(url, template.getUniqueName(), template.getFormat(), template.isRequiresHvm(), template.getAccountId(), template.getId(), template.getDisplayText(), template.getChecksum(), TemplateConstants.DEFAULT_HTTP_AUTH_USER, _copyAuthPasswd, maxTemplateSizeInBytes); + DownloadCommand dcmd = new DownloadCommand(destServer.getStorageUrl(), url, template, TemplateConstants.DEFAULT_HTTP_AUTH_USER, _copyAuthPasswd, maxTemplateSizeInBytes); DownloadListener dl = downloadJobExists?_listenerMap.get(destTmpltHost):null; if (dl == null) { dl = new DownloadListener(destServer, template, _timer, _vmTemplateHostDao, destTmpltHost.getId(), this, dcmd); @@ -241,7 +243,7 @@ public class DownloadMonitorImpl implements DownloadMonitor { _listenerMap.put(destTmpltHost, dl); - long result = send(destServer.getId(), dcmd, dl); + long result = _agentMgr.sendToSecStorage(destServer, dcmd, dl); if (result == -1) { s_logger.warn("Unable to start /resume COPY of template " + template.getUniqueName() + " to " + destServer.getName()); dl.setDisconnected(); @@ -294,10 +296,10 @@ public class DownloadMonitorImpl implements DownloadMonitor { } Long maxTemplateSizeInBytes = getMaxTemplateSizeInBytes(); - + String url = sserver.getStorageUrl(); if(vmTemplateHost != null) { start(); - DownloadCommand dcmd = new DownloadCommand(template, maxTemplateSizeInBytes); + DownloadCommand dcmd = new DownloadCommand(url, template, maxTemplateSizeInBytes); dcmd.setUrl(vmTemplateHost.getDownloadUrl()); if (vmTemplateHost.isCopy()) { dcmd.setCreds(TemplateConstants.DEFAULT_HTTP_AUTH_USER, _copyAuthPasswd); @@ -310,7 +312,7 @@ public class DownloadMonitorImpl implements DownloadMonitor { _listenerMap.put(vmTemplateHost, dl); - long result = send(sserver.getId(), dcmd, dl); + long result = _agentMgr.sendToSecStorage(sserver, dcmd, dl); if (result == -1) { s_logger.warn("Unable to start /resume download of template " + template.getUniqueName() + " to " + sserver.getName()); dl.setDisconnected(); @@ -323,32 +325,29 @@ public class DownloadMonitorImpl implements DownloadMonitor { @Override public boolean downloadTemplateToStorage(Long templateId, Long zoneId) { - if (isTemplateUpdateable(templateId)) { - List dcs = new ArrayList(); - - if (zoneId == null) { - dcs.addAll(_dcDao.listAllIncludingRemoved()); - } else { - dcs.add(_dcDao.findById(zoneId)); - } - - for (DataCenterVO dc: dcs) { - initiateTemplateDownload(templateId, dc.getId()); - } - return true; - } else { - return false; - } + List dcs = new ArrayList(); + if (zoneId == null) { + dcs.addAll(_dcDao.listAll()); + } else { + dcs.add(_dcDao.findById(zoneId)); + } + for ( DataCenterVO dc : dcs ) { + List ssHosts = _hostDao.listBy(Host.Type.SecondaryStorage, dc.getId()); + for ( HostVO ssHost : ssHosts ) { + if (isTemplateUpdateable(ssHost.getId(), templateId)) { + + initiateTemplateDownload(templateId, ssHost); + } + } + } + return true; } - private void initiateTemplateDownload(Long templateId, Long dataCenterId) { + private void initiateTemplateDownload(Long templateId, HostVO ssHost) { VMTemplateVO template = _templateDao.findById(templateId); if (template != null && (template.getUrl() != null)) { //find all storage hosts and tell them to initiate download - List storageServers = _serverDao.listByTypeDataCenter(Host.Type.SecondaryStorage, dataCenterId); - for (HostVO sserver: storageServers) { - downloadTemplateToStorage(template, sserver); - } + downloadTemplateToStorage(template, ssHost); } } @@ -428,47 +427,104 @@ public class DownloadMonitorImpl implements DownloadMonitor { if (ssHosts == null || ssHosts.isEmpty()) { return; } - HostVO sshost = ssHosts.get(0); /*Download all the templates in zone with the same hypervisortype*/ - + for ( HostVO ssHost : ssHosts) { + List rtngTmplts = _templateDao.listAllSystemVMTemplates(); + List defaultBuiltin = _templateDao.listDefaultBuiltinTemplates(); + + + for (VMTemplateVO rtngTmplt : rtngTmplts) { + if (rtngTmplt.getHypervisorType() == hostHyper) { + toBeDownloaded.add(rtngTmplt); + } + } + + for (VMTemplateVO builtinTmplt : defaultBuiltin) { + if (builtinTmplt.getHypervisorType() == hostHyper) { + toBeDownloaded.add(builtinTmplt); + } + } + + for (VMTemplateVO template: toBeDownloaded) { + VMTemplateHostVO tmpltHost = _vmTemplateHostDao.findByHostTemplate(ssHost.getId(), template.getId()); + if (tmpltHost == null || tmpltHost.getDownloadState() != Status.DOWNLOADED) { + downloadTemplateToStorage(template, ssHost); + } + } + } + } + + @Override + public void addSystemVMTemplatesToHost(HostVO host, Map templateInfos){ + if ( templateInfos == null ) { + return; + } + Long hostId = host.getId(); List rtngTmplts = _templateDao.listAllSystemVMTemplates(); - List defaultBuiltin = _templateDao.listDefaultBuiltinTemplates(); - - - for (VMTemplateVO rtngTmplt : rtngTmplts) { - if (rtngTmplt.getHypervisorType() == hostHyper) { - toBeDownloaded.add(rtngTmplt); + for ( VMTemplateVO tmplt : rtngTmplts ) { + TemplateInfo tmpltInfo = templateInfos.get(tmplt.getUniqueName()); + if ( tmpltInfo == null ) { + continue; } - } - - for (VMTemplateVO builtinTmplt : defaultBuiltin) { - if (builtinTmplt.getHypervisorType() == hostHyper) { - toBeDownloaded.add(builtinTmplt); - } - } - - for (VMTemplateVO template: toBeDownloaded) { - VMTemplateHostVO tmpltHost = _vmTemplateHostDao.findByHostTemplate(sshost.getId(), template.getId()); - if (tmpltHost == null || tmpltHost.getDownloadState() != Status.DOWNLOADED) { - if (_vmTemplateZoneDao.findByZoneTemplate(sshost.getDataCenterId(), template.getId()) == null) { - _templateDao.addTemplateToZone(template, sshost.getDataCenterId()); - } - downloadTemplateToStorage(template, sshost); + VMTemplateHostVO tmpltHost = _vmTemplateHostDao.findByHostTemplate(hostId, tmplt.getId()); + if ( tmpltHost == null ) { + tmpltHost = new VMTemplateHostVO(hostId, tmplt.getId(), new Date(), 100, Status.DOWNLOADED, null, null, null, tmpltInfo.getInstallPath(), tmplt.getUrl()); + tmpltHost.setSize(tmpltInfo.getSize()); + tmpltHost.setPhysicalSize(tmpltInfo.getPhysicalSize()); + _vmTemplateHostDao.persist(tmpltHost); } } } + @Override + public void handleTemplateSync(long dcId) { + List ssHosts = _hostDao.listSecondaryStorageHosts(dcId); + for ( HostVO ssHost : ssHosts ) { + Long hostId = ssHost.getId(); + List ths = _vmTemplateHostDao.listByHostId(hostId); + Map templateInfos = new HashMap(); + for ( VMTemplateHostVO th : ths ) { + String tname = _templateDao.findById(th.getTemplateId()).getUniqueName(); + templateInfos.put(tname, null); + } + handleTemplateSync(ssHost); + } + } + + private Map listTemplate(HostVO ssHost) { + ListTemplateCommand cmd = new ListTemplateCommand(ssHost.getStorageUrl()); + Answer answer = _agentMgr.sendToSecStorage(ssHost, cmd); + if (answer != null && answer.getResult()) { + ListTemplateAnswer tanswer = (ListTemplateAnswer)answer; + return tanswer.getTemplateInfo(); + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("can not list template for secondary storage host " + ssHost.getId()); + } + } + + return null; + } + @Override - public void handleTemplateSync(long sserverId, Map templateInfos) { - HostVO storageHost = _serverDao.findById(sserverId); - if (storageHost == null) { + public void handleTemplateSync(HostVO ssHost) { + Long sserverId = ssHost.getId(); + if (ssHost == null) { s_logger.warn("Huh? Agent id " + sserverId + " does not correspond to a row in hosts table?"); return; - } - long zoneId = storageHost.getDataCenterId(); + } + if ( ssHost.getType() != Host.Type.SecondaryStorage ) { + s_logger.warn("Huh? Agent id " + sserverId + " is not secondary storage host"); + return; + } + Map templateInfos = listTemplate(ssHost); + if( templateInfos == null ) { + return; + } + long zoneId = ssHost.getDataCenterId(); Set toBeDownloaded = new HashSet(); - List allTemplates = _templateDao.listAllInZone(storageHost.getDataCenterId()); + List allTemplates = _templateDao.listAllInZone(ssHost.getDataCenterId()); List rtngTmplts = _templateDao.listAllSystemVMTemplates(); List defaultBuiltin = _templateDao.listDefaultBuiltinTemplates(); @@ -561,19 +617,15 @@ public class DownloadMonitorImpl implements DownloadMonitor { } if (toBeDownloaded.size() > 0) { - HostVO sserver = _serverDao.findById(sserverId); - if (sserver == null) { - throw new CloudRuntimeException("Unable to find host from id"); - } /*Only download templates whose hypervirsor type is in the zone*/ - List availHypers = _clusterDao.getAvailableHypervisorInZone(sserver.getDataCenterId()); + List availHypers = _clusterDao.getAvailableHypervisorInZone(ssHost.getDataCenterId()); /* Baremetal need not to download any template */ availHypers.remove(HypervisorType.BareMetal); availHypers.add(HypervisorType.None); //bug 9809: resume ISO download. for (VMTemplateVO tmplt: toBeDownloaded) { if (tmplt.getUrl() == null){ // If url is null we cant initiate the download so mark it as an error. - VMTemplateHostVO tmpltHost = _vmTemplateHostDao.findByHostTemplate(sserver.getId(), tmplt.getId()); + VMTemplateHostVO tmpltHost = _vmTemplateHostDao.findByHostTemplate(ssHost.getId(), tmplt.getId()); if(tmpltHost != null){ tmpltHost.setDownloadState(Status.DOWNLOAD_ERROR); tmpltHost.setDownloadPercent(0); @@ -584,16 +636,16 @@ public class DownloadMonitorImpl implements DownloadMonitor { } if (availHypers.contains(tmplt.getHypervisorType())) { - s_logger.debug("Template " + tmplt.getName() + " needs to be downloaded to " + sserver.getName()); - downloadTemplateToStorage(tmplt, sserver); + s_logger.debug("Template " + tmplt.getName() + " needs to be downloaded to " + ssHost.getName()); + downloadTemplateToStorage(tmplt, ssHost); } } } for (String uniqueName: templateInfos.keySet()) { TemplateInfo tInfo = templateInfos.get(uniqueName); - DeleteTemplateCommand dtCommand = new DeleteTemplateCommand(tInfo.getInstallPath()); - long result = send(sserverId, dtCommand, null); + DeleteTemplateCommand dtCommand = new DeleteTemplateCommand(ssHost.getStorageUrl(), tInfo.getInstallPath()); + long result = _agentMgr.sendToSecStorage(ssHost, dtCommand, null); if (result == -1 ){ String description = "Failed to delete " + tInfo.getTemplateName() + " on secondary storage " + sserverId + " which isn't in the database"; s_logger.error(description); diff --git a/server/src/com/cloud/storage/resource/DummySecondaryStorageResource.java b/server/src/com/cloud/storage/resource/DummySecondaryStorageResource.java index f4ff10e4c71..4e654d92129 100644 --- a/server/src/com/cloud/storage/resource/DummySecondaryStorageResource.java +++ b/server/src/com/cloud/storage/resource/DummySecondaryStorageResource.java @@ -35,6 +35,8 @@ import com.cloud.agent.api.GetStorageStatsAnswer; import com.cloud.agent.api.GetStorageStatsCommand; import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.PingStorageCommand; +import com.cloud.agent.api.ReadyAnswer; +import com.cloud.agent.api.ReadyCommand; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupStorageCommand; import com.cloud.agent.api.storage.DownloadAnswer; @@ -87,7 +89,9 @@ public class DummySecondaryStorageResource extends ServerResourceBase implements } else if (cmd instanceof GetStorageStatsCommand) { return execute((GetStorageStatsCommand)cmd); } else if (cmd instanceof CheckHealthCommand) { - return new CheckHealthAnswer((CheckHealthCommand)cmd, true); + return new CheckHealthAnswer((CheckHealthCommand)cmd, true); + } else if (cmd instanceof ReadyCommand) { + return new ReadyAnswer((ReadyCommand)cmd); } else { return Answer.createUnsupportedCommandAnswer(cmd); } diff --git a/server/src/com/cloud/storage/secondary/SecondaryStorageListener.java b/server/src/com/cloud/storage/secondary/SecondaryStorageListener.java index 6822c3be3c9..bcc3e9259cf 100644 --- a/server/src/com/cloud/storage/secondary/SecondaryStorageListener.java +++ b/server/src/com/cloud/storage/secondary/SecondaryStorageListener.java @@ -25,6 +25,7 @@ import com.cloud.agent.api.AgentControlCommand; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; import com.cloud.agent.api.StartupCommand; +import com.cloud.agent.api.StartupSecondaryStorageCommand; import com.cloud.agent.api.StartupStorageCommand; import com.cloud.host.HostVO; import com.cloud.host.Status; @@ -67,17 +68,26 @@ public class SecondaryStorageListener implements Listener { @Override public void processConnect(HostVO agent, StartupCommand cmd) { - if (cmd instanceof StartupStorageCommand) { - if(s_logger.isInfoEnabled()) - s_logger.info("Received a host startup notification"); - - StartupStorageCommand ss = (StartupStorageCommand)cmd; - if (ss.getResourceType() == Storage.StorageResourceType.SECONDARY_STORAGE) { - _ssVmMgr.onAgentConnect(agent.getDataCenterId(), cmd); - _ssVmMgr.generateFirewallConfiguration(agent.getId()); - _ssVmMgr.generateSetupCommand(agent.getDataCenterId()); + + if ((cmd instanceof StartupStorageCommand) ) { + StartupStorageCommand scmd = (StartupStorageCommand)cmd; + if (scmd.getResourceType() == Storage.StorageResourceType.SECONDARY_STORAGE ) { + _ssVmMgr.generateSetupCommand(agent.getId()); + return; } - } + } else if (cmd instanceof StartupSecondaryStorageCommand) { + if(s_logger.isInfoEnabled()) { + s_logger.info("Received a host startup notification " + cmd); + } + _ssVmMgr.onAgentConnect(agent.getDataCenterId(), cmd); + _ssVmMgr.generateSetupCommand(agent.getId()); + _ssVmMgr.generateFirewallConfiguration(agent.getId()); + _ssVmMgr.generateVMSetupCommand(agent.getId()); + return; + } + return; + + } @Override diff --git a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java index 4b99781517b..4700af2dfc7 100644 --- a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java +++ b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java @@ -35,6 +35,7 @@ import com.cloud.agent.api.Command; import com.cloud.agent.api.RebootCommand; import com.cloud.agent.api.SecStorageFirewallCfgCommand; import com.cloud.agent.api.SecStorageSetupCommand; +import com.cloud.agent.api.SecStorageVMSetupCommand; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StopAnswer; import com.cloud.agent.api.check.CheckSshAnswer; @@ -212,38 +213,84 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V } } - @Override - public boolean generateFirewallConfiguration(Long hostId) { - if (hostId == null) { - return true; + SecondaryStorageVmVO getSSVMfromHost(HostVO ssAHost) { + if( ssAHost.getType() == Host.Type.SecondaryStorageVM ) { + return _secStorageVmDao.findByInstanceName(ssAHost.getName()); } - boolean success = true; - List allZones = _dcDao.listAll(); - for (DataCenterVO zone : allZones) { - success = success && generateFirewallConfigurationForZone(zone.getId()); + 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; + } + if (secStorageVm.getState() != State.Running) { + s_logger.warn("secondary storage VM " + cssHost.getName() + " is not running"); + return false; + } + List ssHosts = _hostDao.listSecondaryStorageHosts(zoneId); + for( HostVO ssHost : ssHosts ) { + String secUrl = ssHost.getStorageUrl(); + SecStorageSetupCommand setupCmd = new SecStorageSetupCommand(secUrl); + + Answer answer = _agentMgr.easySend(ssHostId, setupCmd); + if (answer != null && answer.getResult()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Successfully programmed secondary storage " + ssHost.getName() + " in secondary storage VM " + secStorageVm.getInstanceName()); + } + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Successfully programmed secondary storage " + ssHost.getName() + " in secondary storage VM " + secStorageVm.getInstanceName()); + } + return false; + } + } + } else if( cssHost.getType() == Host.Type.SecondaryStorage ) { + List alreadyRunning = _secStorageVmDao.getSecStorageVmListInStates(SecondaryStorageVm.Role.templateProcessor, zoneId, State.Running); + String secUrl = cssHost.getStorageUrl(); + SecStorageSetupCommand setupCmd = new SecStorageSetupCommand(secUrl); + for ( SecondaryStorageVmVO ssVm : alreadyRunning ) { + HostVO host = _hostDao.findByName(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 generateSetupCommand(Long zoneId) { - - List zoneSsvms = _secStorageVmDao.listByZoneId(SecondaryStorageVm.Role.templateProcessor, zoneId); - if (zoneSsvms.size() == 0) { - return true; + public boolean generateVMSetupCommand(Long ssAHostId) { + HostVO ssAHost = _hostDao.findById(ssAHostId); + if( ssAHost.getType() != Host.Type.SecondaryStorageVM ) { + return false; } - SecondaryStorageVmVO secStorageVm = zoneSsvms.get(0);// FIXME: assumes - // one vm per zone. - if (secStorageVm.getState() != State.Running && secStorageVm.getState() != State.Starting) { - s_logger.warn("No running secondary storage vms found in zone " + zoneId + " , skip programming http auth"); - return true; + SecondaryStorageVmVO secStorageVm = _secStorageVmDao.findByInstanceName(ssAHost.getName()); + if (secStorageVm == null) { + s_logger.warn("secondary storage VM " + ssAHost.getName() + " doesn't exist"); + return false; } - Host storageHost = _hostDao.findSecondaryStorageHost(zoneId); - if (storageHost == null) { - s_logger.warn("No storage hosts found in zone " + zoneId + " , skip programming http auth"); - return true; + if (secStorageVm.getState() != State.Running) { + s_logger.warn("secondary storage VM " + ssAHost.getName() + " is not running"); + return false; } - SecStorageSetupCommand setupCmd = new SecStorageSetupCommand(zoneId); + + SecStorageVMSetupCommand setupCmd = new SecStorageVMSetupCommand(); if (_allowedInternalSites != null) { List allowedCidrs = new ArrayList(); String[] cidrs = _allowedInternalSites.split(","); @@ -265,7 +312,7 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V String copyPasswd = _configDao.getValue("secstorage.copy.password"); setupCmd.setCopyPassword(copyPasswd); setupCmd.setCopyUserName(TemplateConstants.DEFAULT_HTTP_AUTH_USER); - Answer answer = _agentMgr.easySend(storageHost.getId(), setupCmd); + 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()); @@ -284,49 +331,68 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V return null; } - private boolean generateFirewallConfigurationForZone(Long zoneId) { - List zoneSsvms = _secStorageVmDao.listByZoneId(SecondaryStorageVm.Role.templateProcessor, zoneId); - if (zoneSsvms.size() == 0) { + @Override + public boolean generateFirewallConfiguration(Long ssAHostId) { + if ( ssAHostId == null ) { return true; } - SecondaryStorageVmVO secStorageVm = zoneSsvms.get(0);// FIXME: assumes - // one vm per zone. - if (secStorageVm.getState() != State.Running && secStorageVm.getState() != State.Starting) { - s_logger.warn("No running secondary storage vms found in zone " + zoneId + " , skip programming firewall rules"); - return true; + HostVO ssAHost = _hostDao.findById(ssAHostId); + Long zoneId = ssAHost.getDataCenterId(); + SecondaryStorageVmVO thisSecStorageVm = _secStorageVmDao.findByInstanceName(ssAHost.getName()); + + if (thisSecStorageVm == null) { + s_logger.warn("secondary storage VM " + ssAHost.getName() + " doesn't exist"); + return false; } - Host storageHost = _hostDao.findSecondaryStorageHost(zoneId); - if (storageHost == null) { - s_logger.warn("No storage hosts found in zone " + zoneId + " , skip programming firewall rules"); - return true; + if (thisSecStorageVm.getState() != State.Running) { + s_logger.warn("secondary storage VM " + ssAHost.getName() + " is not running"); + return false; } + List alreadyRunning = _secStorageVmDao.getSecStorageVmListInStates(SecondaryStorageVm.Role.templateProcessor, State.Running, State.Migrating, State.Starting); - String copyPort = Integer.toString(TemplateConstants.DEFAULT_TMPLT_COPY_PORT); + String copyPort = _useSSlCopy? "443" : Integer.toString(TemplateConstants.DEFAULT_TMPLT_COPY_PORT); SecStorageFirewallCfgCommand cpc = new SecStorageFirewallCfgCommand(); + SecStorageFirewallCfgCommand thiscpc = new SecStorageFirewallCfgCommand(); + thiscpc.addPortConfig(thisSecStorageVm.getPublicIpAddress(), copyPort, true, TemplateConstants.DEFAULT_TMPLT_COPY_INTF); for (SecondaryStorageVmVO ssVm : alreadyRunning) { + if ( ssVm.getDataCenterId() == zoneId ) { + continue; + } if (ssVm.getPublicIpAddress() != null) { - if (ssVm.getId() == secStorageVm.getId()) { - continue; - } cpc.addPortConfig(ssVm.getPublicIpAddress(), copyPort, true, TemplateConstants.DEFAULT_TMPLT_COPY_INTF); - if (_useSSlCopy) { - cpc.addPortConfig(ssVm.getPublicIpAddress(), "443", true, TemplateConstants.DEFAULT_TMPLT_COPY_INTF); + } + if ( ssVm.getState() != State.Running ) { + continue; + } + String instanceName = ssVm.getInstanceName(); + HostVO host = _hostDao.findByName(instanceName); + Answer answer = _agentMgr.easySend(host.getId(), thiscpc); + if (answer != null && answer.getResult()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Successfully programmed firewall rules into " + ssVm.getHostName()); } + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("failed to program firewall rules into secondary storage vm : " + ssVm.getHostName()); + } + return false; } } - Answer answer = _agentMgr.easySend(storageHost.getId(), cpc); + + Answer answer = _agentMgr.easySend(ssAHostId, cpc); if (answer != null && answer.getResult()) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Successfully programmed firewall rules into " + secStorageVm.getHostName()); + s_logger.debug("Successfully programmed firewall rules into " + thisSecStorageVm.getHostName()); } - return true; } else { if (s_logger.isDebugEnabled()) { - s_logger.debug("failed to program firewall rules into secondary storage vm : " + secStorageVm.getHostName()); + s_logger.debug("failed to program firewall rules into secondary storage vm : " + thisSecStorageVm.getHostName()); } return false; } + + return true; } @@ -500,7 +566,8 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V } return; } - + + boolean secStorageVmFromStoppedPool = false; SecondaryStorageVmVO secStorageVm = assignSecStorageVmFromStoppedPool(dataCenterId, role); if (secStorageVm == null) { @@ -685,7 +752,7 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V _mgmt_port = NumbersUtil.parseInt(value, 8250); _listener = new SecondaryStorageListener(this); - _agentMgr.registerForHostEvents(_listener, true, true, false); + _agentMgr.registerForHostEvents(_listener, true, false, true); _itMgr.registerGuru(VirtualMachine.Type.SecondaryStorageVm, this); @@ -851,19 +918,8 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V buf.append(" zone=").append(dest.getDataCenter().getId()); buf.append(" pod=").append(dest.getPod().getId()); - if (profile.getVirtualMachine().getRole() == SecondaryStorageVm.Role.templateProcessor) { - buf.append(" guid=").append(secHost.getGuid()); - } else { - buf.append(" guid=").append(profile.getVirtualMachine().getHostName()); - } + buf.append(" guid=").append(profile.getVirtualMachine().getHostName()); - String nfsMountPoint = null; - try { - nfsMountPoint = NfsUtils.url2Mount(secHost.getStorageUrl()); - } catch (Exception e) { - } - - buf.append(" mount.path=").append(nfsMountPoint); if (_configDao.isPremium()) { if (profile.getHypervisorType() == HypervisorType.Hyperv) { buf.append(" resource=com.cloud.storage.resource.CifsSecondaryStorageResource"); @@ -875,7 +931,6 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V } buf.append(" instance=SecStorage"); buf.append(" sslcopy=").append(Boolean.toString(_useSSlCopy)); - buf.append(" role=").append(profile.getVirtualMachine().getRole().toString()); boolean externalDhcp = false; String externalDhcpStr = _configDao.getValue("direct.attach.network.externalIpAllocator.enabled"); @@ -1048,16 +1103,14 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V public Pair scanPool(Long pool) { long dataCenterId = pool.longValue(); - List alreadyRunning = _secStorageVmDao.getSecStorageVmListInStates(SecondaryStorageVm.Role.templateProcessor, dataCenterId, State.Running, State.Migrating, - State.Starting); - List stopped = _secStorageVmDao.getSecStorageVmListInStates(SecondaryStorageVm.Role.templateProcessor, dataCenterId, State.Stopped, State.Stopping); - if (alreadyRunning.size() == 0) { - if (stopped.size() == 0) { - s_logger.info("No secondary storage vms found in datacenter id=" + dataCenterId + ", starting a new one"); - return new Pair(AfterScanAction.expand, SecondaryStorageVm.Role.templateProcessor); - } else { - s_logger.warn("Stopped secondary storage vms found in datacenter id=" + dataCenterId + ", not restarting them automatically"); - } + List 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 ssHosts = _hostDao.listSecondaryStorageHosts(dataCenterId); + int hostSize = (ssHosts == null)? 0 : ssHosts.size(); + if ( hostSize > vmSize ) { + s_logger.info("No secondary storage vms found in datacenter id=" + dataCenterId + ", starting a new one"); + return new Pair(AfterScanAction.expand, SecondaryStorageVm.Role.templateProcessor); } return new Pair(AfterScanAction.nop, SecondaryStorageVm.Role.templateProcessor); diff --git a/server/src/com/cloud/storage/secondary/SecondaryStorageVmManager.java b/server/src/com/cloud/storage/secondary/SecondaryStorageVmManager.java index abb9b6946c7..885ba5c14ce 100644 --- a/server/src/com/cloud/storage/secondary/SecondaryStorageVmManager.java +++ b/server/src/com/cloud/storage/secondary/SecondaryStorageVmManager.java @@ -40,7 +40,8 @@ public interface SecondaryStorageVmManager extends Manager { public boolean destroySecStorageVm(long ssVmVmId); public void onAgentConnect(Long dcId, StartupCommand cmd); public boolean generateFirewallConfiguration(Long agentId); - public boolean generateSetupCommand(Long zoneId); + public boolean generateVMSetupCommand(Long hostId); - public Pair assignSecStorageVm(long zoneId, Command cmd); + public Pair assignSecStorageVm(long zoneId, Command cmd); + boolean generateSetupCommand(Long hostId); } diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManager.java b/server/src/com/cloud/storage/snapshot/SnapshotManager.java index ff8b5035d7f..fdf16a17388 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManager.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManager.java @@ -130,4 +130,6 @@ public interface SnapshotManager { List listSnapsforPolicy(long policyId, Filter filter); void downloadSnapshotsFromSwift(SnapshotVO ss); + + String getSecondaryStorageURL(SnapshotVO snapshot); } diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 81f19f9197b..61bd6e2ae89 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -518,8 +518,10 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma String primaryStoragePoolNameLabel = _storageMgr.getPrimaryStorageNameLabel(volume); Long dcId = volume.getDataCenterId(); Long accountId = volume.getAccountId(); - - String secondaryStoragePoolUrl = _storageMgr.getSecondaryStorageURL(volume.getDataCenterId()); + + HostVO secHost = getSecHost(volumeId, volume.getDataCenterId()); + + String secondaryStoragePoolUrl = secHost.getStorageUrl(); String snapshotUuid = snapshot.getPath(); // In order to verify that the snapshot is not empty, // we check if the parent of the snapshot is not the same as the parent of the previous snapshot. @@ -603,6 +605,14 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma } + private HostVO getSecHost(long volumeId, long dcId) { + Long id = _snapshotDao.getSecHostId(volumeId); + if ( id != null) { + return _hostDao.findById(id); + } + return _storageMgr.getSecondaryStorageHost(dcId); + } + private Long getSnapshotUserId() { Long userId = UserContext.current().getCallerUserId(); if (userId == null) { @@ -766,6 +776,13 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma return true; } + @Override + public String getSecondaryStorageURL(SnapshotVO snapshot) { + HostVO secHost = _hostDao.findById(snapshot.getSecHostId()); + return secHost.getStorageUrl(); + + } + @Override @DB public boolean destroySnapshotBackUp(long snapshotId) { @@ -776,7 +793,7 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma throw new CloudRuntimeException("Destroying snapshot " + snapshotId + " backup failed due to unable to find snapshot "); } - String secondaryStoragePoolUrl = _storageMgr.getSecondaryStorageURL(snapshot.getDataCenterId()); + String secondaryStoragePoolUrl = getSecondaryStorageURL(snapshot); Long dcId = snapshot.getDataCenterId(); Long accountId = snapshot.getAccountId(); Long volumeId = snapshot.getVolumeId(); @@ -954,32 +971,35 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma } Long volumeId = volume.getId(); Long dcId = volume.getDataCenterId(); - String secondaryStoragePoolURL = _storageMgr.getSecondaryStorageURL(dcId); String primaryStoragePoolNameLabel = _storageMgr.getPrimaryStorageNameLabel(volume); if (_snapshotDao.listByVolumeIdIncludingRemoved(volumeId).isEmpty()) { // This volume doesn't have any snapshots. Nothing do delete. continue; } - DeleteSnapshotsDirCommand cmd = new DeleteSnapshotsDirCommand(primaryStoragePoolNameLabel, secondaryStoragePoolURL, dcId, accountId, volumeId, volume.getPath()); - Answer answer = null; - Long poolId = volume.getPoolId(); - if (poolId != null) { - // Retry only once for this command. There's low chance of failure because of a connection problem. - try { - answer = _storageMgr.sendToPool(poolId, cmd); - } catch (StorageUnavailableException e) { + + List ssHosts = _hostDao.listSecondaryStorageHosts(dcId); + for ( HostVO ssHost : ssHosts ) { + DeleteSnapshotsDirCommand cmd = new DeleteSnapshotsDirCommand(primaryStoragePoolNameLabel, ssHost.getStorageUrl(), dcId, accountId, volumeId, volume.getPath()); + Answer answer = null; + Long poolId = volume.getPoolId(); + if (poolId != null) { + // Retry only once for this command. There's low chance of failure because of a connection problem. + try { + answer = _storageMgr.sendToPool(poolId, cmd); + } catch (StorageUnavailableException e) { + } + } else { + s_logger.info("Pool id for volume id: " + volumeId + " belonging to account id: " + accountId + " is null. Assuming the snapshotsDir for the account has already been deleted"); } - } else { - s_logger.info("Pool id for volume id: " + volumeId + " belonging to account id: " + accountId + " is null. Assuming the snapshotsDir for the account has already been deleted"); - } - - if (success) { - // SnapshotsDir has been deleted for the volumes so far. - success = (answer != null) && answer.getResult(); + if (success) { - s_logger.debug("Deleted snapshotsDir for volume: " + volumeId + " under account: " + accountId); - } else if (answer != null) { - s_logger.error(answer.getDetails()); + // SnapshotsDir has been deleted for the volumes so far. + success = (answer != null) && answer.getResult(); + if (success) { + s_logger.debug("Deleted snapshotsDir for volume: " + volumeId + " under account: " + accountId); + } else if (answer != null) { + s_logger.error(answer.getDetails()); + } } } diff --git a/server/src/com/cloud/vm/dao/SecondaryStorageVmDao.java b/server/src/com/cloud/vm/dao/SecondaryStorageVmDao.java index 352afbffd83..b085b85a818 100644 --- a/server/src/com/cloud/vm/dao/SecondaryStorageVmDao.java +++ b/server/src/com/cloud/vm/dao/SecondaryStorageVmDao.java @@ -39,4 +39,5 @@ public interface SecondaryStorageVmDao extends GenericDao getRunningSecStorageVmListByMsid(SecondaryStorageVm.Role role, long msid); public List listRunningSecStorageOrderByLoad(SecondaryStorageVm.Role role, long zoneId); + SecondaryStorageVmVO findByInstanceName(String instanceName); } diff --git a/server/src/com/cloud/vm/dao/SecondaryStorageVmDaoImpl.java b/server/src/com/cloud/vm/dao/SecondaryStorageVmDaoImpl.java index dfb5432e53d..3d33a4b8704 100644 --- a/server/src/com/cloud/vm/dao/SecondaryStorageVmDaoImpl.java +++ b/server/src/com/cloud/vm/dao/SecondaryStorageVmDaoImpl.java @@ -47,7 +47,8 @@ public class SecondaryStorageVmDaoImpl extends GenericDaoBase LastHostSearch; protected SearchBuilder HostUpSearch; protected SearchBuilder ZoneSearch; - protected SearchBuilder StateChangeSearch; + protected SearchBuilder StateChangeSearch; + protected SearchBuilder InstanceSearch; protected final Attribute _updateTimeAttr; @@ -68,6 +69,10 @@ public class SecondaryStorageVmDaoImpl extends GenericDaoBase sc = InstanceSearch.create(); + sc.setParameters("instanceName", instanceName); + List list = listBy(sc); + if( list == null ) { + return null; + } else { + return list.get(0); + } + } @Override public List listByZoneId(SecondaryStorageVm.Role role, long zoneId) { diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index ae89dcad923..d7f31a7df72 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -410,6 +410,7 @@ CREATE TABLE `cloud`.`snapshots` ( `backup_snap_id` varchar(255) COMMENT 'Back up uuid of the snapshot', `swift_id` bigint unsigned COMMENT 'which swift', `swift_name` varchar(255) COMMENT 'Back up name in swift', + `sechost_id` bigint unsigned COMMENT 'secondary storage host id', `prev_snap_id` bigint unsigned COMMENT 'Id of the most recent snapshot', `hypervisor_type` varchar(32) NOT NULL COMMENT 'hypervisor that the snapshot was taken under', `version` varchar(32) COMMENT 'snapshot version',