Skip to content

Commit

Permalink
ceph mon url doesn't support password of @ #119
Browse files Browse the repository at this point in the history
  • Loading branch information
zxwing committed Sep 9, 2015
1 parent d7fc1e1 commit d5959db
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 53 deletions.
Expand Up @@ -7,6 +7,7 @@
import org.zstack.core.errorcode.ErrorFacade;
import org.zstack.header.apimediator.ApiMessageInterceptionException;
import org.zstack.header.apimediator.ApiMessageInterceptor;
import org.zstack.header.errorcode.OperationFailureException;
import org.zstack.header.exception.CloudRuntimeException;
import org.zstack.header.message.APIMessage;
import org.zstack.storage.ceph.backup.APIAddCephBackupStorageMsg;
Expand Down Expand Up @@ -75,61 +76,28 @@ public String call(String url) {
}

private void validate(APIAddMonToCephPrimaryStorageMsg msg) {
msg.setMonUrls(normalizeMonUrls(msg.getMonUrls()));
checkMonUrls(msg.getMonUrls());
}

private void validate(APIAddMonToCephBackupStorageMsg msg) {
msg.setMonUrls(normalizeMonUrls(msg.getMonUrls()));
checkMonUrls(msg.getMonUrls());
}

private List<String> normalizeMonUrls(List<String> monUrls) {
private void checkMonUrls(List<String> monUrls) {
List<String> urls = new ArrayList<String>();
for (String monUrl : monUrls) {
String url = String.format("ssh://%s", monUrl);
try {
URI uri = new URI(url);
String userInfo = uri.getAuthority();
if (userInfo == null || !userInfo.contains(":")) {
throw new ApiMessageInterceptionException(errf.stringToInvalidArgumentError(
String.format("invalid monUrl[%s], the sshUsername:sshPassword part is invalid. A valid monUrl is" +
" in format of %s", monUrl, MON_URL_FORMAT)
));
}
if (uri.getHost() == null) {
throw new ApiMessageInterceptionException(errf.stringToInvalidArgumentError(
String.format("invalid monUrl[%s], hostname cannot be null. A valid monUrl is" +
" in format of %s", monUrl, MON_URL_FORMAT)
));
}

try {
MonUri.checkQuery(uri);
} catch (CloudRuntimeException e) {
throw new ApiMessageInterceptionException(errf.stringToInvalidArgumentError(
String.format("invalid monUrl[%s], %s. A valid monUrl is" +
" in format of %s", monUrl, e.getMessage(), MON_URL_FORMAT)
));
}

int sshPort = uri.getPort();
if (sshPort > 0 && sshPort > 65536) {
throw new ApiMessageInterceptionException(errf.stringToInvalidArgumentError(
String.format("invalid monUrl[%s], the ssh port is greater than 65536. A valid monUrl is" +
" in format of %s", monUrl, MON_URL_FORMAT)
));
}

urls.add(url);
} catch (ApiMessageInterceptionException ae) {
throw ae;
new MonUri(url);
} catch (OperationFailureException ae) {
throw new ApiMessageInterceptionException(ae.getErrorCode());
} catch (Exception e) {
logger.warn(e.getMessage(), e);
throw new ApiMessageInterceptionException(errf.stringToInvalidArgumentError(
String.format("invalid monUrl[%s]. A valid url is in format of %s", monUrl, MON_URL_FORMAT)
));
}
}
return urls;
}

private void validate(APIAddCephPrimaryStorageMsg msg) {
Expand All @@ -149,8 +117,7 @@ private void validate(APIAddCephPrimaryStorageMsg msg) {
));
}

msg.setMonUrls(normalizeMonUrls(msg.getMonUrls()));

checkMonUrls(msg.getMonUrls());
checkExistingPrimaryStorage(msg.getMonUrls());
}

Expand Down Expand Up @@ -180,8 +147,8 @@ private void validate(APIAddCephBackupStorageMsg msg) {
"poolName can be null but cannot be an empty string"
));
}
msg.setMonUrls(normalizeMonUrls(msg.getMonUrls()));

checkMonUrls(msg.getMonUrls());
checkExistingBackupStorage(msg.getMonUrls());
}
}
49 changes: 45 additions & 4 deletions plugin/ceph/src/main/java/org/zstack/storage/ceph/MonUri.java
Expand Up @@ -2,8 +2,12 @@

import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.zstack.core.Platform;
import org.zstack.core.errorcode.ErrorFacade;
import org.zstack.core.keyvalue.Op;
import org.zstack.header.apimediator.ApiMessageInterceptionException;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.errorcode.OperationFailureException;
import org.zstack.header.errorcode.SysErrors;
import org.zstack.header.exception.CloudRuntimeException;

