Java tutorial
// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package com.cloud.storage.resource; import static com.cloud.utils.S3Utils.deleteDirectory; import static com.cloud.utils.S3Utils.getDirectory; import static com.cloud.utils.S3Utils.putDirectory; import static com.cloud.utils.StringUtils.join; import static com.cloud.utils.db.GlobalLock.executeWithNoWaitLock; import static java.lang.String.format; import static java.util.Arrays.asList; import static org.apache.commons.lang.StringUtils.substringAfterLast; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; import java.net.InetAddress; import java.net.URI; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.Callable; import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import com.cloud.agent.api.Answer; import com.cloud.agent.api.CheckHealthAnswer; import com.cloud.agent.api.CheckHealthCommand; import com.cloud.agent.api.CleanupSnapshotBackupCommand; import com.cloud.agent.api.Command; import com.cloud.agent.api.ComputeChecksumCommand; import com.cloud.agent.api.DeleteObjectFromSwiftCommand; import com.cloud.agent.api.DeleteSnapshotBackupCommand; import com.cloud.agent.api.DeleteSnapshotsDirCommand; import com.cloud.agent.api.DeleteTemplateFromS3Command; import com.cloud.agent.api.DownloadSnapshotFromS3Command; import com.cloud.agent.api.DownloadTemplateFromS3ToSecondaryStorageCommand; 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.SecStorageFirewallCfgCommand; import com.cloud.agent.api.SecStorageFirewallCfgCommand.PortConfig; import com.cloud.agent.api.SecStorageSetupAnswer; import com.cloud.agent.api.SecStorageSetupCommand; import com.cloud.agent.api.SecStorageSetupCommand.Certificates; import com.cloud.agent.api.SecStorageVMSetupCommand; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupSecondaryStorageCommand; import com.cloud.agent.api.UploadTemplateToS3FromSecondaryStorageCommand; import com.cloud.agent.api.downloadSnapshotFromSwiftCommand; import com.cloud.agent.api.downloadTemplateFromSwiftToSecondaryStorageCommand; import com.cloud.agent.api.uploadTemplateToSwiftFromSecondaryStorageCommand; 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.DeleteVolumeCommand; 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.ListVolumeAnswer; import com.cloud.agent.api.storage.ListVolumeCommand; import com.cloud.agent.api.storage.UploadCommand; import com.cloud.agent.api.storage.ssCommand; import com.cloud.agent.api.to.S3TO; import com.cloud.agent.api.to.SwiftTO; import com.cloud.exception.InternalErrorException; import com.cloud.host.Host; import com.cloud.host.Host.Type; import com.cloud.resource.ServerResourceBase; import com.cloud.storage.StorageLayer; import com.cloud.storage.template.DownloadManager; import com.cloud.storage.template.DownloadManagerImpl; import com.cloud.storage.template.DownloadManagerImpl.ZfsPathParser; import com.cloud.storage.template.TemplateInfo; import com.cloud.storage.template.TemplateLocation; import com.cloud.storage.template.UploadManager; import com.cloud.storage.template.UploadManagerImpl; import com.cloud.utils.NumbersUtil; import com.cloud.utils.S3Utils; import com.cloud.utils.S3Utils.FileNamingStrategy; import com.cloud.utils.S3Utils.ObjectNamingStrategy; import com.cloud.utils.component.ComponentContext; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.utils.script.OutputInterpreter; import com.cloud.utils.script.Script; import com.cloud.vm.SecondaryStorageVm; public class NfsSecondaryStorageResource extends ServerResourceBase implements SecondaryStorageResource { private static final Logger s_logger = Logger.getLogger(NfsSecondaryStorageResource.class); private static final String TEMPLATE_ROOT_DIR = "template/tmpl"; private static final String SNAPSHOT_ROOT_DIR = "snapshots"; int _timeout; String _instance; String _dc; String _pod; String _guid; String _role; Map<String, Object> _params; StorageLayer _storage; boolean _inSystemVM = false; boolean _sslCopy = false; DownloadManager _dlMgr; UploadManager _upldMgr; private String _configSslScr; private String _configAuthScr; private String _configIpFirewallScr; private String _publicIp; private String _hostname; private String _localgw; private String _eth1mask; private String _eth1ip; private String _storageIp; private String _storageNetmask; private String _storageGateway; private final List<String> nfsIps = new ArrayList<String>(); final private String _parent = "/mnt/SecStorage"; final private String _tmpltDir = "/var/cloudstack/template"; final private String _tmpltpp = "template.properties"; @Override public void disconnected() { } @Override public Answer executeRequest(Command cmd) { if (cmd instanceof DownloadProgressCommand) { return _dlMgr.handleDownloadCommand(this, (DownloadProgressCommand) cmd); } else if (cmd instanceof DownloadCommand) { return _dlMgr.handleDownloadCommand(this, (DownloadCommand) cmd); } else if (cmd instanceof UploadCommand) { return _upldMgr.handleUploadCommand(this, (UploadCommand) cmd); } else if (cmd instanceof CreateEntityDownloadURLCommand) { return _upldMgr.handleCreateEntityURLCommand((CreateEntityDownloadURLCommand) cmd); } else if (cmd instanceof DeleteEntityDownloadURLCommand) { return _upldMgr.handleDeleteEntityDownloadURLCommand((DeleteEntityDownloadURLCommand) cmd); } else if (cmd instanceof GetStorageStatsCommand) { return execute((GetStorageStatsCommand) cmd); } else if (cmd instanceof CheckHealthCommand) { return new CheckHealthAnswer((CheckHealthCommand) cmd, true); } else if (cmd instanceof DeleteTemplateCommand) { return execute((DeleteTemplateCommand) cmd); } else if (cmd instanceof DeleteVolumeCommand) { return execute((DeleteVolumeCommand) cmd); } else if (cmd instanceof ReadyCommand) { 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); } else if (cmd instanceof ComputeChecksumCommand) { return execute((ComputeChecksumCommand) cmd); } else if (cmd instanceof ListTemplateCommand) { return execute((ListTemplateCommand) cmd); } else if (cmd instanceof ListVolumeCommand) { return execute((ListVolumeCommand) cmd); } else if (cmd instanceof downloadSnapshotFromSwiftCommand) { return execute((downloadSnapshotFromSwiftCommand) cmd); } else if (cmd instanceof DownloadSnapshotFromS3Command) { return execute((DownloadSnapshotFromS3Command) cmd); } else if (cmd instanceof DeleteSnapshotBackupCommand) { return execute((DeleteSnapshotBackupCommand) cmd); } else if (cmd instanceof DeleteSnapshotsDirCommand) { return execute((DeleteSnapshotsDirCommand) cmd); } else if (cmd instanceof downloadTemplateFromSwiftToSecondaryStorageCommand) { return execute((downloadTemplateFromSwiftToSecondaryStorageCommand) cmd); } else if (cmd instanceof DownloadTemplateFromS3ToSecondaryStorageCommand) { return execute((DownloadTemplateFromS3ToSecondaryStorageCommand) cmd); } else if (cmd instanceof uploadTemplateToSwiftFromSecondaryStorageCommand) { return execute((uploadTemplateToSwiftFromSecondaryStorageCommand) cmd); } else if (cmd instanceof UploadTemplateToS3FromSecondaryStorageCommand) { return execute((UploadTemplateToS3FromSecondaryStorageCommand) cmd); } else if (cmd instanceof DeleteObjectFromSwiftCommand) { return execute((DeleteObjectFromSwiftCommand) cmd); } else if (cmd instanceof DeleteTemplateFromS3Command) { return execute((DeleteTemplateFromS3Command) cmd); } else if (cmd instanceof CleanupSnapshotBackupCommand) { return execute((CleanupSnapshotBackupCommand) cmd); } else { return Answer.createUnsupportedCommandAnswer(cmd); } } @SuppressWarnings("unchecked") private String determineS3TemplateDirectory(final Long accountId, final Long templateId) { return join(asList(TEMPLATE_ROOT_DIR, accountId, templateId), S3Utils.SEPARATOR); } @SuppressWarnings("unchecked") private String determineStorageTemplatePath(final String storagePath, final Long accountId, final Long templateId) { return join(asList(getRootDir(storagePath), TEMPLATE_ROOT_DIR, accountId, templateId), File.separator); } private Answer execute(final DownloadTemplateFromS3ToSecondaryStorageCommand cmd) { final S3TO s3 = cmd.getS3(); final String storagePath = cmd.getStoragePath(); final Long accountId = cmd.getAccountId(); final Long templateId = cmd.getTemplateId(); try { final File downloadDirectory = _storage .getFile(determineStorageTemplatePath(storagePath, accountId, templateId)); downloadDirectory.mkdirs(); if (!downloadDirectory.exists()) { final String errMsg = format("Unable to create directory " + "download directory %1$s for download of template id " + "%2$s from S3.", downloadDirectory.getName(), templateId); s_logger.error(errMsg); return new Answer(cmd, false, errMsg); } getDirectory(s3, s3.getBucketName(), determineS3TemplateDirectory(accountId, templateId), downloadDirectory, new FileNamingStrategy() { @Override public String determineFileName(final String key) { return substringAfterLast(key, S3Utils.SEPARATOR); } }); return new Answer(cmd, true, format("Successfully downloaded " + "template id %1$s from S3 to directory %2$s", templateId, downloadDirectory.getName())); } catch (Exception e) { final String errMsg = format("Failed to upload template id %1$s " + "due to $2%s", templateId, e.getMessage()); s_logger.error(errMsg, e); return new Answer(cmd, false, errMsg); } } private Answer execute(downloadTemplateFromSwiftToSecondaryStorageCommand cmd) { SwiftTO swift = cmd.getSwift(); String secondaryStorageUrl = cmd.getSecondaryStorageUrl(); Long accountId = cmd.getAccountId(); Long templateId = cmd.getTemplateId(); String path = cmd.getPath(); String errMsg; String lDir = null; try { String parent = getRootDir(secondaryStorageUrl); lDir = parent + "/template/tmpl/" + accountId.toString() + "/" + templateId.toString(); String result = createLocalDir(lDir); if (result != null) { errMsg = "downloadTemplateFromSwiftToSecondaryStorageCommand failed due to Create local directory failed"; s_logger.warn(errMsg); throw new InternalErrorException(errMsg); } String lPath = lDir + "/" + path; result = swiftDownload(swift, "T-" + templateId.toString(), path, lPath); if (result != null) { errMsg = "failed to download template " + path + " from Swift to secondary storage " + lPath + " , err=" + result; s_logger.warn(errMsg); throw new CloudRuntimeException(errMsg); } path = "template.properties"; lPath = lDir + "/" + path; result = swiftDownload(swift, "T-" + templateId.toString(), path, lPath); if (result != null) { errMsg = "failed to download template " + path + " from Swift to secondary storage " + lPath + " , err=" + result; s_logger.warn(errMsg); throw new CloudRuntimeException(errMsg); } return new Answer(cmd, true, "success"); } catch (Exception e) { if (lDir != null) { deleteLocalDir(lDir); } errMsg = cmd + " Command failed due to " + e.toString(); s_logger.warn(errMsg, e); return new Answer(cmd, false, errMsg); } } private Answer execute(uploadTemplateToSwiftFromSecondaryStorageCommand cmd) { SwiftTO swift = cmd.getSwift(); String secondaryStorageUrl = cmd.getSecondaryStorageUrl(); Long accountId = cmd.getAccountId(); Long templateId = cmd.getTemplateId(); try { String parent = getRootDir(secondaryStorageUrl); String lPath = parent + "/template/tmpl/" + accountId.toString() + "/" + templateId.toString(); if (!_storage.isFile(lPath + "/template.properties")) { String errMsg = cmd + " Command failed due to template doesn't exist "; s_logger.debug(errMsg); return new Answer(cmd, false, errMsg); } String result = swiftUpload(swift, "T-" + templateId.toString(), lPath, "*"); if (result != null) { String errMsg = "failed to upload template from secondary storage " + lPath + " to swift , err=" + result; s_logger.debug(errMsg); return new Answer(cmd, false, errMsg); } return new Answer(cmd, true, "success"); } catch (Exception e) { String errMsg = cmd + " Command failed due to " + e.toString(); s_logger.warn(errMsg, e); return new Answer(cmd, false, errMsg); } } private Answer execute(UploadTemplateToS3FromSecondaryStorageCommand cmd) { final S3TO s3 = cmd.getS3(); final Long accountId = cmd.getAccountId(); final Long templateId = cmd.getTemplateId(); try { final String templatePath = determineStorageTemplatePath(cmd.getStoragePath(), accountId, templateId); if (s_logger.isDebugEnabled()) { s_logger.debug("Found template id " + templateId + " account id " + accountId + " from directory " + templatePath + " to upload to S3."); } if (!_storage.isDirectory(templatePath)) { final String errMsg = format( "S3 Sync Failure: Directory %1$s" + "for template id %2$s does not exist.", templatePath, templateId); s_logger.error(errMsg); return new Answer(cmd, false, errMsg); } if (!_storage.isFile(templatePath + "/template.properties")) { final String errMsg = format( "S3 Sync Failure: Template id " + "%1$s does not exist on the file system.", templatePath); s_logger.error(errMsg); return new Answer(cmd, false, errMsg); } if (s_logger.isDebugEnabled()) { s_logger.debug(format("Pushing template id %1$s from %2$s to S3...", templateId, templatePath)); } final String bucket = s3.getBucketName(); putDirectory(s3, bucket, _storage.getFile(templatePath), new FilenameFilter() { @Override public boolean accept(final File directory, final String fileName) { File fileToUpload = new File(directory.getAbsolutePath() + "/" + fileName); return !fileName.startsWith(".") && !fileToUpload.isDirectory(); } }, new ObjectNamingStrategy() { @Override public String determineKey(final File file) { s_logger.debug(String.format("Determining key using account id %1$s and template id %2$s", accountId, templateId)); return join(asList(determineS3TemplateDirectory(accountId, templateId), file.getName()), S3Utils.SEPARATOR); } }); return new Answer(cmd, true, format("Uploaded the contents of directory %1$s for template id %2$s to S3 bucket %3$s", templatePath, templateId, bucket)); } catch (Exception e) { final String errMsg = format("Failed to upload template id %1$s", templateId); s_logger.error(errMsg, e); return new Answer(cmd, false, errMsg); } } private Answer execute(DeleteObjectFromSwiftCommand cmd) { SwiftTO swift = cmd.getSwift(); String container = cmd.getContainer(); String object = cmd.getObject(); if (object == null) { object = ""; } try { String result = swiftDelete(swift, container, object); if (result != null) { String errMsg = "failed to delete object " + container + "/" + object + " , err=" + result; s_logger.warn(errMsg); return new Answer(cmd, false, errMsg); } return new Answer(cmd, true, "success"); } catch (Exception e) { String errMsg = cmd + " Command failed due to " + e.toString(); s_logger.warn(errMsg, e); return new Answer(cmd, false, errMsg); } } private Answer execute(final DeleteTemplateFromS3Command cmd) { final S3TO s3 = cmd.getS3(); final Long accountId = cmd.getAccountId(); final Long templateId = cmd.getTemplateId(); if (accountId == null || (accountId != null && accountId <= 0)) { final String errorMessage = "No account id specified for S3 template deletion."; s_logger.error(errorMessage); return new Answer(cmd, false, errorMessage); } if (templateId == null || (templateId != null && templateId <= 0)) { final String errorMessage = "No template id specified for S3 template deletion."; s_logger.error(errorMessage); return new Answer(cmd, false, errorMessage); } if (s3 == null) { final String errorMessge = "No S3 client options provided"; s_logger.error(errorMessge); return new Answer(cmd, false, errorMessge); } final String bucket = s3.getBucketName(); try { deleteDirectory(s3, bucket, determineS3TemplateDirectory(templateId, accountId)); return new Answer(cmd, true, String.format("Deleted template %1%s from bucket %2$s.", templateId, bucket)); } catch (Exception e) { final String errorMessage = String.format( "Failed to delete templaet id %1$s from bucket %2$s due to the following error: %3$s", templateId, bucket, e.getMessage()); s_logger.error(errorMessage, e); return new Answer(cmd, false, errorMessage); } } String swiftDownload(SwiftTO swift, String container, String rfilename, String lFullPath) { Script command = new Script("/bin/bash", s_logger); command.add("-c"); command.add("/usr/bin/python /usr/local/cloud/systemvm/scripts/storage/secondary/swift -A " + swift.getUrl() + " -U " + swift.getAccount() + ":" + swift.getUserName() + " -K " + swift.getKey() + " download " + container + " " + rfilename + " -o " + lFullPath); OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser(); String result = command.execute(parser); if (result != null) { String errMsg = "swiftDownload failed err=" + result; s_logger.warn(errMsg); return errMsg; } if (parser.getLines() != null) { String[] lines = parser.getLines().split("\\n"); for (String line : lines) { if (line.contains("Errno") || line.contains("failed")) { String errMsg = "swiftDownload failed , err=" + lines.toString(); s_logger.warn(errMsg); return errMsg; } } } return null; } String swiftDownloadContainer(SwiftTO swift, String container, String ldir) { Script command = new Script("/bin/bash", s_logger); command.add("-c"); command.add("cd " + ldir + ";/usr/bin/python /usr/local/cloud/systemvm/scripts/storage/secondary/swift -A " + swift.getUrl() + " -U " + swift.getAccount() + ":" + swift.getUserName() + " -K " + swift.getKey() + " download " + container); OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser(); String result = command.execute(parser); if (result != null) { String errMsg = "swiftDownloadContainer failed err=" + result; s_logger.warn(errMsg); return errMsg; } if (parser.getLines() != null) { String[] lines = parser.getLines().split("\\n"); for (String line : lines) { if (line.contains("Errno") || line.contains("failed")) { String errMsg = "swiftDownloadContainer failed , err=" + lines.toString(); s_logger.warn(errMsg); return errMsg; } } } return null; } String swiftUpload(SwiftTO swift, String container, String lDir, String lFilename) { long SWIFT_MAX_SIZE = 5L * 1024L * 1024L * 1024L; List<String> files = new ArrayList<String>(); if (lFilename.equals("*")) { File dir = new File(lDir); for (String file : dir.list()) { if (file.startsWith(".")) { continue; } files.add(file); } } else { files.add(lFilename); } for (String file : files) { File f = new File(lDir + "/" + file); long size = f.length(); Script command = new Script("/bin/bash", s_logger); command.add("-c"); if (size <= SWIFT_MAX_SIZE) { command.add("cd " + lDir + ";/usr/bin/python /usr/local/cloud/systemvm/scripts/storage/secondary/swift -A " + swift.getUrl() + " -U " + swift.getAccount() + ":" + swift.getUserName() + " -K " + swift.getKey() + " upload " + container + " " + file); } else { command.add("cd " + lDir + ";/usr/bin/python /usr/local/cloud/systemvm/scripts/storage/secondary/swift -A " + swift.getUrl() + " -U " + swift.getAccount() + ":" + swift.getUserName() + " -K " + swift.getKey() + " upload -S " + SWIFT_MAX_SIZE + " " + container + " " + file); } OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser(); String result = command.execute(parser); if (result != null) { String errMsg = "swiftUpload failed , err=" + result; s_logger.warn(errMsg); return errMsg; } if (parser.getLines() != null) { String[] lines = parser.getLines().split("\\n"); for (String line : lines) { if (line.contains("Errno") || line.contains("failed")) { String errMsg = "swiftUpload failed , err=" + lines.toString(); s_logger.warn(errMsg); return errMsg; } } } } return null; } String[] swiftList(SwiftTO swift, String container, String rFilename) { Script command = new Script("/bin/bash", s_logger); command.add("-c"); command.add("/usr/bin/python /usr/local/cloud/systemvm/scripts/storage/secondary/swift -A " + swift.getUrl() + " -U " + swift.getAccount() + ":" + swift.getUserName() + " -K " + swift.getKey() + " list " + container + " " + rFilename); OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser(); String result = command.execute(parser); if (result == null && parser.getLines() != null) { String[] lines = parser.getLines().split("\\n"); return lines; } else { if (result != null) { String errMsg = "swiftList failed , err=" + result; s_logger.warn(errMsg); } else { String errMsg = "swiftList failed, no lines returns"; s_logger.warn(errMsg); } } return null; } String swiftDelete(SwiftTO swift, String container, String object) { Script command = new Script("/bin/bash", s_logger); command.add("-c"); command.add("/usr/bin/python /usr/local/cloud/systemvm/scripts/storage/secondary/swift -A " + swift.getUrl() + " -U " + swift.getAccount() + ":" + swift.getUserName() + " -K " + swift.getKey() + " delete " + container + " " + object); OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser(); String result = command.execute(parser); if (result != null) { String errMsg = "swiftDelete failed , err=" + result; s_logger.warn(errMsg); return errMsg; } if (parser.getLines() != null) { String[] lines = parser.getLines().split("\\n"); for (String line : lines) { if (line.contains("Errno") || line.contains("failed")) { String errMsg = "swiftDelete failed , err=" + lines.toString(); s_logger.warn(errMsg); return errMsg; } } } return null; } public Answer execute(DeleteSnapshotsDirCommand cmd) { String secondaryStorageUrl = cmd.getSecondaryStorageUrl(); Long accountId = cmd.getAccountId(); Long volumeId = cmd.getVolumeId(); try { String parent = getRootDir(secondaryStorageUrl); String lPath = parent + "/snapshots/" + String.valueOf(accountId) + "/" + String.valueOf(volumeId) + "/*"; String result = deleteLocalFile(lPath); if (result != null) { String errMsg = "failed to delete all snapshots " + lPath + " , err=" + result; s_logger.warn(errMsg); return new Answer(cmd, false, errMsg); } return new Answer(cmd, true, "success"); } catch (Exception e) { String errMsg = cmd + " Command failed due to " + e.toString(); s_logger.warn(errMsg, e); return new Answer(cmd, false, errMsg); } } public Answer execute(final DownloadSnapshotFromS3Command cmd) { final S3TO s3 = cmd.getS3(); final String secondaryStorageUrl = cmd.getSecondaryStorageUrl(); final Long accountId = cmd.getAccountId(); final Long volumeId = cmd.getVolumeId(); try { executeWithNoWaitLock(determineSnapshotLockId(accountId, volumeId), new Callable<Void>() { @Override public Void call() throws Exception { final String directoryName = determineSnapshotLocalDirectory(secondaryStorageUrl, accountId, volumeId); String result = createLocalDir(directoryName); if (result != null) { throw new InternalErrorException(format( "Failed to create directory %1$s during S3 snapshot download.", directoryName)); } final String snapshotFileName = determineSnapshotBackupFilename(cmd.getSnapshotUuid()); final String key = determineSnapshotS3Key(accountId, volumeId, snapshotFileName); final File targetFile = S3Utils.getFile(s3, s3.getBucketName(), key, _storage.getFile(directoryName), new FileNamingStrategy() { @Override public String determineFileName(String key) { return snapshotFileName; } }); if (cmd.getParent() != null) { final String parentPath = join(File.pathSeparator, directoryName, determineSnapshotBackupFilename(cmd.getParent())); result = setVhdParent(targetFile.getAbsolutePath(), parentPath); if (result != null) { throw new InternalErrorException( format("Failed to set the parent for backup %1$s to %2$s due to %3$s.", targetFile.getAbsolutePath(), parentPath, result)); } } return null; } }); return new Answer(cmd, true, format("Succesfully retrieved volume id %1$s for account id %2$s to %3$s from S3.", volumeId, accountId, secondaryStorageUrl)); } catch (Exception e) { final String errMsg = format( "Failed to retrieve volume id %1$s for account id %2$s to %3$s from S3 due to exception %4$s", volumeId, accountId, secondaryStorageUrl, e.getMessage()); s_logger.error(errMsg); return new Answer(cmd, false, errMsg); } } private String determineSnapshotS3Directory(final Long accountId, final Long volumeId) { return join(S3Utils.SEPARATOR, SNAPSHOT_ROOT_DIR, accountId, volumeId); } private String determineSnapshotS3Key(final Long accountId, final Long volumeId, final String snapshotFileName) { final String directoryName = determineSnapshotS3Directory(accountId, volumeId); return join(S3Utils.SEPARATOR, directoryName, snapshotFileName); } private String determineSnapshotLocalDirectory(final String secondaryStorageUrl, final Long accountId, final Long volumeId) { return join(File.pathSeparator, getRootDir(secondaryStorageUrl), SNAPSHOT_ROOT_DIR, accountId, volumeId); } public Answer execute(downloadSnapshotFromSwiftCommand cmd) { SwiftTO swift = cmd.getSwift(); String secondaryStorageUrl = cmd.getSecondaryStorageUrl(); Long accountId = cmd.getAccountId(); Long volumeId = cmd.getVolumeId(); String rFilename = cmd.getSnapshotUuid(); String sParent = cmd.getParent(); String errMsg = ""; try { String parent = getRootDir(secondaryStorageUrl); String lPath = parent + "/snapshots/" + String.valueOf(accountId) + "/" + String.valueOf(volumeId); String result = createLocalDir(lPath); if (result != null) { errMsg = "downloadSnapshotFromSwiftCommand failed due to Create local path failed"; s_logger.warn(errMsg); throw new InternalErrorException(errMsg); } String lFilename = rFilename; if (rFilename.startsWith("VHD-")) { lFilename = rFilename.replace("VHD-", "") + ".vhd"; } String lFullPath = lPath + "/" + lFilename; result = swiftDownload(swift, "S-" + volumeId.toString(), rFilename, lFullPath); if (result != null) { return new Answer(cmd, false, result); } if (sParent != null) { if (sParent.startsWith("VHD-") || sParent.endsWith(".vhd")) { String pFilename = sParent; if (sParent.startsWith("VHD-")) { pFilename = pFilename.replace("VHD-", "") + ".vhd"; } String pFullPath = lPath + "/" + pFilename; result = setVhdParent(lFullPath, pFullPath); if (result != null) { return new Answer(cmd, false, result); } } } return new Answer(cmd, true, "success"); } catch (Exception e) { String msg = cmd + " Command failed due to " + e.toString(); s_logger.warn(msg, e); throw new CloudRuntimeException(msg); } } private Answer execute(ComputeChecksumCommand cmd) { String relativeTemplatePath = cmd.getTemplatePath(); String parent = getRootDir(cmd); if (relativeTemplatePath.startsWith(File.separator)) { relativeTemplatePath = relativeTemplatePath.substring(1); } if (!parent.endsWith(File.separator)) { parent += File.separator; } String absoluteTemplatePath = parent + relativeTemplatePath; MessageDigest digest; String checksum = null; File f = new File(absoluteTemplatePath); InputStream is = null; byte[] buffer = new byte[8192]; int read = 0; if (s_logger.isDebugEnabled()) { s_logger.debug("parent path " + parent + " relative template path " + relativeTemplatePath); } try { digest = MessageDigest.getInstance("MD5"); is = new FileInputStream(f); while ((read = is.read(buffer)) > 0) { digest.update(buffer, 0, read); } byte[] md5sum = digest.digest(); BigInteger bigInt = new BigInteger(1, md5sum); checksum = bigInt.toString(16); if (s_logger.isDebugEnabled()) { s_logger.debug( "Successfully calculated checksum for file " + absoluteTemplatePath + " - " + checksum); } } catch (IOException e) { String logMsg = "Unable to process file for MD5 - " + absoluteTemplatePath; s_logger.error(logMsg); return new Answer(cmd, false, checksum); } catch (NoSuchAlgorithmException e) { return new Answer(cmd, false, checksum); } finally { try { if (is != null) is.close(); } catch (IOException e) { if (s_logger.isDebugEnabled()) { s_logger.debug("Could not close the file " + absoluteTemplatePath); } return new Answer(cmd, false, checksum); } } return new Answer(cmd, true, checksum); } private void configCerts(Certificates certs) { if (certs == null) { configureSSL(); } else { String prvKey = certs.getPrivKey(); String pubCert = certs.getPrivCert(); String certChain = certs.getCertChain(); try { File prvKeyFile = File.createTempFile("prvkey", null); String prvkeyPath = prvKeyFile.getAbsolutePath(); BufferedWriter out = new BufferedWriter(new FileWriter(prvKeyFile)); out.write(prvKey); out.close(); File pubCertFile = File.createTempFile("pubcert", null); String pubCertFilePath = pubCertFile.getAbsolutePath(); out = new BufferedWriter(new FileWriter(pubCertFile)); out.write(pubCert); out.close(); configureSSL(prvkeyPath, pubCertFilePath, null); prvKeyFile.delete(); pubCertFile.delete(); } catch (IOException e) { s_logger.debug("Failed to config ssl: " + e.toString()); } } } 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(_storageGateway, _storageIp, _storageNetmask, nfsHostIp); String nfsPath = nfsHostIp + ":" + uri.getPath(); String dir = UUID.nameUUIDFromBytes(nfsPath.getBytes()).toString(); String root = _parent + "/" + dir; mount(root, nfsPath); configCerts(cmd.getCerts()); nfsIps.add(nfsHostIp); return new SecStorageSetupAnswer(dir); } catch (Exception e) { String msg = "GetRootDir for " + secUrl + " failed due to " + e.toString(); s_logger.error(msg); return new Answer(cmd, false, msg); } } private String deleteSnapshotBackupFromLocalFileSystem(final String secondaryStorageUrl, final Long accountId, final Long volumeId, final String name, final Boolean deleteAllFlag) { final String lPath = determineSnapshotLocalDirectory(secondaryStorageUrl, accountId, volumeId) + File.pathSeparator + (deleteAllFlag ? "*" : "*" + name + "*"); final String result = deleteLocalFile(lPath); if (result != null) { return "failed to delete snapshot " + lPath + " , err=" + result; } return null; } private String deleteSnapshotBackupfromS3(final S3TO s3, final String secondaryStorageUrl, final Long accountId, final Long volumeId, final String name, final Boolean deleteAllFlag) { try { final String bucket = s3.getBucketName(); final String result = executeWithNoWaitLock(determineSnapshotLockId(accountId, volumeId), new Callable<String>() { @Override public String call() throws Exception { final String innerResult = deleteSnapshotBackupFromLocalFileSystem(secondaryStorageUrl, accountId, volumeId, name, deleteAllFlag); if (innerResult != null) { return innerResult; } if (deleteAllFlag) { S3Utils.deleteDirectory(s3, bucket, determineSnapshotS3Directory(accountId, volumeId)); } else { S3Utils.deleteObject(s3, bucket, determineSnapshotS3Key(accountId, volumeId, determineSnapshotBackupFilename(name))); } return null; } }); return result; } catch (Exception e) { s_logger.error( String.format("Failed to delete snapshot backup for account id %1$s volume id %2$sfrom S3.", accountId, volumeId), e); return e.getMessage(); } } private String determineSnapshotBackupFilename(final String snapshotUuid) { return snapshotUuid + ".vhd"; } private String determineSnapshotLockId(final Long accountId, final Long volumeId) { return join("_", "SNAPSHOT", accountId, volumeId); } protected Answer execute(final DeleteSnapshotBackupCommand cmd) { String secondaryStorageUrl = cmd.getSecondaryStorageUrl(); Long accountId = cmd.getAccountId(); Long volumeId = cmd.getVolumeId(); String name = cmd.getSnapshotUuid(); try { SwiftTO swift = cmd.getSwift(); S3TO s3 = cmd.getS3(); if (swift == null) { final String result = deleteSnapshotBackupFromLocalFileSystem(secondaryStorageUrl, accountId, volumeId, name, cmd.isAll()); if (result != null) { s_logger.warn(result); return new Answer(cmd, false, result); } } else if (s3 != null) { final String result = deleteSnapshotBackupfromS3(s3, secondaryStorageUrl, accountId, volumeId, name, cmd.isAll()); if (result != null) { s_logger.warn(result); return new Answer(cmd, false, result); } } else { String filename; if (cmd.isAll()) { filename = ""; } else { filename = name; } String result = swiftDelete(swift, "V-" + volumeId.toString(), filename); if (result != null) { String errMsg = "failed to delete snapshot " + filename + " , err=" + result; s_logger.warn(errMsg); return new Answer(cmd, false, errMsg); } } return new Answer(cmd, true, "success"); } catch (Exception e) { String errMsg = cmd + " Command failed due to " + e.toString(); s_logger.warn(errMsg, e); return new Answer(cmd, false, errMsg); } } Map<String, TemplateInfo> swiftListTemplate(SwiftTO swift) { String[] containers = swiftList(swift, "", ""); if (containers == null) { return null; } Map<String, TemplateInfo> tmpltInfos = new HashMap<String, TemplateInfo>(); for (String container : containers) { if (container.startsWith("T-")) { String ldir = _tmpltDir + "/" + UUID.randomUUID().toString(); createLocalDir(ldir); String lFullPath = ldir + "/" + _tmpltpp; swiftDownload(swift, container, _tmpltpp, lFullPath); TemplateLocation loc = new TemplateLocation(_storage, ldir); try { if (!loc.load()) { s_logger.warn("Can not parse template.properties file for template " + container); continue; } } catch (IOException e) { s_logger.warn("Unable to load template location " + ldir + " due to " + e.toString(), e); continue; } TemplateInfo tInfo = loc.getTemplateInfo(); tInfo.setInstallPath(container); tmpltInfos.put(tInfo.getTemplateName(), tInfo); loc.purge(); deleteLocalDir(ldir); } } return tmpltInfos; } private Answer execute(ListTemplateCommand cmd) { if (!_inSystemVM) { return new Answer(cmd, true, null); } if (cmd.getSwift() != null) { Map<String, TemplateInfo> templateInfos = swiftListTemplate(cmd.getSwift()); return new ListTemplateAnswer(cmd.getSwift().toString(), templateInfos); } else { String root = getRootDir(cmd.getSecUrl()); Map<String, TemplateInfo> templateInfos = _dlMgr.gatherTemplateInfo(root); return new ListTemplateAnswer(cmd.getSecUrl(), templateInfos); } } private Answer execute(ListVolumeCommand cmd) { if (!_inSystemVM) { return new Answer(cmd, true, null); } String root = getRootDir(cmd.getSecUrl()); Map<Long, TemplateInfo> templateInfos = _dlMgr.gatherVolumeInfo(root); return new ListVolumeAnswer(cmd.getSecUrl(), templateInfos); } private Answer execute(SecStorageVMSetupCommand cmd) { if (!_inSystemVM) { return new Answer(cmd, true, null); } boolean success = true; StringBuilder result = new StringBuilder(); for (String cidr : cmd.getAllowedInternalSites()) { if (nfsIps.contains(cidr)) { /* * if the internal download ip is the same with secondary storage ip, adding internal sites will flush * ip route to nfs through storage ip. */ continue; } String tmpresult = allowOutgoingOnPrivate(cidr); if (tmpresult != null) { result.append(", ").append(tmpresult); success = false; } } if (success) { if (cmd.getCopyPassword() != null && cmd.getCopyUserName() != null) { String tmpresult = configureAuth(cmd.getCopyUserName(), cmd.getCopyPassword()); if (tmpresult != null) { result.append("Failed to configure auth for copy ").append(tmpresult); success = false; } } } return new Answer(cmd, success, result.toString()); } private String setVhdParent(String lFullPath, String pFullPath) { Script command = new Script("/bin/bash", s_logger); command.add("-c"); command.add("/bin/vhd-util modify -n " + lFullPath + " -p " + pFullPath); String result = command.execute(); if (result != null) { String errMsg = "failed to set vhd parent, child " + lFullPath + " parent " + pFullPath + ", err=" + result; s_logger.warn(errMsg); return errMsg; } return null; } private String createLocalDir(String folder) { Script command = new Script("/bin/bash", s_logger); command.add("-c"); command.add("mkdir -p " + folder); String result = command.execute(); if (result != null) { String errMsg = "Create local path " + folder + " failed , err=" + result; s_logger.warn(errMsg); return errMsg; } return null; } private String deleteLocalDir(String folder) { Script command = new Script("/bin/bash", s_logger); command.add("-c"); command.add("rmdir " + folder); String result = command.execute(); if (result != null) { String errMsg = "Delete local path " + folder + " failed , err=" + result; s_logger.warn(errMsg); return errMsg; } return null; } private String deleteLocalFile(String fullPath) { Script command = new Script("/bin/bash", s_logger); command.add("-c"); command.add("rm -f " + fullPath); String result = command.execute(); if (result != null) { String errMsg = "Failed to delete file " + fullPath + ", err=" + result; s_logger.warn(errMsg); return errMsg; } return null; } public String allowOutgoingOnPrivate(String destCidr) { Script command = new Script("/bin/bash", s_logger); String intf = "eth1"; command.add("-c"); command.add("iptables -I OUTPUT -o " + intf + " -d " + destCidr + " -p tcp -m state --state NEW -m tcp -j ACCEPT"); String result = command.execute(); if (result != null) { s_logger.warn("Error in allowing outgoing to " + destCidr + ", err=" + result); return "Error in allowing outgoing to " + destCidr + ", err=" + result; } addRouteToInternalIpOrCidr(_localgw, _eth1ip, _eth1mask, destCidr); return null; } private Answer execute(SecStorageFirewallCfgCommand cmd) { if (!_inSystemVM) { return new Answer(cmd, true, null); } List<String> ipList = new ArrayList<String>(); for (PortConfig pCfg : cmd.getPortConfigs()) { if (pCfg.isAdd()) { ipList.add(pCfg.getSourceIp()); } } boolean success = true; String result; result = configureIpFirewall(ipList, cmd.getIsAppendAIp()); if (result != null) success = false; return new Answer(cmd, success, result); } protected GetStorageStatsAnswer execute(final GetStorageStatsCommand cmd) { String rootDir = getRootDir(cmd.getSecUrl()); 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 { return new GetStorageStatsAnswer(cmd, totalSize, usedSize); } } protected Answer execute(final DeleteTemplateCommand cmd) { String relativeTemplatePath = cmd.getTemplatePath(); String parent = getRootDir(cmd); if (relativeTemplatePath.startsWith(File.separator)) { relativeTemplatePath = relativeTemplatePath.substring(1); } if (!parent.endsWith(File.separator)) { parent += File.separator; } String absoluteTemplatePath = parent + relativeTemplatePath; File tmpltParent = new File(absoluteTemplatePath).getParentFile(); String details = null; if (!tmpltParent.exists()) { details = "template parent directory " + tmpltParent.getName() + " doesn't exist"; s_logger.debug(details); return new Answer(cmd, true, details); } File[] tmpltFiles = tmpltParent.listFiles(); if (tmpltFiles == null || tmpltFiles.length == 0) { details = "No files under template parent directory " + tmpltParent.getName(); s_logger.debug(details); } else { boolean found = false; for (File f : tmpltFiles) { if (!found && f.getName().equals("template.properties")) { found = true; } if (!f.delete()) { return new Answer(cmd, false, "Unable to delete file " + f.getName() + " under Template path " + relativeTemplatePath); } } if (!found) { details = "Can not find template.properties under " + tmpltParent.getName(); s_logger.debug(details); } } if (!tmpltParent.delete()) { details = "Unable to delete directory " + tmpltParent.getName() + " under Template path " + relativeTemplatePath; s_logger.debug(details); return new Answer(cmd, false, details); } return new Answer(cmd, true, null); } protected Answer execute(final DeleteVolumeCommand cmd) { String relativeVolumePath = cmd.getVolumePath(); String parent = getRootDir(cmd); if (relativeVolumePath.startsWith(File.separator)) { relativeVolumePath = relativeVolumePath.substring(1); } if (!parent.endsWith(File.separator)) { parent += File.separator; } String absoluteVolumePath = parent + relativeVolumePath; File tmpltParent = new File(absoluteVolumePath).getParentFile(); String details = null; if (!tmpltParent.exists()) { details = "volume parent directory " + tmpltParent.getName() + " doesn't exist"; s_logger.debug(details); return new Answer(cmd, true, details); } File[] tmpltFiles = tmpltParent.listFiles(); if (tmpltFiles == null || tmpltFiles.length == 0) { details = "No files under volume parent directory " + tmpltParent.getName(); s_logger.debug(details); } else { boolean found = false; for (File f : tmpltFiles) { if (!found && f.getName().equals("volume.properties")) { found = true; } if (!f.delete()) { return new Answer(cmd, false, "Unable to delete file " + f.getName() + " under Volume path " + relativeVolumePath); } } if (!found) { details = "Can not find volume.properties under " + tmpltParent.getName(); s_logger.debug(details); } } if (!tmpltParent.delete()) { details = "Unable to delete directory " + tmpltParent.getName() + " under Volume path " + relativeVolumePath; s_logger.debug(details); return new Answer(cmd, false, details); } return new Answer(cmd, true, null); } Answer execute(CleanupSnapshotBackupCommand cmd) { String parent = getRootDir(cmd.getSecondaryStoragePoolURL()); if (!parent.endsWith(File.separator)) { parent += File.separator; } String absoluteSnapsthotDir = parent + File.separator + "snapshots" + File.separator + cmd.getAccountId() + File.separator + cmd.getVolumeId(); File ssParent = new File(absoluteSnapsthotDir); if (ssParent.exists() && ssParent.isDirectory()) { File[] files = ssParent.listFiles(); for (File file : files) { boolean found = false; String filename = file.getName(); for (String uuid : cmd.getValidBackupUUIDs()) { if (filename.startsWith(uuid)) { found = true; break; } } if (!found) { file.delete(); String msg = "snapshot " + filename + " is not recorded in DB, remove it"; s_logger.warn(msg); } } } return new Answer(cmd, true, null); } synchronized 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 = _parent + "/" + 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); } } @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) { if (size == null || size.isEmpty()) { return -1; } long multiplier = 1; if (size.endsWith("T")) { multiplier = 1024l * 1024l * 1024l * 1024l; } else if (size.endsWith("G")) { multiplier = 1024l * 1024l * 1024l; } else if (size.endsWith("M")) { multiplier = 1024l * 1024l; } else { assert (false) : "Well, I have no idea what this is: " + size; } return (long) (Double.parseDouble(size.substring(0, size.length() - 1)) * multiplier); } @Override public Type getType() { if (SecondaryStorageVm.Role.templateProcessor.toString().equals(_role)) return Host.Type.SecondaryStorage; return Host.Type.SecondaryStorageCmdExecutor; } @Override public PingCommand getCurrentStatus(final long id) { return new PingStorageCommand(Host.Type.Storage, id, new HashMap<String, Boolean>()); } @Override public boolean configure(String name, Map<String, Object> params) throws ConfigurationException { _eth1ip = (String) params.get("eth1ip"); _eth1mask = (String) params.get("eth1mask"); if (_eth1ip != null) { //can only happen inside service vm params.put("private.network.device", "eth1"); } else { s_logger.warn("Wait, what's going on? eth1ip is null!!"); } String eth2ip = (String) params.get("eth2ip"); if (eth2ip != null) { params.put("public.network.device", "eth2"); } _publicIp = (String) params.get("eth2ip"); _hostname = (String) params.get("name"); _storageIp = (String) params.get("storageip"); if (_storageIp == null) { s_logger.warn("Wait, there is no storageip in /proc/cmdline, something wrong!"); } _storageNetmask = (String) params.get("storagenetmask"); _storageGateway = (String) params.get("storagegateway"); super.configure(name, params); _params = params; String value = (String) params.get("scripts.timeout"); _timeout = NumbersUtil.parseInt(value, 1440) * 1000; _storage = (StorageLayer) params.get(StorageLayer.InstanceConfigKey); if (_storage == null) { value = (String) params.get(StorageLayer.ClassConfigKey); if (value == null) { value = "com.cloud.storage.JavaStorageLayer"; } try { Class<?> clazz = Class.forName(value); _storage = (StorageLayer) clazz.newInstance(); _storage.configure("StorageLayer", params); } catch (ClassNotFoundException e) { throw new ConfigurationException("Unable to find class " + value); } catch (InstantiationException e) { throw new ConfigurationException("Unable to find class " + value); } catch (IllegalAccessException e) { throw new ConfigurationException("Unable to find class " + value); } } _storage.mkdirs(_parent); _configSslScr = Script.findScript(getDefaultScriptsDir(), "config_ssl.sh"); if (_configSslScr != null) { s_logger.info("config_ssl.sh found in " + _configSslScr); } _configAuthScr = Script.findScript(getDefaultScriptsDir(), "config_auth.sh"); if (_configSslScr != null) { s_logger.info("config_auth.sh found in " + _configAuthScr); } _configIpFirewallScr = Script.findScript(getDefaultScriptsDir(), "ipfirewall.sh"); if (_configIpFirewallScr != null) { s_logger.info("_configIpFirewallScr found in " + _configIpFirewallScr); } _role = (String) params.get("role"); if (_role == null) _role = SecondaryStorageVm.Role.templateProcessor.toString(); s_logger.info("Secondary storage runs in role " + _role); _guid = (String) params.get("guid"); if (_guid == null) { throw new ConfigurationException("Unable to find the guid"); } _dc = (String) params.get("zone"); if (_dc == null) { throw new ConfigurationException("Unable to find the zone"); } _pod = (String) params.get("pod"); _instance = (String) params.get("instance"); String inSystemVM = (String) params.get("secondary.storage.vm"); if (inSystemVM == null || "true".equalsIgnoreCase(inSystemVM)) { _inSystemVM = true; _localgw = (String) params.get("localgw"); if (_localgw != null) { // can only happen inside service vm String mgmtHost = (String) params.get("host"); addRouteToInternalIpOrCidr(_localgw, _eth1ip, _eth1mask, mgmtHost); String internalDns1 = (String) params.get("internaldns1"); if (internalDns1 == null) { s_logger.warn("No DNS entry found during configuration of NfsSecondaryStorage"); } else { addRouteToInternalIpOrCidr(_localgw, _eth1ip, _eth1mask, internalDns1); } String internalDns2 = (String) params.get("internaldns2"); if (internalDns2 != null) { addRouteToInternalIpOrCidr(_localgw, _eth1ip, _eth1mask, internalDns2); } } startAdditionalServices(); _params.put("install.numthreads", "50"); _params.put("secondary.storage.vm", "true"); } try { _params.put(StorageLayer.InstanceConfigKey, _storage); _dlMgr = new DownloadManagerImpl(); _dlMgr.configure("DownloadManager", _params); _upldMgr = new UploadManagerImpl(); _upldMgr.configure("UploadManager", params); } catch (ConfigurationException e) { s_logger.warn("Caught problem while configuring DownloadManager", e); return false; } return true; } private void startAdditionalServices() { Script command = new Script("/bin/bash", s_logger); command.add("-c"); command.add("if [ -f /etc/init.d/ssh ]; then service ssh restart; else service sshd restart; fi "); String result = command.execute(); if (result != null) { s_logger.warn("Error in starting sshd service err=" + result); } command = new Script("/bin/bash", s_logger); command.add("-c"); command.add("iptables -I INPUT -i eth1 -p tcp -m state --state NEW -m tcp --dport 3922 -j ACCEPT"); result = command.execute(); if (result != null) { s_logger.warn("Error in opening up ssh port err=" + result); } } private void addRouteToInternalIpOrCidr(String localgw, String eth1ip, String eth1mask, String destIpOrCidr) { s_logger.debug("addRouteToInternalIp: localgw=" + localgw + ", eth1ip=" + eth1ip + ", eth1mask=" + eth1mask + ",destIp=" + destIpOrCidr); if (destIpOrCidr == null) { s_logger.debug("addRouteToInternalIp: destIp is null"); return; } if (!NetUtils.isValidIp(destIpOrCidr) && !NetUtils.isValidCIDR(destIpOrCidr)) { s_logger.warn(" destIp is not a valid ip address or cidr destIp=" + destIpOrCidr); return; } boolean inSameSubnet = false; if (NetUtils.isValidIp(destIpOrCidr)) { if (eth1ip != null && eth1mask != null) { inSameSubnet = NetUtils.sameSubnet(eth1ip, destIpOrCidr, eth1mask); } else { s_logger.warn("addRouteToInternalIp: unable to determine same subnet: _eth1ip=" + eth1ip + ", dest ip=" + destIpOrCidr + ", _eth1mask=" + eth1mask); } } else { inSameSubnet = NetUtils.isNetworkAWithinNetworkB(destIpOrCidr, NetUtils.ipAndNetMaskToCidr(eth1ip, eth1mask)); } if (inSameSubnet) { s_logger.debug("addRouteToInternalIp: dest ip " + destIpOrCidr + " is in the same subnet as eth1 ip " + eth1ip); return; } Script command = new Script("/bin/bash", s_logger); command.add("-c"); command.add("ip route delete " + destIpOrCidr); command.execute(); command = new Script("/bin/bash", s_logger); command.add("-c"); command.add("ip route add " + destIpOrCidr + " via " + localgw); String result = command.execute(); if (result != null) { s_logger.warn("Error in configuring route to internal ip err=" + result); } else { s_logger.debug("addRouteToInternalIp: added route to internal ip=" + destIpOrCidr + " via " + localgw); } } private void configureSSL() { Script command = new Script(_configSslScr); command.add("-i", _publicIp); command.add("-h", _hostname); String result = command.execute(); if (result != null) { s_logger.warn("Unable to configure httpd to use ssl"); } } private void configureSSL(String prvkeyPath, String prvCertPath, String certChainPath) { Script command = new Script(_configSslScr); command.add("-i", _publicIp); command.add("-h", _hostname); command.add("-k", prvkeyPath); command.add("-p", prvCertPath); if (certChainPath != null) { command.add("-t", certChainPath); } String result = command.execute(); if (result != null) { s_logger.warn("Unable to configure httpd to use ssl"); } } private String configureAuth(String user, String passwd) { Script command = new Script(_configAuthScr); command.add(user); command.add(passwd); String result = command.execute(); if (result != null) { s_logger.warn("Unable to configure httpd to use auth"); } return result; } private String configureIpFirewall(List<String> ipList, boolean isAppend) { Script command = new Script(_configIpFirewallScr); command.add(String.valueOf(isAppend)); for (String ip : ipList) { command.add(ip); } String result = command.execute(); if (result != null) { s_logger.warn("Unable to configure firewall for command : " + command); } return result; } 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; } } Script script = null; String result = null; script = new Script(!_inSystemVM, "mount", _timeout, s_logger); List<String> res = new ArrayList<String>(); 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(nfsPath); command.add(root); result = command.execute(); if (result != null) { 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(root)) { return null; } // Create the volumes dir if (!checkForVolumesDir(root)) { return null; } return root; } @Override public boolean start() { return true; } @Override public boolean stop() { return true; } @Override public StartupCommand[] initialize() { final StartupSecondaryStorageCommand cmd = new StartupSecondaryStorageCommand(); fillNetworkInformation(cmd); if (_publicIp != null) cmd.setPublicIpAddress(_publicIp); Script command = new Script("/bin/bash", s_logger); command.add("-c"); command.add("ln -sf " + _parent + " /var/www/html/copy"); String result = command.execute(); if (result != null) { s_logger.warn("Error in linking err=" + result); return null; } return new StartupCommand[] { cmd }; } protected boolean checkForSnapshotsDir(String mountPoint) { String snapshotsDirLocation = mountPoint + File.separator + "snapshots"; return createDir("snapshots", snapshotsDirLocation, mountPoint); } protected boolean checkForVolumesDir(String mountPoint) { String volumesDirLocation = mountPoint + "/" + "volumes"; return createDir("volumes", volumesDirLocation, mountPoint); } protected boolean createDir(String dirName, String dirLocation, String mountPoint) { boolean dirExists = false; File dir = new File(dirLocation); if (dir.exists()) { if (dir.isDirectory()) { s_logger.debug(dirName + " already exists on secondary storage, and is mounted at " + mountPoint); dirExists = true; } else { if (dir.delete() && _storage.mkdir(dirLocation)) { dirExists = true; } } } else if (_storage.mkdir(dirLocation)) { dirExists = true; } if (dirExists) { s_logger.info(dirName + " directory created/exists on Secondary Storage."); } else { s_logger.info(dirName + " directory does not exist on Secondary Storage."); } return dirExists; } @Override protected String getDefaultScriptsDir() { return "./scripts/storage/secondary"; } @Override public void setName(String name) { // TODO Auto-generated method stub } @Override public void setConfigParams(Map<String, Object> params) { // TODO Auto-generated method stub } @Override public Map<String, Object> getConfigParams() { // TODO Auto-generated method stub return null; } @Override public int getRunLevel() { // TODO Auto-generated method stub return 0; } @Override public void setRunLevel(int level) { // TODO Auto-generated method stub } }