Skip to content

Commit afe55ea

Browse files
committed
CLOUDSTACK-8715: Add channel to Instances for Qemu Guest Agent
This commit adds a additional VirtIO channel with the name 'org.qemu.guest_agent.0' to all Instances. With the Qemu Guest Agent the Hypervisor gains more control over the Instance if these tools are present inside the Instance, for example: * Power control * Flushing filesystems * Fetching Network information In the future this should allow safer snapshots on KVM since we can instruct the Instance to flush the filesystems prior to snapshotting the disk. More information: http://wiki.qemu.org/Features/QAPI/GuestAgent Keep in mind that on Ubuntu AppArmor still needs to be disabled since the default AppArmor profile doesn't allow libvirt to write into /var/lib/libvirt/qemu This commit does not add any communication methods through API-calls, it merely adds the channel to the Instances and installs the Guest Agent in the SSVMs.
1 parent 2b4b8aa commit afe55ea

File tree

7 files changed

+161
-13
lines changed

7 files changed

+161
-13
lines changed

plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
import com.cloud.exception.InternalErrorException;
9696
import com.cloud.host.Host.Type;
9797
import com.cloud.hypervisor.Hypervisor.HypervisorType;
98+
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef;
9899
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ClockDef;
99100
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ConsoleDef;
100101
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.CpuModeDef;
@@ -114,7 +115,6 @@
114115
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.SerialDef;
115116
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.TermPolicy;
116117
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.VideoDef;
117-
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.VirtioSerialDef;
118118
import com.cloud.hypervisor.kvm.resource.wrapper.LibvirtRequestWrapper;
119119
import com.cloud.hypervisor.kvm.resource.wrapper.LibvirtUtilitiesHelper;
120120
import com.cloud.hypervisor.kvm.storage.KVMPhysicalDisk;
@@ -1978,9 +1978,14 @@ So if getMinSpeed() returns null we fall back to getSpeed().
19781978
final SerialDef serial = new SerialDef("pty", null, (short)0);
19791979
devices.addDevice(serial);
19801980

1981+
/* Add a VirtIO channel for the Qemu Guest Agent tools */
1982+
devices.addDevice(new ChannelDef("org.qemu.guest_agent.0", ChannelDef.ChannelType.UNIX,
1983+
"/var/lib/libvirt/qemu/" + vmTO.getName() + ".org.qemu.guest_agent.0"));
1984+
1985+
/* Add a VirtIO channel for SystemVMs for communication and provisioning */
19811986
if (vmTO.getType() != VirtualMachine.Type.User) {
1982-
final VirtioSerialDef vserial = new VirtioSerialDef(vmTO.getName(), null);
1983-
devices.addDevice(vserial);
1987+
devices.addDevice(new ChannelDef(vmTO.getName() + ".vport", ChannelDef.ChannelType.UNIX,
1988+
"/var/lib/libvirt/qemu/" + vmTO.getName() + ".agent"));
19841989
}
19851990

19861991
final VideoDef videoCard = new VideoDef(_videoHw, _videoRam);

plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.xml.sax.InputSource;
3434
import org.xml.sax.SAXException;
3535