Expand Down Expand Up @@ -41,6 +45,10 @@ public static void checkQuery(URI uri) {
public static String getQueryValue(URI uri, String name) {
List<NameValuePair> params = URLEncodedUtils.parse(uri, "UTF-8");
for (NameValuePair p : params) {
if (!allowedQueryParameter.contains(p.getName())) {
throw new CloudRuntimeException(String.format("unknown parameter[%s]", p.getName()));
}

if (p.getName().equals(name)) {
return p.getValue();
}
Expand All @@ -49,15 +57,48 @@ public static String getQueryValue(URI uri, String name) {
return null;
}

private static final String MON_URL_FORMAT = "sshUsername:sshPassword@hostname:[sshPort]/?[monPort=]";

private ErrorCode errorCode(String err) {
ErrorFacade errf = Platform.getComponentLoader().getComponent(ErrorFacade.class);
return errf.stringToInvalidArgumentError(err);
}

public MonUri(String url) {
try {
URI uri = new URI(url);
hostname = uri.getHost();
String[] ssh = uri.getUserInfo().split(":");
int at = url.lastIndexOf("@");
if (at == -1) {
throw new OperationFailureException(errorCode(String.format("invalid monUrl[%s], the sshUsername:sshPassword part is invalid. A valid monUrl is" +
" in format of %s", url, MON_URL_FORMAT)));
}

String userInfo = url.substring(0, at);
if (!userInfo.contains(":")) {
throw new OperationFailureException(errorCode(String.format("invalid monUrl[%s], the sshUsername:sshPassword part is invalid. A valid monUrl is" +
" in format of %s", url, MON_URL_FORMAT)));
}

String rest = url.substring(at+1, url.length());
String[] ssh = userInfo.split(":");
sshUsername = ssh[0];
sshPassword = ssh[1];
sshPort = uri.getPort() == -1 ? sshPort : uri.getPort();

URI uri = new URI(String.format("ssh://%s", rest));
hostname = uri.getHost();
if (hostname == null) {
throw new OperationFailureException(errorCode(
String.format("invalid monUrl[%s], hostname cannot be null. A valid monUrl is" +
" in format of %s", url, MON_URL_FORMAT)
));
}

sshPort = uri.getPort() == -1 ? sshPort : uri.getPort();
if (sshPort < 1 || sshPort > 65536) {
throw new OperationFailureException(errorCode(
String.format("invalid monUrl[%s], the ssh port is greater than 65536 or lesser than 0. A valid monUrl is" +
" in format of %s", url, MON_URL_FORMAT)
));
}
String v = getQueryValue(uri, CephConstants.MON_PARAM_MON_PORT);
monPort = v == null ? monPort : Integer.valueOf(v);
} catch (URISyntaxException e) {
Expand Down
13 changes: 13 additions & 0 deletions test/src/test/java/org/zstack/test/storage/ceph/TestCeph1.java
Expand Up @@ -6,11 +6,16 @@
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.componentloader.ComponentLoader;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.SimpleQuery;
import org.zstack.header.identity.SessionInventory;
import org.zstack.header.storage.backup.BackupStorage;
import org.zstack.header.storage.backup.BackupStorageInventory;
import org.zstack.header.storage.primary.PrimaryStorageInventory;
import org.zstack.header.vm.VmInstanceInventory;
import org.zstack.simulator.kvm.KVMSimulatorConfig;
import org.zstack.simulator.storage.backup.sftp.SftpBackupStorageSimulatorConfig;
import org.zstack.storage.ceph.backup.CephBackupStorageMonVO;
import org.zstack.storage.ceph.backup.CephBackupStorageMonVO_;
import org.zstack.storage.ceph.primary.CephPrimaryStorageMonVO;
import org.zstack.storage.ceph.primary.CephPrimaryStorageSimulatorConfig;
import org.zstack.storage.ceph.primary.CephPrimaryStorageSimulatorConfig.CephPrimaryStorageConfig;
Expand Down Expand Up @@ -64,6 +69,14 @@ public void setUp() throws Exception {

@Test
public void test() throws ApiSenderException {
BackupStorageInventory bs = deployer.backupStorages.get("ceph-bk");
SimpleQuery<CephBackupStorageMonVO> q = dbf.createQuery(CephBackupStorageMonVO.class);
q.add(CephBackupStorageMonVO_.hostname, SimpleQuery.Op.EQ, "127.0.0.1");
CephBackupStorageMonVO bsmon = q.find();

Assert.assertEquals("root", bsmon.getSshUsername());
Assert.assertEquals("pass@#$word", bsmon.getSshPassword());

Assert.assertFalse(config.createSnapshotCmds.isEmpty());
Assert.assertFalse(config.protectSnapshotCmds.isEmpty());
Assert.assertFalse(config.cloneCmds.isEmpty());
Expand Down
2 changes: 1 addition & 1 deletion test/src/test/resources/deployerXml/ceph/TestCeph1.xml
Expand Up @@ -4,7 +4,7 @@

<backupStorages>
<cephBackupStorage name="ceph-bk" description="Test"
url="/path1" fsid="7ff218d9-f525-435f-8a40-3618d1772a64" monUrl="root:password@localhost,root:password@127.0.0.1"
url="/path1" fsid="7ff218d9-f525-435f-8a40-3618d1772a64" monUrl="root:password@localhost,root:pass@#$word@127.0.0.1"
totalCapacity="1T" availableCapacity="500G"/>
</backupStorages>

Expand Down
17 changes: 11 additions & 6 deletions utils/src/test/java/com/zstack/utils/test/TestURI.java
Expand Up @@ -2,16 +2,21 @@

import org.junit.Test;

import java.net.URI;
import java.net.URISyntaxException;
import java.io.UnsupportedEncodingException;
import java.net.*;

public class TestURI {

@Test
public void test() throws URISyntaxException {
URI u1 = new URI("ssh://root:zstackqwe:!@#@172.16.36.184/");
System.out.println(u1.getAuthority());
System.out.println(u1.getHost());
public void test() throws URISyntaxException, UnsupportedEncodingException, MalformedURLException {
String password = "zstackqwe:!@#";
String url = String.format("root:%s@172.16.36.184/", password);
int at = url.lastIndexOf("@");
String userinfo = url.substring(0, at);
System.out.println(userinfo);
String rest = url.substring(at+1, url.length());
System.out.println(rest);
System.out.println(userinfo.split(":")[0]);
}

}

0 comments on commit d5959db

Please sign in to comment.