Skip to content

Commit 32b7d54

Browse files
committed
Flesh out cloud-hypervisor support for virsh console
This change enables virsh console support for the cloud-hypervisor domain. Along the way it also allows the handling of GET requests to the cloud-hypervisor. To use this feature, adding the following under the device node in the configuration xml: <console type='pty'> <target type='virtio' port='0'/> </console>
1 parent cc18b84 commit 32b7d54

File tree

4 files changed

+182
-4
lines changed

4 files changed

+182
-4
lines changed

src/ch/ch_domain.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,12 @@ virCHDomainObjPrivateAlloc(void *opaque)
149149
VIR_FREE(priv);
150150
return NULL;
151151
}
152+
153+
if (!(priv->devs = virChrdevAlloc())) {
154+
VIR_FREE(priv);
155+
return NULL;
156+
}
157+
152158
priv->driver = opaque;
153159

154160
return priv;
@@ -159,6 +165,7 @@ virCHDomainObjPrivateFree(void *data)
159165
{
160166
virCHDomainObjPrivatePtr priv = data;
161167

168+
virChrdevFree(priv->devs);
162169
virCHDomainObjFreeJob(priv);
163170
VIR_FREE(priv);
164171
}

src/ch/ch_monitor.c

Lines changed: 105 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ VIR_ONCE_GLOBAL_INIT(virCHMonitor);
5656

5757
int virCHMonitorShutdownVMM(virCHMonitorPtr mon);
5858
int virCHMonitorPutNoContent(virCHMonitorPtr mon, const char *endpoint);
59-
int virCHMonitorGet(virCHMonitorPtr mon, const char *endpoint);
59+
int virCHMonitorGet(virCHMonitorPtr mon, const char *endpoint, virJSONValuePtr *response);
6060
int virCHMonitorPingVMM(virCHMonitorPtr mon);
6161

6262
static int
@@ -93,6 +93,55 @@ virCHMonitorBuildCPUJson(virJSONValuePtr content, virDomainDefPtr vmdef)
9393
return -1;
9494
}
9595

