-
Notifications
You must be signed in to change notification settings - Fork 1.3k
CLOUDSTACK-10146: Bypass Secondary Storage for KVM templates #2379
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
6103f96
CLOUDSTACK-10146: Bypass Secondary Storage for KVM templates
nvazquez 5492090
CLOUDSTACK-10146: Refactor
nvazquez ca8f26a
removed useless/unused javadoc tags
DaanHoogland c3c268e
Refactor HTTP and HTTPS downloaders to use IOUtils
nvazquez d4a3659
removed wrapper to IOUtils.copy()
DaanHoogland bd230ed
Merge branch 'master' into bypasssecstoragekvm
yadvr 003cf61
Merge branch 'master' into bypasssecstoragekvm
yadvr 954ba4e
regression: annotation on command wrapper
DaanHoogland e10371e
CLOUDSTACK-10146 kvm can be passed (or KvM or whatnot)
DaanHoogland 80177eb
include
DaanHoogland File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
agent/src/com/cloud/agent/direct/download/DirectTemplateDownloader.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| // | ||
| // 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.agent.direct.download; | ||
|
|
||
| public interface DirectTemplateDownloader { | ||
|
|
||
| class DirectTemplateInformation { | ||
| private String installPath; | ||
| private Long size; | ||
| private String checksum; | ||
|
|
||
| public DirectTemplateInformation(String installPath, Long size, String checksum) { | ||
| this.installPath = installPath; | ||
| this.size = size; | ||
| this.checksum = checksum; | ||
| } | ||
|
|
||
| public String getInstallPath() { | ||
| return installPath; | ||
| } | ||
|
|
||
| public Long getSize() { | ||
| return size; | ||
| } | ||
|
|
||
| public String getChecksum() { | ||
| return checksum; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Perform template download to pool specified on downloader creation | ||
| * @return true if successful, false if not | ||
| */ | ||
| boolean downloadTemplate(); | ||
|
|
||
| /** | ||
| * Perform extraction (if necessary) and installation of previously downloaded template | ||
| * @return true if successful, false if not | ||
| */ | ||
| boolean extractAndInstallDownloadedTemplate(); | ||
|
|
||
| /** | ||
| * Get template information after it is properly installed on pool | ||
| * @return template information | ||
| */ | ||
| DirectTemplateInformation getTemplateInformation(); | ||
|
|
||
| /** | ||
| * Perform checksum validation of previously downloadeed template | ||
| * @return true if successful, false if not | ||
| */ | ||
| boolean validateChecksum(); | ||
| } |
185 changes: 185 additions & 0 deletions
185
agent/src/com/cloud/agent/direct/download/DirectTemplateDownloaderImpl.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,185 @@ | ||
| // | ||
| // 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.agent.direct.download; | ||
|
|
||
| import com.cloud.utils.exception.CloudRuntimeException; | ||
| import com.cloud.utils.script.Script; | ||
| import org.apache.cloudstack.utils.security.ChecksumValue; | ||
| import org.apache.commons.lang.StringUtils; | ||
|
|
||
| import java.io.File; | ||
| import java.util.UUID; | ||
|
|
||
| public abstract class DirectTemplateDownloaderImpl implements DirectTemplateDownloader { | ||
|
|
||
| private String url; | ||
| private String destPoolPath; | ||
| private Long templateId; | ||
| private String downloadedFilePath; | ||
| private String installPath; | ||
| private String checksum; | ||
|
|
||
| protected DirectTemplateDownloaderImpl(final String url, final String destPoolPath, final Long templateId, final String checksum) { | ||
| this.url = url; | ||
| this.destPoolPath = destPoolPath; | ||
| this.templateId = templateId; | ||
| this.checksum = checksum; | ||
| } | ||
|
|
||
| private static String directDownloadDir = "template"; | ||
|
|
||
| /** | ||
| * Return direct download temporary path to download template | ||
| */ | ||
| protected static String getDirectDownloadTempPath(Long templateId) { | ||
| String templateIdAsString = String.valueOf(templateId); | ||
| return directDownloadDir + File.separator + templateIdAsString.substring(0,1) + | ||
| File.separator + templateIdAsString; | ||
| } | ||
|
|
||
| /** | ||
| * Create folder on path if it does not exist | ||
| */ | ||
| protected void createFolder(String path) { | ||
| File dir = new File(path); | ||
| if (!dir.exists()) { | ||
| dir.mkdirs(); | ||
| } | ||
| } | ||
|
|
||
| public String getUrl() { | ||
| return url; | ||
| } | ||
|
|
||
| public String getDestPoolPath() { | ||
| return destPoolPath; | ||
| } | ||
|
|
||
| public Long getTemplateId() { | ||
| return templateId; | ||
| } | ||
|
|
||
| public String getDownloadedFilePath() { | ||
| return downloadedFilePath; | ||
| } | ||
|
|
||
| public void setDownloadedFilePath(String filePath) { | ||
| this.downloadedFilePath = filePath; | ||
| } | ||
|
|
||
| /** | ||
| * Return filename from url | ||
| */ | ||
| public String getFileNameFromUrl() { | ||
| String[] urlParts = url.split("/"); | ||
| return urlParts[urlParts.length - 1]; | ||
| } | ||
|
|
||
| /** | ||
| * Checks if downloaded template is extractable | ||
| * @return true if it should be extracted, false if not | ||
| */ | ||
| private boolean isTemplateExtractable() { | ||
| String type = Script.runSimpleBashScript("file " + downloadedFilePath + " | awk -F' ' '{print $2}'"); | ||
| return type.equalsIgnoreCase("bzip2") || type.equalsIgnoreCase("gzip") || type.equalsIgnoreCase("zip"); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean extractAndInstallDownloadedTemplate() { | ||
| installPath = UUID.randomUUID().toString(); | ||
| if (isTemplateExtractable()) { | ||
| extractDownloadedTemplate(); | ||
| } else { | ||
| Script.runSimpleBashScript("mv " + downloadedFilePath + " " + getInstallFullPath()); | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| /** | ||
| * Return install full path | ||
| */ | ||
| private String getInstallFullPath() { | ||
| return destPoolPath + File.separator + installPath; | ||
| } | ||
|
|
||
| /** | ||
| * Return extract command to execute given downloaded file | ||
| */ | ||
| private String getExtractCommandForDownloadedFile() { | ||
| if (downloadedFilePath.endsWith(".zip")) { | ||
| return "unzip -p " + downloadedFilePath + " | cat > " + getInstallFullPath(); | ||
| } else if (downloadedFilePath.endsWith(".bz2")) { | ||
| return "bunzip2 -c " + downloadedFilePath + " > " + getInstallFullPath(); | ||
| } else if (downloadedFilePath.endsWith(".gz")) { | ||
| return "gunzip -c " + downloadedFilePath + " > " + getInstallFullPath(); | ||
| } else { | ||
| throw new CloudRuntimeException("Unable to extract template " + templateId + " on " + downloadedFilePath); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Extract downloaded template into installPath, remove compressed file | ||
| */ | ||
| private void extractDownloadedTemplate() { | ||
| String extractCommand = getExtractCommandForDownloadedFile(); | ||
| Script.runSimpleBashScript(extractCommand); | ||
| Script.runSimpleBashScript("rm -f " + downloadedFilePath); | ||
| } | ||
|
|
||
| @Override | ||
| public DirectTemplateInformation getTemplateInformation() { | ||
| String sizeResult = Script.runSimpleBashScript("ls -als " + getInstallFullPath() + " | awk '{print $1}'"); | ||
| long size = Long.parseLong(sizeResult); | ||
| return new DirectTemplateInformation(installPath, size, checksum); | ||
| } | ||
|
|
||
| /** | ||
| * Return checksum command from algorithm | ||
| */ | ||
| private String getChecksumCommandFromAlgorithm(String algorithm) { | ||
| if (algorithm.equalsIgnoreCase("MD5")) { | ||
| return "md5sum"; | ||
| } else if (algorithm.equalsIgnoreCase("SHA-1")) { | ||
| return "sha1sum"; | ||
| } else if (algorithm.equalsIgnoreCase("SHA-224")) { | ||
| return "sha224sum"; | ||
| } else if (algorithm.equalsIgnoreCase("SHA-256")) { | ||
| return "sha256sum"; | ||
| } else if (algorithm.equalsIgnoreCase("SHA-384")) { | ||
| return "sha384sum"; | ||
| } else if (algorithm.equalsIgnoreCase("SHA-512")) { | ||
| return "sha512sum"; | ||
| } else { | ||
| throw new CloudRuntimeException("Unknown checksum algorithm: " + algorithm); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public boolean validateChecksum() { | ||
| if (StringUtils.isNotBlank(checksum)) { | ||
| ChecksumValue providedChecksum = new ChecksumValue(checksum); | ||
| String algorithm = providedChecksum.getAlgorithm(); | ||
| String checksumCommand = "echo '%s %s' | %s -c --quiet"; | ||
| String cmd = String.format(checksumCommand, providedChecksum.getChecksum(), downloadedFilePath, getChecksumCommandFromAlgorithm(algorithm)); | ||
| int result = Script.runSimpleBashScriptForExitValue(cmd); | ||
| return result == 0; | ||
| } | ||
| return true; | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole setup process could be implemented as a shell script with the java code calling that script to perform the job.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. You can do that, or you can do everything in Java (reading and writing files).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I prefer using this java approach for those that can be done instead of using a script file. If you prefer I can refactor it to a script file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer going the script way, perhaps re-using one of the import keystore/cert scripts. Alternatively,
KeyStorecould be read and manipulated (keys imported etc) by using Java only, agreeing with what @rafaelweingartner suggested.