36+
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef;
3637
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
3738
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
3839
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef.NicModel;
@@ -41,6 +42,7 @@ public class LibvirtDomainXMLParser {
4142
private static final Logger s_logger = Logger.getLogger(LibvirtDomainXMLParser.class);
4243
private final List<InterfaceDef> interfaces = new ArrayList<InterfaceDef>();
4344
private final List<DiskDef> diskDefs = new ArrayList<DiskDef>();
45+
private final List<ChannelDef> channels = new ArrayList<ChannelDef>();
4446
private Integer vncPort;
4547
private String desc;
4648

@@ -171,6 +173,25 @@ public boolean parseDomainXML(String domXML) {
171173
interfaces.add(def);
172174
}
173175

176+
NodeList ports = devices.getElementsByTagName("channel");
177+
for (int i = 0; i < ports.getLength(); i++) {
178+
Element channel = (Element)ports.item(i);
179+
180+
String type = channel.getAttribute("type");
181+
String path = getAttrValue("source", "path", channel);
182+
String name = getAttrValue("target", "name", channel);
183+
String state = getAttrValue("target", "state", channel);
184+
185+
ChannelDef def = null;
186+
if (state == null || state.length() == 0) {
187+
def = new ChannelDef(name, ChannelDef.ChannelType.valueOf(type.toUpperCase()), path);
188+
} else {
189+
def = new ChannelDef(name, ChannelDef.ChannelType.valueOf(type.toUpperCase()), ChannelDef.ChannelState.valueOf(state.toUpperCase()), path);
190+
}
191+
192+
channels.add(def);
193+
}
194+
174195
Element graphic = (Element)devices.getElementsByTagName("graphics").item(0);
175196

176197
if (graphic != null) {
@@ -234,6 +255,10 @@ public List<DiskDef> getDisks() {
234255
return diskDefs;
235256
}
236257

258+
public List<ChannelDef> getChannels() {
259+
return channels;
260+
}
261+
237262
public String getDescription() {
238263
return desc;
239264
}

plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,25 +1209,95 @@ public String toString() {
12091209
}
12101210
}
12111211

1212-
public static class VirtioSerialDef {
1213-
private final String _name;
1212+
public static class ChannelDef {
1213+
enum ChannelType {
1214+
UNIX("unix"), SERIAL("serial");
1215+
String _type;
1216+
1217+
ChannelType(String type) {
1218+
_type = type;
1219+
}
1220+
1221+
@Override
1222+
public String toString() {
1223+
return _type;
1224+
}
1225+
}
1226+
1227+
enum ChannelState {
1228+
DISCONNECTED("disconnected"), CONNECTED("connected");
1229+
String _type;
1230+
1231+
ChannelState(String type) {
1232+
_type = type;
1233+
}
1234+
1235+
@Override
1236+
public String toString() {
1237+
return _type;
1238+
}
1239+
}
1240+
1241+
private String _name;
12141242
private String _path;
1243+
private ChannelType _type;
1244+
private ChannelState _state;
1245+
1246+
public ChannelDef(String name, ChannelType type) {
1247+
_name = name;
1248+
_type = type;
1249+
}
1250+
1251+
public ChannelDef(String name, ChannelType type, String path) {
1252+
_name = name;
1253+
_path = path;
1254+
_type = type;
1255+
}
1256+
1257+
public ChannelDef(String name, ChannelType type, ChannelState state) {
1258+
_name = name;
1259+
_state = state;
1260+
_type = type;
1261+
}
12151262

1216-
public VirtioSerialDef(String name, String path) {
1263+
public ChannelDef(String name, ChannelType type, ChannelState state, String path) {
12171264
_name = name;
12181265
_path = path;
1266+
_state = state;
1267+
_type = type;
1268+
}
1269+
1270+
public ChannelType getChannelType() {
1271+
return _type;
1272+
}
1273+
1274+
public ChannelState getChannelState() {
1275+
return _state;
1276+
}
1277+
1278+
public String getName() {
1279+
return _name;
1280+
}
1281+
1282+
public String getPath() {
1283+
return _path;
12191284
}
12201285

12211286
@Override
12221287
public String toString() {
12231288
StringBuilder virtioSerialBuilder = new StringBuilder();
1289+
virtioSerialBuilder.append("<channel type='" + _type.toString() + "'>\n");
12241290
if (_path == null) {
1225-
_path = "/var/lib/libvirt/qemu";
1291+
virtioSerialBuilder.append("<source mode='bind'/>\n");
1292+
} else {
1293+
virtioSerialBuilder.append("<source mode='bind' path='" + _path + "'/>\n");
12261294
}
1227-
virtioSerialBuilder.append("<channel type='unix'>\n");
1228-
virtioSerialBuilder.append("<source mode='bind' path='" + _path + "/" + _name + ".agent'/>\n");
1229-
virtioSerialBuilder.append("<target type='virtio' name='" + _name + ".vport'/>\n");
12301295
virtioSerialBuilder.append("<address type='virtio-serial'/>\n");
1296+
if (_state == null) {
1297+
virtioSerialBuilder.append("<target type='virtio' name='" + _name + "'/>\n");
1298+
} else {
1299+
virtioSerialBuilder.append("<target type='virtio' name='" + _name + "' state='" + _state.toString() + "'/>\n");
1300+
}
12311301
virtioSerialBuilder.append("</channel>\n");
12321302
return virtioSerialBuilder.toString();
12331303
}

plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtComputingResourceTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@
149149
import com.cloud.agent.resource.virtualnetwork.VirtualRoutingResource;
150150
import com.cloud.exception.InternalErrorException;
151151
import com.cloud.hypervisor.kvm.resource.KVMHABase.NfsStoragePool;
152+
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef;
152153
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
153154
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
154155
import com.cloud.hypervisor.kvm.resource.wrapper.LibvirtRequestWrapper;
@@ -335,6 +336,9 @@ private void verifyVm(final VirtualMachineTO to, final LibvirtVMDef vm) {
335336
assertXpath(domainDoc, "/domain/devices/input/@type", "tablet");
336337
assertXpath(domainDoc, "/domain/devices/input/@bus", "usb");
337338

339+
assertNodeExists(domainDoc, "/domain/devices/channel");
340+
assertXpath(domainDoc, "/domain/devices/channel/@type", ChannelDef.ChannelType.UNIX.toString());
341+
338342
assertXpath(domainDoc, "/domain/memory/text()", String.valueOf( to.getMaxRam() / 1024 ));
339343
assertXpath(domainDoc, "/domain/currentMemory/text()", String.valueOf( to.getMinRam() / 1024 ));
340344

plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParserTest.java

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.List;
2424
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
2525
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
26+
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef;
2627

2728
public class LibvirtDomainXMLParserTest extends TestCase {
2829

@@ -38,6 +39,13 @@ public void testDomainXMLParser() {
3839
InterfaceDef.NicModel ifModel = InterfaceDef.NicModel.VIRTIO;
3940
InterfaceDef.GuestNetType ifType = InterfaceDef.GuestNetType.BRIDGE;
4041

42+
ChannelDef.ChannelType channelType = ChannelDef.ChannelType.UNIX;
43+
ChannelDef.ChannelState channelState = ChannelDef.ChannelState.DISCONNECTED;
44+
String ssvmAgentPath = "/var/lib/libvirt/qemu/s-2970-VM.agent";
45+
String ssvmAgentName = "s-2970-VM.vport";
46+
String guestAgentPath = "/var/lib/libvirt/qemu/guest-agent.org.qemu.guest_agent.0";
47+
String guestAgentName = "org.qemu.guest_agent.0";
48+
4149
String diskLabel ="vda";
4250
String diskPath = "/var/lib/libvirt/images/my-test-image.qcow2";
4351

@@ -144,7 +152,7 @@ public void testDomainXMLParser() {
144152
"</console>" +
145153
"<channel type='unix'>" +
146154
"<source mode='bind' path='/var/lib/libvirt/qemu/s-2970-VM.agent'/>" +
147-
"<target type='virtio' name='s-2970-VM.vport'/>" +
155+
"<target type='virtio' name='s-2970-VM.vport' state='disconnected'/>" +
148156
"<alias name='channel0'/>" +
149157
"<address type='virtio-serial' controller='0' bus='0' port='1'/>" +
150158
"</channel>" +
@@ -164,6 +172,12 @@ public void testDomainXMLParser() {
164172
"<alias name='balloon0'/>" +
165173
"<address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>" +
166174
"</memballoon>" +
175+
"<channel type='unix'>" +
176+
"<source mode='bind' path='" + guestAgentPath + "'/>" +
177+
"<target type='virtio' name='" + guestAgentName + "'/>" +
178+
"<alias name='channel0'/>" +
179+
"<address type='virtio-serial' controller='0' bus='0' port='1'/>" +
180+
"</channel>" +
167181
"</devices>" +
168182
"<seclabel type='none'/>" +
169183
"</domain>";
@@ -185,10 +199,25 @@ public void testDomainXMLParser() {
185199
assertEquals(deviceType, disks.get(diskId).getDeviceType());
186200
assertEquals(diskFormat, disks.get(diskId).getDiskFormatType());
187201

202+
List<ChannelDef> channels = parser.getChannels();
203+
for (int i = 0; i < channels.size(); i++) {
204+
assertEquals(channelType, channels.get(i).getChannelType());
205+
assertEquals(channelType, channels.get(i).getChannelType());
206+
}
207+
208+
/* SSVM provisioning port/channel */
209+
assertEquals(channelState, channels.get(0).getChannelState());
210+
assertEquals(ssvmAgentPath, channels.get(0).getPath());
211+
assertEquals(ssvmAgentName, channels.get(0).getName());
212+
213+
/* Qemu Guest Agent port/channel */
214+
assertEquals(guestAgentPath, channels.get(1).getPath());
215+
assertEquals(guestAgentName, channels.get(1).getName());
216+
188217
List<InterfaceDef> ifs = parser.getInterfaces();
189218
for (int i = 0; i < ifs.size(); i++) {
190219
assertEquals(ifModel, ifs.get(i).getModel());
191220
assertEquals(ifType, ifs.get(i).getNetType());
192221
}
193222
}
194-
}
223+
}

plugins/hypervisors/kvm/test/com/cloud/hypervisor/kvm/resource/LibvirtVMDefTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import junit.framework.TestCase;
2323
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
24+
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.ChannelDef;
2425
import com.cloud.utils.Pair;
2526

2627
public class LibvirtVMDefTest extends TestCase {
@@ -118,4 +119,18 @@ public void testHypervEnlightDef() {
118119
assertTrue((hostOsVersion.first() == 6 && hostOsVersion.second() >= 5) || (hostOsVersion.first() >= 7));
119120
}
120121

122+
public void testChannelDef() {
123+
ChannelDef.ChannelType type = ChannelDef.ChannelType.UNIX;
124+
ChannelDef.ChannelState state = ChannelDef.ChannelState.CONNECTED;
125+
String name = "v-136-VM.vport";
126+
String path = "/var/lib/libvirt/qemu/" + name;
127+
128+
ChannelDef channelDef = new ChannelDef(name, type, state, path);
129+
130+
assertEquals(state, channelDef.getChannelState());
131+
assertEquals(type, channelDef.getChannelType());
132+
assertEquals(name, channelDef.getName());
133+
assertEquals(path, channelDef.getPath());
134+
}
135+
121136
}

tools/appliance/definitions/systemvmtemplate/install_systemvm_packages.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ function install_packages() {
7575
radvd \
7676
sharutils
7777

78-
${apt_get} -t wheezy-backports install keepalived irqbalance open-vm-tools
78+
${apt_get} -t wheezy-backports install keepalived irqbalance open-vm-tools qemu-guest-agent
7979

8080
# hold on installed openswan version, upgrade rest of the packages (if any)
8181
apt-mark hold openswan

0 commit comments

Comments
 (0)