Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import com.cloud.resource.CommandWrapper;
import com.cloud.resource.ResourceWrapper;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.utils.RbdUtils;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.script.Script;

Expand Down Expand Up @@ -98,7 +99,7 @@ public Answer execute(final BackupSnapshotCommand command, final LibvirtComputin
if (primaryPool.getType() == StoragePoolType.RBD) {
try {
final Rados r = new Rados(primaryPool.getAuthUserName());
r.confSet("mon_host", primaryPool.getSourceHost() + ":" + primaryPool.getSourcePort());
r.confSet("mon_host", RbdUtils.getRbdMonitors(primaryPool.getSourceHost(), primaryPool.getSourcePort()));
r.confSet("key", primaryPool.getAuthSecret());
r.confSet("client_mount_timeout", "30");
r.connect();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import com.cloud.resource.CommandWrapper;
import com.cloud.resource.ResourceWrapper;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.utils.RbdUtils;
import com.cloud.utils.script.Script;

@ResourceWrapper(handles = ManageSnapshotCommand.class)
Expand Down Expand Up @@ -115,7 +116,7 @@ public Answer execute(final ManageSnapshotCommand command, final LibvirtComputin
if (primaryPool.getType() == StoragePoolType.RBD) {
try {
final Rados r = new Rados(primaryPool.getAuthUserName());
r.confSet("mon_host", primaryPool.getSourceHost() + ":" + primaryPool.getSourcePort());
r.confSet("mon_host", RbdUtils.getRbdMonitors(primaryPool.getSourceHost(), primaryPool.getSourcePort()));
r.confSet("key", primaryPool.getAuthSecret());
r.confSet("client_mount_timeout", "30");
r.connect();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import com.cloud.resource.ResourceWrapper;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.utils.RbdUtils;
import com.cloud.utils.Pair;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.script.Script;
Expand Down Expand Up @@ -96,7 +97,7 @@ public Answer execute(final RevertSnapshotCommand command, final LibvirtComputin

if (primaryPool.getType() == StoragePoolType.RBD) {
Rados rados = new Rados(primaryPool.getAuthUserName());
rados.confSet(MON_HOST, primaryPool.getSourceHost() + ":" + primaryPool.getSourcePort());
rados.confSet(MON_HOST, RbdUtils.getRbdMonitors(primaryPool.getSourceHost(), primaryPool.getSourcePort()));
rados.confSet(KEY, primaryPool.getAuthSecret());
rados.confSet(CLIENT_MOUNT_TIMEOUT, RADOS_CONNECTION_TIMEOUT);
rados.connect();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
// under the License.
package com.cloud.hypervisor.kvm.storage;

import com.cloud.utils.RbdUtils;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.storage.formatinspector.Qcow2Inspector;
import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
Expand All @@ -25,11 +26,8 @@
import org.apache.cloudstack.utils.qemu.QemuImgFile;
import org.apache.cloudstack.utils.qemu.QemuObject;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.apache.commons.lang3.StringUtils;
import org.libvirt.LibvirtException;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class KVMPhysicalDisk {
Expand All @@ -51,7 +49,7 @@ public static String RBDStringBuilder(KVMStoragePool storagePool, String image)
String dataPool = (details == null) ? null : details.get(RBD_DEFAULT_DATA_POOL);

String rbdOpts = "rbd:" + image;
rbdOpts += ":mon_host=" + composeOptionForMonHosts(monHost, monPort);
rbdOpts += ":mon_host=" + RbdUtils.composeOptionForMonHosts(monHost, monPort);

if (authUserName == null) {
rbdOpts += ":auth_client_required=none";
Expand All @@ -71,25 +69,6 @@ public static String RBDStringBuilder(KVMStoragePool storagePool, String image)
return rbdOpts;
}

private static String composeOptionForMonHosts(String monHost, int monPort) {
List<String> hosts = new ArrayList<>();
for (String host : monHost.split(",")) {
if (monPort > 0) {
hosts.add(replaceHostAddress(host) + "\\:" + monPort);
} else {
hosts.add(replaceHostAddress(host));
}
}
return StringUtils.join(hosts, "\\;");
}

private static String replaceHostAddress(String hostIp) {
if (hostIp != null && hostIp.startsWith("[") && hostIp.endsWith("]")) {
return hostIp.replaceAll("\\:", "\\\\:");
}
return hostIp;
}

public static long getVirtualSizeFromFile(String path) {
try {
QemuImg qemu = new QemuImg(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@
import com.cloud.storage.template.QCOW2Processor;
import com.cloud.storage.template.TemplateConstants;
import com.cloud.storage.template.TemplateLocation;
import com.cloud.utils.RbdUtils;
import com.cloud.utils.Pair;
import com.cloud.utils.UriUtils;
import com.cloud.utils.exception.CloudRuntimeException;
Expand Down Expand Up @@ -2911,7 +2912,7 @@ protected boolean isAvailablePoolSizeDividedByDiskSizeLesserThanMinRate(long ava

protected Rados radosConnect(final KVMStoragePool primaryPool) throws RadosException {
Rados r = new Rados(primaryPool.getAuthUserName());
r.confSet(CEPH_MON_HOST, primaryPool.getSourceHost() + ":" + primaryPool.getSourcePort());
r.confSet(CEPH_MON_HOST, RbdUtils.getRbdMonitors(primaryPool.getSourceHost(), primaryPool.getSourcePort()));
r.confSet(CEPH_AUTH_KEY, primaryPool.getAuthSecret());
r.confSet(CEPH_CLIENT_MOUNT_TIMEOUT, CEPH_DEFAULT_MOUNT_TIMEOUT);
r.connect();
Expand Down Expand Up @@ -3128,7 +3129,7 @@ private KVMPhysicalDisk createRBDvolumeFromRBDSnapshot(KVMPhysicalDisk volume, S
try {

r = new Rados(srcPool.getAuthUserName());
r.confSet("mon_host", srcPool.getSourceHost() + ":" + srcPool.getSourcePort());
r.confSet("mon_host", RbdUtils.getRbdMonitors(srcPool.getSourceHost(), srcPool.getSourcePort()));
r.confSet("key", srcPool.getAuthSecret());
r.confSet("client_mount_timeout", "30");
r.connect();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
import com.cloud.storage.Storage;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.StorageLayer;
import com.cloud.utils.RbdUtils;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.script.Script;
import com.cloud.utils.storage.TemplateDownloaderUtil;
Expand Down Expand Up @@ -1353,7 +1354,7 @@ private KVMPhysicalDisk createDiskFromTemplateOnRBD(KVMPhysicalDisk template,
logger.debug("Trying to perform a RBD clone (layering) since we are operating in the same storage pool");

Rados r = new Rados(srcPool.getAuthUserName());
r.confSet("mon_host", srcPool.getSourceHost() + ":" + srcPool.getSourcePort());
r.confSet("mon_host", RbdUtils.getRbdMonitors(srcPool.getSourceHost(), srcPool.getSourcePort()));
r.confSet("key", srcPool.getAuthSecret());
r.confSet("client_mount_timeout", "30");
if (dataPool != null) {
Expand Down Expand Up @@ -1426,14 +1427,14 @@ private KVMPhysicalDisk createDiskFromTemplateOnRBD(KVMPhysicalDisk template,
logger.debug("Both the source and destination are RBD, but not the same Ceph cluster. Performing a copy");

Rados rSrc = new Rados(srcPool.getAuthUserName());
rSrc.confSet("mon_host", srcPool.getSourceHost() + ":" + srcPool.getSourcePort());
rSrc.confSet("mon_host", RbdUtils.getRbdMonitors(srcPool.getSourceHost(), srcPool.getSourcePort()));
rSrc.confSet("key", srcPool.getAuthSecret());
rSrc.confSet("client_mount_timeout", "30");
rSrc.connect();
logger.debug("Successfully connected to source Ceph cluster at " + rSrc.confGet("mon_host"));

Rados rDest = new Rados(destPool.getAuthUserName());
rDest.confSet("mon_host", destPool.getSourceHost() + ":" + destPool.getSourcePort());
rDest.confSet("mon_host", RbdUtils.getRbdMonitors(destPool.getSourceHost(), destPool.getSourcePort()));
rDest.confSet("key", destPool.getAuthSecret());
rDest.confSet("client_mount_timeout", "30");
if (dataPool != null) {
Expand Down Expand Up @@ -1498,7 +1499,7 @@ private KVMPhysicalDisk createEncryptedRootCoWClone(KVMPhysicalDisk template, KV
RbdImage templateImage = null;
try {
radosConnection = new Rados(destPool.getAuthUserName());
radosConnection.confSet("mon_host", destPool.getSourceHost() + ":" + destPool.getSourcePort());
radosConnection.confSet("mon_host", RbdUtils.getRbdMonitors(destPool.getSourceHost(), destPool.getSourcePort()));
radosConnection.confSet("key", destPool.getAuthSecret());
radosConnection.confSet("client_mount_timeout", "30");
radosConnection.connect();
Expand Down Expand Up @@ -1559,7 +1560,7 @@ private KVMPhysicalDisk createEncryptedRootFullCopy(KVMStoragePool srcPool, KVMP
IoCTX ioContext = null;
try {
radosConnection = new Rados(destPool.getAuthUserName());
radosConnection.confSet("mon_host", destPool.getSourceHost() + ":" + destPool.getSourcePort());
radosConnection.confSet("mon_host", RbdUtils.getRbdMonitors(destPool.getSourceHost(), destPool.getSourcePort()));
radosConnection.confSet("key", destPool.getAuthSecret());
radosConnection.confSet("client_mount_timeout", "30");
radosConnection.connect();
Expand Down Expand Up @@ -1738,7 +1739,7 @@ to support snapshots(backuped) as qcow2 files. */

/* We have to stat the RBD image to see how big it became afterwards */
Rados r = new Rados(destPool.getAuthUserName());
r.confSet("mon_host", destPool.getSourceHost() + ":" + destPool.getSourcePort());
r.confSet("mon_host", RbdUtils.getRbdMonitors(destPool.getSourceHost(), destPool.getSourcePort()));
r.confSet("key", destPool.getAuthSecret());
r.confSet("client_mount_timeout", "30");
r.connect();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
// under the License.
package org.apache.cloudstack.utils.rbd;

import com.cloud.utils.RbdUtils;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.script.Script;
import org.apache.cloudstack.utils.cryptsetup.CryptSetup;
Expand Down Expand Up @@ -67,7 +68,7 @@ public RbdEncryption(String commandPath) {
}

private static String monSpec(String monHost, int monPort) {
return monPort > 0 ? monHost + ":" + monPort : monHost;
return RbdUtils.getRbdMonitors(monHost, monPort);
}

/**
Expand Down
78 changes: 78 additions & 0 deletions utils/src/main/java/com/cloud/utils/RbdUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// 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.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;

public class RbdUtils {

private RbdUtils() {
}

/**
* Returns the Ceph monitors as expected by "--mon-host": the comma-separated monitors of the pool, trimmed
* and without empty entries. If the pool has a monitor port, it is added to each monitor which has none yet.
*
* @param sourceHost the comma-separated monitors, IPv4 or IPv6 addresses or host names
* @param sourcePort the port of the monitors, or 0 (or less) if the pool has none
*/
public static String getRbdMonitors(String sourceHost, int sourcePort) {
List<String> monitors = new ArrayList<>();
for (String monitor : sourceHost.split(",")) {
monitor = monitor.trim();
if (monitor.isEmpty()) {
continue;
}
monitors.add(sourcePort > 0 ? addPortToRbdMonitor(monitor, sourcePort) : monitor);
}
return String.join(",", monitors);
}

protected static String addPortToRbdMonitor(String monitor, int port) {
if (monitor.startsWith("[")) {
// IPv6 address in square brackets, which has a port if followed by ":<port>"
return monitor.contains("]:") ? monitor : monitor + ":" + port;
}
int colons = StringUtils.countMatches(monitor, ":");
if (colons == 0) {
return monitor + ":" + port;
}
if (colons == 1) {
// IPv4 address or host name, with a port
return monitor;
}
// IPv6 address without square brackets, so without a port
return "[" + monitor + "]:" + port;
}

/**
* The monitor list as the {@code rbd:} option string of a disk needs it: ':' separates the
* options of that string and ';' its monitors, so both are escaped inside the list, as is
* every ':' of an IPv6 address.
*/
public static String composeOptionForMonHosts(String monHost, int monPort) {
List<String> hosts = new ArrayList<>();
for (String monitor : getRbdMonitors(monHost, monPort).split(",")) {
hosts.add(monitor.replace(":", "\\:"));
}
return StringUtils.join(hosts, "\\;");
}
}
Loading
Loading