Skip to content

Commit daacf3e

Browse files
committed
kvm: keep the Ceph key out of the logs and process list of the RBD Host HA checks, and harden the parsing
Follow-up to the review of the Host HA on Ceph RBD support: - LibvirtStoragePool: do not add a port to Ceph monitors which have one already, and only wrap bare IPv6 addresses in square brackets; mask the Ceph key in the logged command - kvmheartbeat_rbd.sh, kvmvmactivity_rbd.sh: give the Ceph key to rados and rbd in a temporary keyfile instead of --key - kvmheartbeat_rbd.sh: require -t to be a number when checking a heartbeat - kvmvmactivity_rbd.sh: read the list of volumes without word splitting or globbing, skipping empty entries, and check if the activity object exists by the exit status of rados stat - add unit tests for monitors with a port and for the masked key
1 parent a36604e commit daacf3e

4 files changed

Lines changed: 64 additions & 17 deletions

File tree

‎plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStoragePool.java‎

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -352,8 +352,7 @@ private String findKvmHaScript(String scriptName) {
352352

353353
/**
354354
* Returns the Ceph monitors as expected by "--mon-host": the comma-separated monitors of the pool, trimmed
355-
* and without empty entries, each with the pool's monitor port if one is set (IPv6 addresses are enclosed
356-
* in square brackets then).
355+
* and without empty entries. If the pool has a monitor port, it is added to each monitor which has none yet.
357356
*/
358357
protected String getRbdMonitors() {
359358
List<String> monitors = new ArrayList<>();
@@ -362,17 +361,28 @@ protected String getRbdMonitors() {
362361
if (monitor.isEmpty()) {
363362
continue;
364363
}
365-
if (sourcePort > 0) {
366-
if (monitor.contains(":") && !monitor.startsWith("[")) {
367-
monitor = "[" + monitor + "]";
368-
}
369-
monitor = monitor + ":" + sourcePort;
370-
}
371-
monitors.add(monitor);
364+
monitors.add(sourcePort > 0 ? addPortToRbdMonitor(monitor) : monitor);
372365
}
373366
return String.join(",", monitors);
374367
}
375368

369+
private String addPortToRbdMonitor(String monitor) {
370+
if (monitor.startsWith("[")) {
371+
// IPv6 address in square brackets, which has a port if followed by ":<port>"
372+
return monitor.contains("]:") ? monitor : monitor + ":" + sourcePort;
373+
}
374+
int colons = StringUtils.countMatches(monitor, ":");
375+
if (colons == 0) {
376+
return monitor + ":" + sourcePort;
377+
}
378+
if (colons == 1) {
379+
// IPv4 address or host name, with a port
380+
return monitor;
381+
}
382+
// IPv6 address without square brackets, so without a port
383+
return "[" + monitor + "]:" + sourcePort;
384+
}
385+
376386
/**
377387
* Adds the Ceph cluster connection details (monitors, pool and, if cephx is enabled, credentials)
378388
* to a heartbeat/VM-activity check {@link Script} for a RBD storage pool. Mirrors the "mon_host"/"id"/"key"
@@ -388,7 +398,8 @@ protected void addRbdConnectionArgs(Script cmd) {
388398
cmd.add("-o", sourceDir);
389399
if (hasUser) {
390400
cmd.add("-n", authUsername);
391-
cmd.add("-k", authSecret);
401+
cmd.add("-k");
402+
cmd.addSensitive(authSecret);
392403
}
393404
}
394405

‎plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/LibvirtStoragePoolTest.java‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,8 @@ public void testAddRbdConnectionArgsWithCephx() {
195195
Mockito.verify(cmd).add("-s", "10.0.0.1:6789,[fd00::1]:6789");
196196
Mockito.verify(cmd).add("-o", "rbdpool");
197197
Mockito.verify(cmd).add("-n", "cephuser");
198-
Mockito.verify(cmd).add("-k", "cephkey");
198+
Mockito.verify(cmd).add("-k");
199+
Mockito.verify(cmd).addSensitive("cephkey");
199200
Mockito.verifyNoMoreInteractions(cmd);
200201
}
201202

@@ -222,4 +223,19 @@ public void testAddRbdConnectionArgsWithCephUserOnlyOrKeyOnly() {
222223
}
223224
}
224225
}
226+
227+
@Test
228+
public void testRbdMonitorsWhichHaveAPortAlready() {
229+
// the monitors keep their port, with or without a port of the pool
230+
String withPorts = "10.0.0.1:6789,mon.example.com:3300,[fd00::1]:6789";
231+
assertEquals(withPorts, getRbdMonitors(withPorts, 0));
232+
assertEquals(withPorts, getRbdMonitors(withPorts, 6789));
233+
assertEquals(withPorts, getRbdMonitors(withPorts, 3300));
234+
}
235+
236+
@Test
237+
public void testRbdMonitorsWithAndWithoutAPortAreMixed() {
238+
assertEquals("10.0.0.1:6789,10.0.0.2:3300,mon.example.com:3300,[fd00::1]:3300,[fd00::2]:6789,[fd00::3]:3300",
239+
getRbdMonitors("10.0.0.1:6789,10.0.0.2,mon.example.com,fd00::1,[fd00::2]:6789,[fd00::3]", 3300));
240+
}
225241
}

‎scripts/vm/hypervisor/kvm/kvmheartbeat_rbd.sh‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,20 @@ then
9595
exit 1
9696
fi
9797

98+
# -t is the maximum age of the heartbeat, which is compared in a check
99+
if [ "$rflag" == "1" ] && ! [[ "$interval" =~ ^[0-9]+$ ]]
100+
then
101+
exit 1
102+
fi
103+
98104
RadosOpts=(--mon-host "$MonHosts")
99-
if [ -n "$CephUser" ]
105+
if [ -n "$CephUser" ] && [ "$cflag" != "1" ]
100106
then
101-
RadosOpts+=(--id "$CephUser" --key "$CephKey")
107+
# the key is given to rados in a file, to keep it out of the process list
108+
KeyFile=$(mktemp)
109+
trap 'rm -f "$KeyFile"' EXIT
110+
printf '%s' "$CephKey" > "$KeyFile"
111+
RadosOpts+=(--id "$CephUser" --keyfile "$KeyFile")
102112
fi
103113

104114
hbObject="KVMHA-hb-$HostIP"

‎scripts/vm/hypervisor/kvm/kvmvmactivity_rbd.sh‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,12 @@ RadosOpts=(--mon-host "$MonHosts")
107107
RbdOpts=(--mon-host "$MonHosts")
108108
if [ -n "$CephUser" ]
109109
then
110-
RadosOpts+=(--id "$CephUser" --key "$CephKey")
111-
RbdOpts+=(--id "$CephUser" --key "$CephKey")
110+
# the key is given to rados and rbd in a file, to keep it out of the process list
111+
KeyFile=$(mktemp)
112+
trap 'rm -f "$KeyFile"' EXIT
113+
printf '%s' "$CephKey" > "$KeyFile"
114+
RadosOpts+=(--id "$CephUser" --keyfile "$KeyFile")
115+
RbdOpts+=(--id "$CephUser" --keyfile "$KeyFile")
112116
fi
113117

114118
hbObject="KVMHA-hb-$HostIP"
@@ -137,8 +141,14 @@ fi
137141
# If any of the host's volumes still has a live watcher, something (most
138142
# likely qemu on the host being checked) is actively using it right now.
139143
latestUpdateTime=0
140-
for image in ${UUIDList//,/ }
144+
IFS=',' read -ra images <<< "$UUIDList"
145+
for image in "${images[@]}"
141146
do
147+
image=${image//[[:space:]]/}
148+
if [ -z "$image" ]
149+
then
150+
continue
151+
fi
142152
watcherCount=$(rbd status "$PoolName/$image" "${RbdOpts[@]}" --format json 2> /dev/null | \
143153
python3 -c 'import json,sys
144154
try:
@@ -152,7 +162,7 @@ except Exception:
152162
fi
153163
done
154164

155-
if [ ! -z "$(rados -p "$PoolName" "${RadosOpts[@]}" stat "$acObject" 2> /dev/null)" ]
165+
if rados -p "$PoolName" "${RadosOpts[@]}" stat "$acObject" &> /dev/null
156166
then
157167
acTime=$(rados -p "$PoolName" "${RadosOpts[@]}" get "$acObject" - 2> /dev/null)
158168
else

0 commit comments

Comments
 (0)