96+
static int
97+
virCHMonitorBuildPTYJson(virJSONValuePtr content, virDomainDefPtr vmdef)
98+
{
99+
virJSONValuePtr ptyc = virJSONValueNewObject();
100+
virJSONValuePtr ptys = virJSONValueNewObject();
101+
102+
if (vmdef->nconsoles || vmdef->nserials) {
103+
if (vmdef->nconsoles > 1) {
104+
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
105+
_("Only a single console can be configured for this domain"));
106+
return -1;
107+
}
108+
if (vmdef->nserials > 1) {
109+
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
110+
_("Only a single serial can be configured for this domain"));
111+
return -1;
112+
}
113+
}
114+
115+
if (vmdef->nconsoles) {
116+
if (virJSONValueObjectAppendString(ptyc, "mode", "Pty") < 0)
117+
goto cleanup;
118+
} else {
119+
if (virJSONValueObjectAppendString(ptyc, "mode", "Null") < 0)
120+
goto cleanup;
121+
}
122+
123+
if (vmdef->nserials) {
124+
if (virJSONValueObjectAppendString(ptys, "mode", "Pty") < 0)
125+
goto cleanup;
126+
} else {
127+
if (virJSONValueObjectAppendString(ptys, "mode", "Null") < 0)
128+
goto cleanup;
129+
}
130+
131+
if (virJSONValueObjectAppend(content, "console", ptyc) < 0)
132+
goto cleanup;
133+
if (virJSONValueObjectAppend(content, "serial", ptys) < 0)
134+
goto cleanup;
135+
136+
return 0;
137+
138+
cleanup:
139+
virJSONValueFree(ptyc);
140+
virJSONValueFree(ptys);
141+
return -1;
142+
}
143+
144+
96145
static int
97146
virCHMonitorBuildKernelJson(virJSONValuePtr content, virDomainDefPtr vmdef)
98147
{
@@ -449,6 +498,9 @@ virCHMonitorBuildVMJson(virDomainObjPtr vm, virDomainDefPtr vmdef, char **jsonst
449498
if (virCHMonitorBuildCPUJson(content, vmdef) < 0)
450499
goto cleanup;
451500

501+
if (virCHMonitorBuildPTYJson(content, vmdef) < 0)
502+
goto cleanup;
503+
452504
if (virCHMonitorBuildMemoryJson(content, vmdef) < 0)
453505
goto cleanup;
454506

@@ -784,12 +836,33 @@ virCHMonitorPutNoContent(virCHMonitorPtr mon, const char *endpoint)
784836
return ret;
785837
}
786838

839+
struct curl_data {
840+
char *content;
841+
size_t size;
842+
};
843+
844+
static size_t
845+
curl_callback(void *contents, size_t size, size_t nmemb, void *userp)
846+
{
847+
size_t content_size = size * nmemb;
848+
struct curl_data *data = (struct curl_data *)userp;
849+
850+
data->content = g_malloc0(content_size + 1);
851+
memcpy(data->content, contents, content_size);
852+
data->content[content_size] = 0;
853+
data->size = content_size;
854+
855+
return content_size;
856+
}
857+
787858
int
788-
virCHMonitorGet(virCHMonitorPtr mon, const char *endpoint)
859+
virCHMonitorGet(virCHMonitorPtr mon, const char *endpoint, virJSONValuePtr *response)
789860
{
790861
char *url;
791862
int responseCode = 0;
792863
int ret = -1;
864+
struct curl_slist *headers = NULL;
865+
struct curl_data data;
793866

794867
url = g_strdup_printf("%s/%s", URL_ROOT, endpoint);
795868

@@ -801,12 +874,24 @@ virCHMonitorGet(virCHMonitorPtr mon, const char *endpoint)
801874
curl_easy_setopt(mon->handle, CURLOPT_UNIX_SOCKET_PATH, mon->socketpath);
802875
curl_easy_setopt(mon->handle, CURLOPT_URL, url);
803876

877+
if (response) {
878+
headers = curl_slist_append(headers, "Accept: application/json");
879+
headers = curl_slist_append(headers, "Content-Type: application/json");
880+
curl_easy_setopt(mon->handle, CURLOPT_HTTPHEADER, headers);
881+
curl_easy_setopt(mon->handle, CURLOPT_WRITEFUNCTION, curl_callback);
882+
curl_easy_setopt(mon->handle, CURLOPT_WRITEDATA, (void *)&data);
883+
}
884+
804885
responseCode = virCHMonitorCurlPerform(mon->handle);
805886

806887
virObjectUnlock(mon);
807888

808-
if (responseCode == 200 || responseCode == 204)
889+
if (responseCode == 200 || responseCode == 204) {
809890
ret = 0;
891+
if (response) {
892+
*response = virJSONValueFromString(data.content);
893+
}
894+
}
810895

811896
VIR_FREE(url);
812897
return ret;
@@ -815,7 +900,7 @@ virCHMonitorGet(virCHMonitorPtr mon, const char *endpoint)
815900
int
816901
virCHMonitorPingVMM(virCHMonitorPtr mon)
817902
{
818-
return virCHMonitorGet(mon, URL_VMM_PING);
903+
return virCHMonitorGet(mon, URL_VMM_PING, NULL);
819904
}
820905

821906
int
@@ -992,6 +1077,22 @@ virCHMonitorRefreshThreadInfo(virCHMonitorPtr mon)
9921077
return mon->nthreads;
9931078
}
9941079

1080+
/**
1081+
* virCHMonitorGetInfo:
1082+
* @mon: Pointer to the monitor
1083+
* @info: Get VM info
1084+
*
1085+
* Retrive the VM info and store in @info
1086+
*
1087+
* Returns 0 on success.
1088+
*/
1089+
int
1090+
virCHMonitorGetInfo(virCHMonitorPtr mon, virJSONValuePtr *info)
1091+
{
1092+
return virCHMonitorGet(mon, URL_VM_INFO, info);
1093+
}
1094+
1095+
9951096
/**
9961097
* virCHMonitorGetThreadInfo:
9971098
* @mon: Pointer to the monitor

src/ch/ch_monitor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <curl/curl.h>
2424

2525
#include "virobject.h"
26+
#include "virjson.h"
2627
#include "domain_conf.h"
2728

2829
#define URL_ROOT "http://localhost/api/v1"
@@ -35,6 +36,7 @@
3536
#define URL_VM_REBOOT "vm.reboot"
3637
#define URL_VM_Suspend "vm.pause"
3738
#define URL_VM_RESUME "vm.resume"
39+
#define URL_VM_INFO "vm.info"
3840

3941
#define VIRCH_THREAD_NAME_LEN 16
4042

@@ -118,3 +120,5 @@ size_t virCHMonitorGetThreadInfo(virCHMonitorPtr mon, bool refresh,
118120

119121
int virCHMonitorGetIOThreads(virCHMonitorPtr mon,
120122
virDomainIOThreadInfoPtr **iothreads);
123+
124+
int virCHMonitorGetInfo(virCHMonitorPtr mon, virJSONValuePtr *info);

src/ch/ch_process.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "virnuma.h"
3333
#include "viralloc.h"
3434
#include "virerror.h"
35+
#include "virjson.h"
3536
#include "virlog.h"
3637

3738
#define VIR_FROM_THIS VIR_FROM_CH
@@ -300,6 +301,69 @@ virCHProcessSetupEmulatorThreads(virDomainObjPtr vm)
300301
return 0;
301302
}
302303

304+
static void
305+
virCHProcessUpdateConsoleDevice(virDomainObjPtr vm,
306+
virJSONValuePtr config,
307+
const char *device)
308+
{
309+
const char *path;
310+
virDomainChrDefPtr chr = NULL;
311+
virJSONValuePtr dev, file;
312+
313+
if (!config)
314+
return;
315+
316+
dev = virJSONValueObjectGet(config, device);
317+
if (!dev)
318+
return;
319+
320+
file = virJSONValueObjectGet(dev, "file");
321+
if (!file)
322+
return;
323+
324+
path = virJSONValueGetString(file);
325+
if (!path)
326+
return;
327+
328+
if (STREQ(device, "console")) {
329+
chr = vm->def->consoles[0];
330+
} else if (STREQ(device, "serial")) {
331+
chr = vm->def->serials[0];
332+
}
333+
334+
if (chr && chr->source)
335+
chr->source->data.file.path = g_strdup(path);
336+
}
337+
338+
static void
339+
virCHProcessUpdateConsole(virDomainObjPtr vm,
340+
virJSONValuePtr info)
341+
{
342+
virJSONValuePtr config;
343+
344+
config = virJSONValueObjectGet(info, "config");
345+
if (!config)
346+
return;
347+
348+
virCHProcessUpdateConsoleDevice(vm, config, "console");
349+
virCHProcessUpdateConsoleDevice(vm, config, "serial");
350+
}
351+
352+
static int
353+
virCHProcessUpdateInfo(virDomainObjPtr vm)
354+
{
355+
virJSONValuePtr info;
356+
virCHDomainObjPrivatePtr priv = vm->privateData;
357+
if (virCHMonitorGetInfo(priv->monitor, &info) < 0)
358+
return -1;
359+
360+
virCHProcessUpdateConsole(vm, info);
361+
362+
virJSONValueFree(info);
363+
364+
return 0;
365+
}
366+
303367
/**
304368
* virCHProcessSetupVcpu:
305369
* @vm: domain object
@@ -669,6 +733,8 @@ int virCHProcessStart(virCHDriverPtr driver,
669733

670734
virCHMonitorRefreshThreadInfo(priv->monitor);
671735

736+
virCHProcessUpdateInfo(vm);
737+
672738
if (virCHProcessSetupThreads(vm) < 0)
673739
goto cleanup;
674740

0 commit comments

Comments
 (0)