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.utils; import java.io.File; import java.net.URL; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Hex; import org.apache.log4j.Logger; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.OutputInterpreter; import com.cloud.utils.script.Script; public class SwiftUtil { private static Logger logger = Logger.getLogger(SwiftUtil.class); protected static final long SWIFT_MAX_SIZE = 5L * 1024L * 1024L * 1024L; private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1"; private static final String CD_SRC = "cd %s;"; private static final String SWIFT_CMD = "/usr/bin/python %s -A %s -U %s:%s -K %s %s"; private static final String WITH_STORAGE_POLICY = " --storage-policy \"%s\""; private static final String WITH_SEGMENTS = " -S " + SWIFT_MAX_SIZE; private static final String[] OPERATIONS_WITH_STORAGE_POLICIES = { "post", "upload" }; public interface SwiftClientCfg { String getAccount(); String getUserName(); String getKey(); String getEndPoint(); String getStoragePolicy(); } private static String getSwiftCLIPath() { String swiftCLI = Script.findScript("scripts/storage/secondary", "swift"); if (swiftCLI == null) { logger.debug("Can't find swift cli at scripts/storage/secondary/swift"); throw new CloudRuntimeException("Can't find swift cli at scripts/storage/secondary/swift"); } return swiftCLI; } public static boolean postMeta(SwiftClientCfg cfg, String container, String object, Map<String, String> metas) { Script command = new Script("/bin/bash", logger); command.add("-c"); command.add(getSwiftObjectCmd(cfg, getSwiftCLIPath(), "post", container, object) + getMeta(metas)); OutputInterpreter.OneLineParser parser = new OutputInterpreter.OneLineParser(); String result = command.execute(parser); if (result != null) { throw new CloudRuntimeException("Failed to post meta" + result); } return true; } public static String putObject(SwiftClientCfg cfg, File srcFile, String container, String fileName) { if (fileName == null) { fileName = srcFile.getName(); } Script command = new Script("/bin/bash", logger); command.add("-c"); command.add(String.format(CD_SRC, srcFile.getParent()) + getUploadObjectCommand(cfg, getSwiftCLIPath(), container, fileName, srcFile.length())); OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser(); String result = command.execute(parser); if (result != null) { throw new CloudRuntimeException("Failed to upload file: " + result); } if (parser.getLines() != null) { String[] lines = parser.getLines().split("\\n"); for (String line : lines) { if (line.contains("Errno") || line.contains("failed") || line.contains("not found")) { throw new CloudRuntimeException("Failed to upload file: " + Arrays.toString(lines)); } } } return container + File.separator + srcFile.getName(); } public static String[] list(SwiftClientCfg swift, String container, String rFilename) { StringBuilder swiftCmdBuilder = new StringBuilder(); swiftCmdBuilder.append(getSwiftContainerCmd(swift, getSwiftCLIPath(), "list", container)); if (rFilename != null) { swiftCmdBuilder.append(" -p "); swiftCmdBuilder.append(rFilename); } Script command = new Script("/bin/bash", logger); command.add("-c"); command.add(swiftCmdBuilder.toString()); OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser(); String result = command.execute(parser); if (result == null && parser.getLines() != null && !parser.getLines().equalsIgnoreCase("")) { return parser.getLines().split("\\n"); } else { if (result != null) { String errMsg = "swiftList failed , err=" + result; logger.debug("Failed to list " + errMsg); } else { String errMsg = "swiftList failed, no lines returns"; logger.debug("Failed to list " + errMsg); } } return new String[0]; } public static File getObject(SwiftClientCfg cfg, File destDirectory, String swiftPath) { int firstIndexOfSeparator = swiftPath.indexOf(File.separator); String container = swiftPath.substring(0, firstIndexOfSeparator); String srcPath = swiftPath.substring(firstIndexOfSeparator + 1); String destFilePath; if (destDirectory.isDirectory()) { destFilePath = destDirectory.getAbsolutePath() + File.separator + srcPath; } else { destFilePath = destDirectory.getAbsolutePath(); } Script command = new Script("/bin/bash", logger); command.add("-c"); command.add( getSwiftObjectCmd(cfg, getSwiftCLIPath(), "download", container, srcPath) + " -o " + destFilePath); OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser(); String result = command.execute(parser); if (result != null) { String errMsg = "swiftDownload failed err=" + result; logger.debug(errMsg); throw new CloudRuntimeException("failed to get object: " + swiftPath); } 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=" + Arrays.toString(lines); logger.debug(errMsg); throw new CloudRuntimeException("Failed to get object: " + swiftPath); } } } return new File(destFilePath); } public static boolean deleteObject(SwiftClientCfg cfg, String path) { Script command = new Script("/bin/bash", logger); command.add("-c"); String[] paths = splitSwiftPath(path); if (paths == null) { return false; } String container = paths[0]; String objectName = paths[1]; command.add(getSwiftObjectCmd(cfg, getSwiftCLIPath(), "delete", container, objectName)); OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser(); command.execute(parser); return true; } public static boolean setTempKey(SwiftClientCfg cfg, String tempKey) { Map<String, String> tempKeyMap = new HashMap<>(); tempKeyMap.put("Temp-URL-Key", tempKey); return postMeta(cfg, "", "", tempKeyMap); } public static URL generateTempUrl(SwiftClientCfg cfg, String container, String object, String tempKey, int urlExpirationInterval) { int currentTime = (int) (System.currentTimeMillis() / 1000L); int expirationSeconds = currentTime + urlExpirationInterval; try { URL endpoint = new URL(cfg.getEndPoint()); String method = "GET"; String path = String.format("/v1/AUTH_%s/%s/%s", cfg.getAccount(), container, object); //sign the request String hmacBody = String.format("%s\n%d\n%s", method, expirationSeconds, path); String signature = calculateRFC2104HMAC(hmacBody, tempKey); path += String.format("?temp_url_sig=%s&temp_url_expires=%d", signature, expirationSeconds); //generate the temp url URL tempUrl = new URL(endpoint.getProtocol(), endpoint.getHost(), endpoint.getPort(), path); return tempUrl; } catch (Exception e) { logger.error(e.getMessage()); throw new CloudRuntimeException(e.getMessage()); } } static String calculateRFC2104HMAC(String data, String key) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException { SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), HMAC_SHA1_ALGORITHM); Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM); mac.init(signingKey); return toHexString(mac.doFinal(data.getBytes())); } static String toHexString(byte[] bytes) { return Hex.encodeHexString(bytes); } /////////////// SWIFT CMD STRING HELPERS /////////////// protected static String getSwiftCmd(SwiftClientCfg cfg, String swiftCli, String operation) { return String.format(SWIFT_CMD, swiftCli, cfg.getEndPoint(), cfg.getAccount(), cfg.getUserName(), cfg.getKey(), operation); } protected static String getSwiftObjectCmd(SwiftClientCfg cfg, String swiftCliPath, String operation, String container, String objectName) { String cmd = getSwiftCmd(cfg, swiftCliPath, operation) + " " + container + " " + objectName; if (StringUtils.isNotBlank(cfg.getStoragePolicy()) && supportsStoragePolicies(operation)) { return cmd + String.format(WITH_STORAGE_POLICY, cfg.getStoragePolicy()); } return cmd; } private static boolean supportsStoragePolicies(String operation) { for (String supportedOp : OPERATIONS_WITH_STORAGE_POLICIES) { if (supportedOp.equals(operation)) { return true; } } return false; } protected static String getSwiftContainerCmd(SwiftClientCfg cfg, String swiftCliPath, String operation, String container) { return getSwiftCmd(cfg, swiftCliPath, operation) + " " + container; } protected static String getUploadObjectCommand(SwiftClientCfg cfg, String swiftCliPath, String container, String objectName, long size) { String cmd = getSwiftObjectCmd(cfg, swiftCliPath, "upload", container, objectName); if (size > SWIFT_MAX_SIZE) { return cmd + WITH_SEGMENTS; } return cmd; } public static String getContainerName(String type, Long id) { if (type.startsWith("T")) { return "T-" + id; } else if (type.startsWith("S")) { return "S-" + id; } else if (type.startsWith("V")) { return "V-" + id; } return null; } public static String[] splitSwiftPath(String path) { int index = path.indexOf(File.separator); if (index == -1) { return null; } String[] paths = new String[2]; paths[0] = path.substring(0, index); paths[1] = path.substring(index + 1); return paths; } private static String getMeta(Map<String, String> metas) { StringBuilder cms = new StringBuilder(); for (Map.Entry<String, String> entry : metas.entrySet()) { cms.append(" -m "); cms.append(entry.getKey()); cms.append(":"); cms.append(entry.getValue()); cms.append(" "); } return cms.toString(); } }