HDFS-11162. Block Storage: add command line tool. Contributed by Chen Liang.
This commit is contained in:
parent
85c2312e7d
commit
1e892f5748
|
@ -25,13 +25,19 @@ public final class CBlockConfigKeys {
|
|||
"dfs.cblock.enabled";
|
||||
public static final String DFS_CBLOCK_SERVICERPC_ADDRESS_KEY =
|
||||
"dfs.cblock.servicerpc-address";
|
||||
public static final int DFS_CBLOCK_RPCSERVICE_PORT_DEFAULT =
|
||||
public static final String DFS_CBLOCK_SERVICERPC_PORT_KEY =
|
||||
"dfs.cblock.servicerpc.port";
|
||||
public static final int DFS_CBLOCK_SERVICERPC_PORT_DEFAULT =
|
||||
9810;
|
||||
public static final String DFS_CBLOCK_SERVICERPC_HOSTNAME_KEY =
|
||||
"dfs.cblock.servicerpc.hostname";
|
||||
public static final String DFS_CBLOCK_SERVICERPC_HOSTNAME_DEFAULT =
|
||||
"0.0.0.0";
|
||||
public static final String DFS_CBLOCK_RPCSERVICE_IP_DEFAULT =
|
||||
"0.0.0.0";
|
||||
public static final String DFS_CBLOCK_SERVICERPC_ADDRESS_DEFAULT =
|
||||
DFS_CBLOCK_RPCSERVICE_IP_DEFAULT
|
||||
+ ":" + DFS_CBLOCK_RPCSERVICE_PORT_DEFAULT;
|
||||
DFS_CBLOCK_SERVICERPC_HOSTNAME_DEFAULT
|
||||
+ ":" + DFS_CBLOCK_SERVICERPC_PORT_DEFAULT;
|
||||
|
||||
public static final String DFS_CBLOCK_JSCSIRPC_ADDRESS_KEY =
|
||||
"dfs.cblock.jscsi-address";
|
||||
|
|
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.hadoop.cblock.cli;
|
||||
|
||||
import org.apache.commons.cli.BasicParser;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.HelpFormatter;
|
||||
import org.apache.commons.cli.Option;
|
||||
import org.apache.commons.cli.OptionBuilder;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.hadoop.cblock.client.CBlockVolumeClient;
|
||||
import org.apache.hadoop.cblock.meta.VolumeInfo;
|
||||
import org.apache.hadoop.cblock.protocolPB.CBlockServiceProtocolPB;
|
||||
import org.apache.hadoop.conf.Configured;
|
||||
import org.apache.hadoop.ipc.ProtobufRpcEngine;
|
||||
import org.apache.hadoop.ipc.RPC;
|
||||
import org.apache.hadoop.ozone.OzoneConfiguration;
|
||||
import org.apache.hadoop.util.Tool;
|
||||
import org.apache.hadoop.util.ToolRunner;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* The command line tool class.
|
||||
*/
|
||||
public class CBlockCli extends Configured implements Tool {
|
||||
|
||||
private static final String CREATE_VOLUME = "createVolume";
|
||||
|
||||
private static final String DELETE_VOLUME = "deleteVolume";
|
||||
|
||||
private static final String INFO_VOLUME = "infoVolume";
|
||||
|
||||
private static final String LIST_VOLUME = "listVolume";
|
||||
|
||||
private static final String SERVER_ADDR = "serverAddr";
|
||||
|
||||
private static final String HELP = "help";
|
||||
|
||||
private static final Logger LOG =
|
||||
LoggerFactory.getLogger(CBlockCli.class);
|
||||
private OzoneConfiguration conf;
|
||||
|
||||
private PrintStream printStream;
|
||||
|
||||
private Options options;
|
||||
|
||||
private BasicParser parser;
|
||||
|
||||
private CBlockVolumeClient localProxy;
|
||||
|
||||
public CBlockCli(OzoneConfiguration conf, PrintStream printStream)
|
||||
throws IOException {
|
||||
this.printStream = printStream;
|
||||
this.conf = conf;
|
||||
this.options = getOptions();
|
||||
this.parser = new BasicParser();
|
||||
}
|
||||
|
||||
public CBlockCli(OzoneConfiguration conf) throws IOException{
|
||||
this(conf, System.out);
|
||||
}
|
||||
|
||||
private CommandLine parseArgs(String[] argv)
|
||||
throws ParseException {
|
||||
return parser.parse(options, argv);
|
||||
}
|
||||
|
||||
private static Options getOptions() {
|
||||
Options options = new Options();
|
||||
Option serverAddress = OptionBuilder
|
||||
.withArgName("serverAddress>:<serverPort")
|
||||
.withLongOpt(SERVER_ADDR)
|
||||
.withValueSeparator(':')
|
||||
.hasArgs(2)
|
||||
.withDescription("specify server address:port")
|
||||
.create("s");
|
||||
options.addOption(serverAddress);
|
||||
|
||||
// taking 4 args: userName, volumeName, volumeSize, blockSize
|
||||
Option createVolume = OptionBuilder
|
||||
.withArgName("user> <volume> <volumeSize in [GB/TB]> <blockSize")
|
||||
.withLongOpt(CREATE_VOLUME)
|
||||
.withValueSeparator(' ')
|
||||
.hasArgs(4)
|
||||
.withDescription("create a fresh new volume")
|
||||
.create("c");
|
||||
options.addOption(createVolume);
|
||||
|
||||
// taking 2 args: userName, volumeName
|
||||
Option deleteVolume = OptionBuilder
|
||||
.withArgName("user> <volume")
|
||||
.withLongOpt(DELETE_VOLUME)
|
||||
.hasArgs(2)
|
||||
.withDescription("delete a volume")
|
||||
.create("d");
|
||||
options.addOption(deleteVolume);
|
||||
|
||||
// taking 2 args: userName, volumeName
|
||||
Option infoVolume = OptionBuilder
|
||||
.withArgName("user> <volume")
|
||||
.withLongOpt(INFO_VOLUME)
|
||||
.hasArgs(2)
|
||||
.withDescription("info a volume")
|
||||
.create("i");
|
||||
options.addOption(infoVolume);
|
||||
|
||||
// taking 1 arg: userName
|
||||
Option listVolume = OptionBuilder
|
||||
.withArgName("user")
|
||||
.withLongOpt(LIST_VOLUME)
|
||||
.hasOptionalArgs(1)
|
||||
.withDescription("list all volumes")
|
||||
.create("l");
|
||||
options.addOption(listVolume);
|
||||
|
||||
Option help = OptionBuilder
|
||||
.withLongOpt(HELP)
|
||||
.withDescription("help")
|
||||
.create("h");
|
||||
options.addOption(help);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int run(String[] args) throws ParseException, IOException {
|
||||
CommandLine commandLine = parseArgs(args);
|
||||
if (commandLine.hasOption("s")) {
|
||||
String[] serverAddrArgs = commandLine.getOptionValues("s");
|
||||
LOG.info("server address" + Arrays.toString(serverAddrArgs));
|
||||
String serverHost = serverAddrArgs[0];
|
||||
int serverPort = Integer.parseInt(serverAddrArgs[1]);
|
||||
InetSocketAddress serverAddress =
|
||||
new InetSocketAddress(serverHost, serverPort);
|
||||
this.localProxy = new CBlockVolumeClient(conf, serverAddress);
|
||||
} else {
|
||||
this.localProxy = new CBlockVolumeClient(conf);
|
||||
}
|
||||
|
||||
if (commandLine.hasOption("h")) {
|
||||
LOG.info("help");
|
||||
help();
|
||||
}
|
||||
|
||||
if (commandLine.hasOption("c")) {
|
||||
String[] createArgs = commandLine.getOptionValues("c");
|
||||
LOG.info("create volume:" + Arrays.toString(createArgs));
|
||||
createVolume(createArgs);
|
||||
}
|
||||
|
||||
if (commandLine.hasOption("d")) {
|
||||
String[] deleteArgs = commandLine.getOptionValues("d");
|
||||
LOG.info("delete args:" + Arrays.toString(deleteArgs));
|
||||
deleteVolume(deleteArgs);
|
||||
}
|
||||
|
||||
if (commandLine.hasOption("l")) {
|
||||
String[] listArg = commandLine.getOptionValues("l");
|
||||
LOG.info("list args:" + Arrays.toString(listArg));
|
||||
listVolume(listArg);
|
||||
}
|
||||
|
||||
if (commandLine.hasOption("i")) {
|
||||
String[] infoArgs = commandLine.getOptionValues("i");
|
||||
LOG.info("info args:" + Arrays.toString(infoArgs));
|
||||
infoVolume(infoArgs);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void main(String[] argv) throws Exception {
|
||||
OzoneConfiguration cblockConf = new OzoneConfiguration();
|
||||
RPC.setProtocolEngine(cblockConf, CBlockServiceProtocolPB.class,
|
||||
ProtobufRpcEngine.class);
|
||||
int res = 0;
|
||||
Tool shell = new CBlockCli(cblockConf, System.out);
|
||||
try {
|
||||
ToolRunner.run(shell, argv);
|
||||
} catch (Exception ex) {
|
||||
LOG.error(ex.toString());
|
||||
res = 1;
|
||||
}
|
||||
System.exit(res);
|
||||
}
|
||||
|
||||
private long parseSize(String volumeSizeArgs) throws IOException {
|
||||
long multiplier = 1;
|
||||
|
||||
Pattern p = Pattern.compile("([0-9]+)([a-zA-Z]+)");
|
||||
Matcher m = p.matcher(volumeSizeArgs);
|
||||
|
||||
if (!m.find()) {
|
||||
throw new IOException("Invalid volume size args " + volumeSizeArgs);
|
||||
}
|
||||
|
||||
int size = Integer.parseInt(m.group(1));
|
||||
String s = m.group(2);
|
||||
|
||||
if (s.equalsIgnoreCase("GB")) {
|
||||
multiplier = 1024L * 1024 * 1024;
|
||||
} else if (s.equalsIgnoreCase("TB")) {
|
||||
multiplier = 1024L * 1024 * 1024 * 1024;
|
||||
} else {
|
||||
throw new IOException("Invalid volume size args " + volumeSizeArgs);
|
||||
}
|
||||
return size * multiplier;
|
||||
}
|
||||
|
||||
private void createVolume(String[] createArgs) throws IOException {
|
||||
String userName = createArgs[0];
|
||||
String volumeName = createArgs[1];
|
||||
long volumeSize = parseSize(createArgs[2]);
|
||||
int blockSize = Integer.parseInt(createArgs[3])*1024;
|
||||
localProxy.createVolume(userName, volumeName, volumeSize, blockSize);
|
||||
}
|
||||
|
||||
private void deleteVolume(String[] deleteArgs) throws IOException {
|
||||
String userName = deleteArgs[0];
|
||||
String volumeName = deleteArgs[1];
|
||||
boolean force = false;
|
||||
if (deleteArgs.length > 2) {
|
||||
force = Boolean.parseBoolean(deleteArgs[2]);
|
||||
}
|
||||
localProxy.deleteVolume(userName, volumeName, force);
|
||||
}
|
||||
|
||||
private void infoVolume(String[] infoArgs) throws IOException {
|
||||
String userName = infoArgs[0];
|
||||
String volumeName = infoArgs[1];
|
||||
VolumeInfo volumeInfo = localProxy.infoVolume(userName, volumeName);
|
||||
printStream.println(volumeInfo.toString());
|
||||
}
|
||||
|
||||
private void listVolume(String[] listArgs) throws IOException {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
List<VolumeInfo> volumeResponse;
|
||||
if (listArgs == null) {
|
||||
volumeResponse = localProxy.listVolume(null);
|
||||
} else {
|
||||
volumeResponse = localProxy.listVolume(listArgs[0]);
|
||||
}
|
||||
for (int i = 0; i<volumeResponse.size(); i++) {
|
||||
stringBuilder.append(
|
||||
String.format("%s:%s\t%d\t%d", volumeResponse.get(i).getUserName(),
|
||||
volumeResponse.get(i).getVolumeName(),
|
||||
volumeResponse.get(i).getVolumeSize(),
|
||||
volumeResponse.get(i).getBlockSize()));
|
||||
if (i < volumeResponse.size() - 1) {
|
||||
stringBuilder.append("\n");
|
||||
}
|
||||
}
|
||||
printStream.println(stringBuilder);
|
||||
}
|
||||
|
||||
private void help() {
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
formatter.printHelp(100, "cblock", "", options, "");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.hadoop.cblock.cli;
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.hadoop.cblock.client;
|
||||
|
||||
import com.google.protobuf.ServiceException;
|
||||
import org.apache.hadoop.cblock.meta.VolumeInfo;
|
||||
import org.apache.hadoop.cblock.proto.CBlockServiceProtocol;
|
||||
import org.apache.hadoop.cblock.protocol.proto.CBlockServiceProtocolProtos;
|
||||
import org.apache.hadoop.cblock.protocolPB.CBlockServiceProtocolPB;
|
||||
import org.apache.hadoop.classification.InterfaceAudience;
|
||||
import org.apache.hadoop.ipc.ProtobufHelper;
|
||||
import org.apache.hadoop.ipc.ProtocolTranslator;
|
||||
import org.apache.hadoop.ipc.RPC;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The client side implement of CBlockServiceProtocol.
|
||||
*/
|
||||
@InterfaceAudience.Private
|
||||
public final class CBlockServiceProtocolClientSideTranslatorPB
|
||||
implements CBlockServiceProtocol, ProtocolTranslator, Closeable {
|
||||
|
||||
private final CBlockServiceProtocolPB rpcProxy;
|
||||
|
||||
public CBlockServiceProtocolClientSideTranslatorPB(
|
||||
CBlockServiceProtocolPB rpcProxy) {
|
||||
this.rpcProxy = rpcProxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
RPC.stopProxy(rpcProxy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createVolume(String userName, String volumeName,
|
||||
long volumeSize, int blockSize) throws IOException {
|
||||
CBlockServiceProtocolProtos.CreateVolumeRequestProto.Builder req =
|
||||
CBlockServiceProtocolProtos.CreateVolumeRequestProto.newBuilder();
|
||||
req.setUserName(userName);
|
||||
req.setVolumeName(volumeName);
|
||||
req.setVolumeSize(volumeSize);
|
||||
req.setBlockSize(blockSize);
|
||||
try {
|
||||
rpcProxy.createVolume(null, req.build());
|
||||
} catch (ServiceException e) {
|
||||
throw ProtobufHelper.getRemoteException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteVolume(String userName, String volumeName, boolean force)
|
||||
throws IOException {
|
||||
CBlockServiceProtocolProtos.DeleteVolumeRequestProto.Builder req =
|
||||
CBlockServiceProtocolProtos.DeleteVolumeRequestProto.newBuilder();
|
||||
req.setUserName(userName);
|
||||
req.setVolumeName(volumeName);
|
||||
req.setForce(force);
|
||||
try {
|
||||
rpcProxy.deleteVolume(null, req.build());
|
||||
} catch (ServiceException e) {
|
||||
throw ProtobufHelper.getRemoteException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getUnderlyingProxyObject() {
|
||||
return rpcProxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VolumeInfo infoVolume(String userName, String volumeName)
|
||||
throws IOException {
|
||||
CBlockServiceProtocolProtos.InfoVolumeRequestProto.Builder req =
|
||||
CBlockServiceProtocolProtos.InfoVolumeRequestProto.newBuilder();
|
||||
req.setUserName(userName);
|
||||
req.setVolumeName(volumeName);
|
||||
try {
|
||||
CBlockServiceProtocolProtos.InfoVolumeResponseProto resp =
|
||||
rpcProxy.infoVolume(null, req.build());
|
||||
return new VolumeInfo(resp.getVolumeInfo().getUserName(),
|
||||
resp.getVolumeInfo().getVolumeName(),
|
||||
resp.getVolumeInfo().getVolumeSize(),
|
||||
resp.getVolumeInfo().getBlockSize(),
|
||||
resp.getVolumeInfo().getUsage());
|
||||
} catch (ServiceException e) {
|
||||
throw ProtobufHelper.getRemoteException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VolumeInfo> listVolume(String userName) throws IOException {
|
||||
CBlockServiceProtocolProtos.ListVolumeRequestProto.Builder req =
|
||||
CBlockServiceProtocolProtos.ListVolumeRequestProto.newBuilder();
|
||||
if (userName != null) {
|
||||
req.setUserName(userName);
|
||||
}
|
||||
try {
|
||||
CBlockServiceProtocolProtos.ListVolumeResponseProto resp =
|
||||
rpcProxy.listVolume(null, req.build());
|
||||
List<VolumeInfo> respList = new ArrayList<>();
|
||||
for (CBlockServiceProtocolProtos.VolumeInfoProto entry :
|
||||
resp.getVolumeEntryList()) {
|
||||
VolumeInfo volumeInfo = new VolumeInfo(
|
||||
entry.getUserName(), entry.getVolumeName(), entry.getVolumeSize(),
|
||||
entry.getBlockSize());
|
||||
respList.add(volumeInfo);
|
||||
}
|
||||
return respList;
|
||||
} catch (ServiceException e) {
|
||||
throw ProtobufHelper.getRemoteException(e);
|
||||
} catch (Exception e) {
|
||||
throw new IOException("got" + e.getCause() + " " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.hadoop.cblock.client;
|
||||
|
||||
import org.apache.hadoop.cblock.meta.VolumeInfo;
|
||||
import org.apache.hadoop.cblock.protocolPB.CBlockServiceProtocolPB;
|
||||
import org.apache.hadoop.io.retry.RetryPolicies;
|
||||
import org.apache.hadoop.ipc.RPC;
|
||||
import org.apache.hadoop.net.NetUtils;
|
||||
import org.apache.hadoop.ozone.OzoneConfiguration;
|
||||
import org.apache.hadoop.security.UserGroupInformation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.apache.hadoop.cblock.CBlockConfigKeys.DFS_CBLOCK_SERVICERPC_HOSTNAME_DEFAULT;
|
||||
import static org.apache.hadoop.cblock.CBlockConfigKeys.DFS_CBLOCK_SERVICERPC_HOSTNAME_KEY;
|
||||
import static org.apache.hadoop.cblock.CBlockConfigKeys.DFS_CBLOCK_SERVICERPC_PORT_DEFAULT;
|
||||
import static org.apache.hadoop.cblock.CBlockConfigKeys.DFS_CBLOCK_SERVICERPC_PORT_KEY;
|
||||
|
||||
/**
|
||||
* Implementation of client used by CBlock command line tool.
|
||||
*/
|
||||
public class CBlockVolumeClient {
|
||||
private final CBlockServiceProtocolClientSideTranslatorPB cblockClient;
|
||||
private final OzoneConfiguration conf;
|
||||
|
||||
public CBlockVolumeClient(OzoneConfiguration conf) throws IOException {
|
||||
this.conf = conf;
|
||||
long version = RPC.getProtocolVersion(CBlockServiceProtocolPB.class);
|
||||
String serverAddress = conf.get(DFS_CBLOCK_SERVICERPC_HOSTNAME_KEY,
|
||||
DFS_CBLOCK_SERVICERPC_HOSTNAME_DEFAULT);
|
||||
int serverPort = conf.getInt(DFS_CBLOCK_SERVICERPC_PORT_KEY,
|
||||
DFS_CBLOCK_SERVICERPC_PORT_DEFAULT);
|
||||
InetSocketAddress address = new InetSocketAddress(
|
||||
serverAddress, serverPort);
|
||||
// currently the largest supported volume is about 8TB, which might take
|
||||
// > 20 seconds to finish creating containers. thus set timeout to 30 sec.
|
||||
cblockClient = new CBlockServiceProtocolClientSideTranslatorPB(
|
||||
RPC.getProtocolProxy(CBlockServiceProtocolPB.class, version,
|
||||
address, UserGroupInformation.getCurrentUser(), conf,
|
||||
NetUtils.getDefaultSocketFactory(conf), 30000, RetryPolicies
|
||||
.retryUpToMaximumCountWithFixedSleep(300, 1, TimeUnit
|
||||
.SECONDS)).getProxy());
|
||||
}
|
||||
|
||||
public CBlockVolumeClient(OzoneConfiguration conf,
|
||||
InetSocketAddress serverAddress) throws IOException {
|
||||
this.conf = conf;
|
||||
long version = RPC.getProtocolVersion(CBlockServiceProtocolPB.class);
|
||||
cblockClient = new CBlockServiceProtocolClientSideTranslatorPB(
|
||||
RPC.getProtocolProxy(CBlockServiceProtocolPB.class, version,
|
||||
serverAddress, UserGroupInformation.getCurrentUser(), conf,
|
||||
NetUtils.getDefaultSocketFactory(conf), 30000, RetryPolicies
|
||||
.retryUpToMaximumCountWithFixedSleep(300, 1, TimeUnit
|
||||
.SECONDS)).getProxy());
|
||||
}
|
||||
|
||||
public void createVolume(String userName, String volumeName,
|
||||
long volumeSize, int blockSize) throws IOException {
|
||||
cblockClient.createVolume(userName, volumeName,
|
||||
volumeSize, blockSize);
|
||||
}
|
||||
|
||||
public void deleteVolume(String userName, String volumeName, boolean force)
|
||||
throws IOException {
|
||||
cblockClient.deleteVolume(userName, volumeName, force);
|
||||
}
|
||||
|
||||
public VolumeInfo infoVolume(String userName, String volumeName)
|
||||
throws IOException {
|
||||
return cblockClient.infoVolume(userName, volumeName);
|
||||
}
|
||||
|
||||
public List<VolumeInfo> listVolume(String userName)
|
||||
throws IOException {
|
||||
return cblockClient.listVolume(userName);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.hadoop.cblock.client;
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.hadoop.cblock;
|
||||
|
||||
import org.apache.hadoop.cblock.cli.CBlockCli;
|
||||
import org.apache.hadoop.cblock.meta.VolumeDescriptor;
|
||||
import org.apache.hadoop.cblock.util.MockStorageClient;
|
||||
import org.apache.hadoop.ozone.OzoneConfiguration;
|
||||
import org.apache.hadoop.scm.client.ScmClient;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.hadoop.cblock.CBlockConfigKeys.DFS_CBLOCK_SERVICE_LEVELDB_PATH_KEY;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* A testing class for cblock command line tool.
|
||||
*/
|
||||
public class TestCBlockCLI {
|
||||
private static final long GB = 1 * 1024 * 1024 * 1024L;
|
||||
private static final int KB = 1024;
|
||||
private static CBlockCli cmd;
|
||||
private static OzoneConfiguration conf;
|
||||
private static CBlockManager cBlockManager;
|
||||
private static ByteArrayOutputStream outContent;
|
||||
private static PrintStream testPrintOut;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() throws IOException {
|
||||
outContent = new ByteArrayOutputStream();
|
||||
ScmClient storageClient = new MockStorageClient();
|
||||
conf = new OzoneConfiguration();
|
||||
conf.set(DFS_CBLOCK_SERVICE_LEVELDB_PATH_KEY, "/tmp/testCblockCli.dat");
|
||||
cBlockManager = new CBlockManager(conf, storageClient);
|
||||
cBlockManager.start();
|
||||
testPrintOut = new PrintStream(outContent);
|
||||
cmd = new CBlockCli(conf, testPrintOut);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void clean() {
|
||||
cBlockManager.stop();
|
||||
cBlockManager.join();
|
||||
cBlockManager.clean();
|
||||
}
|
||||
|
||||
@After
|
||||
public void reset() {
|
||||
outContent.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the help command.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testCliHelp() throws Exception {
|
||||
PrintStream initialStdOut = System.out;
|
||||
System.setOut(testPrintOut);
|
||||
String[] args = {"-h"};
|
||||
cmd.run(args);
|
||||
String helpPrints =
|
||||
"usage: cblock\n" +
|
||||
" -c,--createVolume <user> <volume> <volumeSize in [GB/TB]> " +
|
||||
"<blockSize> create a fresh new volume\n" +
|
||||
" -d,--deleteVolume <user> <volume> " +
|
||||
" delete a volume\n" +
|
||||
" -h,--help " +
|
||||
" help\n" +
|
||||
" -i,--infoVolume <user> <volume> " +
|
||||
" info a volume\n" +
|
||||
" -l,--listVolume <user> " +
|
||||
" list all volumes\n" +
|
||||
" -s,--serverAddr <serverAddress>:<serverPort> " +
|
||||
" specify server address:port\n";
|
||||
assertEquals(helpPrints, outContent.toString());
|
||||
outContent.reset();
|
||||
System.setOut(initialStdOut);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test volume listing command.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testCliList() throws Exception {
|
||||
String userName0 = "userTestCliList0";
|
||||
String userName1 = "userTestCliList1";
|
||||
String userTestNotExist = "userTestNotExist";
|
||||
String volumeName0 = "volumeTest0";
|
||||
String volumeName1 = "volumeTest1";
|
||||
String volumeSize0 = "30GB";
|
||||
String volumeSize1 = "40GB";
|
||||
String blockSize = Integer.toString(4);
|
||||
String[] argsCreate0 =
|
||||
{"-c", userName0, volumeName0, volumeSize0, blockSize};
|
||||
cmd.run(argsCreate0);
|
||||
String[] argsCreate1 =
|
||||
{"-c", userName0, volumeName1, volumeSize1, blockSize};
|
||||
cmd.run(argsCreate1);
|
||||
String[] argsCreate2 =
|
||||
{"-c", userName1, volumeName0, volumeSize0, blockSize};
|
||||
cmd.run(argsCreate2);
|
||||
String[] argsList0 = {"-l"};
|
||||
cmd.run(argsList0);
|
||||
String[] outExpected1 = {
|
||||
"userTestCliList1:volumeTest0\t32212254720\t4096\n",
|
||||
"userTestCliList0:volumeTest0\t32212254720\t4096\n",
|
||||
"userTestCliList0:volumeTest1\t42949672960\t4096\n"};
|
||||
int length = 0;
|
||||
for (String str : outExpected1) {
|
||||
assertTrue(outContent.toString().contains(str));
|
||||
length += str.length();
|
||||
}
|
||||
assertEquals(length, outContent.toString().length());
|
||||
outContent.reset();
|
||||
|
||||
String[] argsList1 = {"-l", userName1};
|
||||
cmd.run(argsList1);
|
||||
String outExpected2 = "userTestCliList1:volumeTest0\t32212254720\t4096\n";
|
||||
assertEquals(outExpected2, outContent.toString());
|
||||
outContent.reset();
|
||||
|
||||
String[] argsList2 = {"-l", userTestNotExist};
|
||||
cmd.run(argsList2);
|
||||
String outExpected3 = "\n";
|
||||
assertEquals(outExpected3, outContent.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test create volume command.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testCliCreate() throws Exception {
|
||||
String userName = "userTestCliCreate";
|
||||
String volumeName = "volumeTest";
|
||||
String volumeSize = "30GB";
|
||||
String blockSize = "4";
|
||||
String[] argsCreate = {"-c", userName, volumeName, volumeSize, blockSize};
|
||||
cmd.run(argsCreate);
|
||||
List<VolumeDescriptor> allVolumes = cBlockManager.getAllVolumes(userName);
|
||||
assertEquals(1, allVolumes.size());
|
||||
VolumeDescriptor volume = allVolumes.get(0);
|
||||
assertEquals(userName, volume.getUserName());
|
||||
assertEquals(volumeName, volume.getVolumeName());
|
||||
long volumeSizeB = volume.getVolumeSize();
|
||||
assertEquals(30, (int)(volumeSizeB/ GB));
|
||||
assertEquals(4, volume.getBlockSize()/ KB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test delete volume command.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testCliDelete() throws Exception {
|
||||
String userName = "userTestCliDelete";
|
||||
String volumeName = "volumeTest";
|
||||
String volumeSize = "30GB";
|
||||
String blockSize = "4";
|
||||
String[] argsCreate = {"-c", userName, volumeName, volumeSize, blockSize};
|
||||
cmd.run(argsCreate);
|
||||
List<VolumeDescriptor> allVolumes = cBlockManager.getAllVolumes(userName);
|
||||
assertEquals(1, allVolumes.size());
|
||||
VolumeDescriptor volume = allVolumes.get(0);
|
||||
assertEquals(userName, volume.getUserName());
|
||||
assertEquals(volumeName, volume.getVolumeName());
|
||||
long volumeSizeB = volume.getVolumeSize();
|
||||
assertEquals(30, (int)(volumeSizeB/ GB));
|
||||
assertEquals(4, volume.getBlockSize()/ KB);
|
||||
|
||||
String[] argsDelete = {"-d", userName, volumeName};
|
||||
cmd.run(argsDelete);
|
||||
allVolumes = cBlockManager.getAllVolumes(userName);
|
||||
assertEquals(0, allVolumes.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test info volume command.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testCliInfoVolume() throws Exception {
|
||||
String userName0 = "userTestCliInfo";
|
||||
String volumeName0 = "volumeTest0";
|
||||
String volumeSize = "8000GB";
|
||||
String blockSize = "4";
|
||||
String[] argsCreate0 = {
|
||||
"-c", userName0, volumeName0, volumeSize, blockSize};
|
||||
cmd.run(argsCreate0);
|
||||
String[] argsInfo = {"-i", userName0, volumeName0};
|
||||
cmd.run(argsInfo);
|
||||
// TODO : the usage field is not implemented yet, always 0 now.
|
||||
String outExpected = " userName:userTestCliInfo " +
|
||||
"volumeName:volumeTest0 " +
|
||||
"volumeSize:8589934592000 " +
|
||||
"blockSize:4096 (sizeInBlocks:2097152000) usageInBlocks:0\n";
|
||||
assertEquals(outExpected, outContent.toString());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue