mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-10-22 05:59:18 +00:00
virsh: Add support for modifying domain description and titles
This patch adds a new command "desc" to show and modify titles and description for the domains using the new API. This patch also adds a new flag for the "list" command to show titles in the domain list, to allow easy identification of VMs by storing a short description. Example: virsh # list --title Id Name State Title ----------------------------------------------- 0 Domain-0 running Mailserver 1 2 fedora paused
This commit is contained in:
parent
c471e55e10
commit
fad5cd2108
257
tools/virsh.c
257
tools/virsh.c
@ -313,6 +313,9 @@ static int vshCommandOptULongLong(const vshCmd *cmd, const char *name,
|
|||||||
static bool vshCommandOptBool(const vshCmd *cmd, const char *name);
|
static bool vshCommandOptBool(const vshCmd *cmd, const char *name);
|
||||||
static const vshCmdOpt *vshCommandOptArgv(const vshCmd *cmd,
|
static const vshCmdOpt *vshCommandOptArgv(const vshCmd *cmd,
|
||||||
const vshCmdOpt *opt);
|
const vshCmdOpt *opt);
|
||||||
|
static char *vshGetDomainDescription(vshControl *ctl, virDomainPtr dom,
|
||||||
|
bool title, unsigned int flags)
|
||||||
|
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
||||||
|
|
||||||
#define VSH_BYID (1 << 1)
|
#define VSH_BYID (1 << 1)
|
||||||
#define VSH_BYUUID (1 << 2)
|
#define VSH_BYUUID (1 << 2)
|
||||||
@ -886,6 +889,7 @@ static const vshCmdOptDef opts_list[] = {
|
|||||||
{"all", VSH_OT_BOOL, 0, N_("list inactive & active domains")},
|
{"all", VSH_OT_BOOL, 0, N_("list inactive & active domains")},
|
||||||
{"managed-save", VSH_OT_BOOL, 0,
|
{"managed-save", VSH_OT_BOOL, 0,
|
||||||
N_("mark domains with managed save state")},
|
N_("mark domains with managed save state")},
|
||||||
|
{"title", VSH_OT_BOOL, 0, N_("show short domain description")},
|
||||||
{NULL, 0, 0, NULL}
|
{NULL, 0, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -900,7 +904,10 @@ cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
|
|||||||
char **names = NULL;
|
char **names = NULL;
|
||||||
int maxname = 0;
|
int maxname = 0;
|
||||||
bool managed = vshCommandOptBool(cmd, "managed-save");
|
bool managed = vshCommandOptBool(cmd, "managed-save");
|
||||||
|
bool desc = vshCommandOptBool(cmd, "title");
|
||||||
|
char *title;
|
||||||
int state;
|
int state;
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
inactive |= all;
|
inactive |= all;
|
||||||
|
|
||||||
@ -918,8 +925,7 @@ cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
|
|||||||
|
|
||||||
if ((maxid = virConnectListDomains(ctl->conn, &ids[0], maxid)) < 0) {
|
if ((maxid = virConnectListDomains(ctl->conn, &ids[0], maxid)) < 0) {
|
||||||
vshError(ctl, "%s", _("Failed to list active domains"));
|
vshError(ctl, "%s", _("Failed to list active domains"));
|
||||||
VIR_FREE(ids);
|
goto cleanup;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qsort(&ids[0], maxid, sizeof(int), idsorter);
|
qsort(&ids[0], maxid, sizeof(int), idsorter);
|
||||||
@ -929,24 +935,27 @@ cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
|
|||||||
maxname = virConnectNumOfDefinedDomains(ctl->conn);
|
maxname = virConnectNumOfDefinedDomains(ctl->conn);
|
||||||
if (maxname < 0) {
|
if (maxname < 0) {
|
||||||
vshError(ctl, "%s", _("Failed to list inactive domains"));
|
vshError(ctl, "%s", _("Failed to list inactive domains"));
|
||||||
VIR_FREE(ids);
|
goto cleanup;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (maxname) {
|
if (maxname) {
|
||||||
names = vshMalloc(ctl, sizeof(char *) * maxname);
|
names = vshMalloc(ctl, sizeof(char *) * maxname);
|
||||||
|
|
||||||
if ((maxname = virConnectListDefinedDomains(ctl->conn, names, maxname)) < 0) {
|
if ((maxname = virConnectListDefinedDomains(ctl->conn, names, maxname)) < 0) {
|
||||||
vshError(ctl, "%s", _("Failed to list inactive domains"));
|
vshError(ctl, "%s", _("Failed to list inactive domains"));
|
||||||
VIR_FREE(ids);
|
goto cleanup;
|
||||||
VIR_FREE(names);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qsort(&names[0], maxname, sizeof(char*), namesorter);
|
qsort(&names[0], maxname, sizeof(char*), namesorter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (desc) {
|
||||||
|
vshPrintExtra(ctl, "%-5s %-30s %-10s %s\n", _("Id"), _("Name"), _("State"), _("Title"));
|
||||||
|
vshPrintExtra(ctl, "-----------------------------------------------------------\n");
|
||||||
|
} else {
|
||||||
vshPrintExtra(ctl, " %-5s %-30s %s\n", _("Id"), _("Name"), _("State"));
|
vshPrintExtra(ctl, " %-5s %-30s %s\n", _("Id"), _("Name"), _("State"));
|
||||||
vshPrintExtra(ctl, "----------------------------------------------------\n");
|
vshPrintExtra(ctl, "----------------------------------------------------\n");
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < maxid; i++) {
|
for (i = 0; i < maxid; i++) {
|
||||||
virDomainPtr dom = virDomainLookupByID(ctl->conn, ids[i]);
|
virDomainPtr dom = virDomainLookupByID(ctl->conn, ids[i]);
|
||||||
@ -955,10 +964,22 @@ cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
|
|||||||
if (!dom)
|
if (!dom)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (desc) {
|
||||||
|
if (!(title = vshGetDomainDescription(ctl, dom, true, 0)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
vshPrint(ctl, "%-5d %-30s %-10s %s\n",
|
||||||
|
virDomainGetID(dom),
|
||||||
|
virDomainGetName(dom),
|
||||||
|
_(vshDomainStateToString(vshDomainState(ctl, dom, NULL))),
|
||||||
|
title);
|
||||||
|
VIR_FREE(title);
|
||||||
|
} else {
|
||||||
vshPrint(ctl, " %-5d %-30s %s\n",
|
vshPrint(ctl, " %-5d %-30s %s\n",
|
||||||
virDomainGetID(dom),
|
virDomainGetID(dom),
|
||||||
virDomainGetName(dom),
|
virDomainGetName(dom),
|
||||||
_(vshDomainStateToString(vshDomainState(ctl, dom, NULL))));
|
_(vshDomainStateToString(vshDomainState(ctl, dom, NULL))));
|
||||||
|
}
|
||||||
virDomainFree(dom);
|
virDomainFree(dom);
|
||||||
}
|
}
|
||||||
for (i = 0; i < maxname; i++) {
|
for (i = 0; i < maxname; i++) {
|
||||||
@ -975,6 +996,17 @@ cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
|
|||||||
virDomainHasManagedSaveImage(dom, 0) > 0)
|
virDomainHasManagedSaveImage(dom, 0) > 0)
|
||||||
state = -2;
|
state = -2;
|
||||||
|
|
||||||
|
if (desc) {
|
||||||
|
if (!(title = vshGetDomainDescription(ctl, dom, true, 0)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
vshPrint(ctl, "%-5s %-30s %-10s %s\n",
|
||||||
|
"-",
|
||||||
|
names[i],
|
||||||
|
state == -2 ? _("saved") : _(vshDomainStateToString(state)),
|
||||||
|
title);
|
||||||
|
VIR_FREE(title);
|
||||||
|
} else {
|
||||||
vshPrint(ctl, " %-5s %-30s %s\n",
|
vshPrint(ctl, " %-5s %-30s %s\n",
|
||||||
"-",
|
"-",
|
||||||
names[i],
|
names[i],
|
||||||
@ -983,9 +1015,158 @@ cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
|
|||||||
virDomainFree(dom);
|
virDomainFree(dom);
|
||||||
VIR_FREE(names[i]);
|
VIR_FREE(names[i]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
cleanup:
|
||||||
VIR_FREE(ids);
|
VIR_FREE(ids);
|
||||||
VIR_FREE(names);
|
VIR_FREE(names);
|
||||||
return true;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "desc" command for managing domain description and title
|
||||||
|
*/
|
||||||
|
static const vshCmdInfo info_desc[] = {
|
||||||
|
{"help", N_("show or set domain's description or title")},
|
||||||
|
{"desc", N_("Allows to show or modify description or title of a domain.")},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const vshCmdOptDef opts_desc[] = {
|
||||||
|
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
|
||||||
|
{"live", VSH_OT_BOOL, 0, N_("modify/get running state")},
|
||||||
|
{"config", VSH_OT_BOOL, 0, N_("modify/get persistent configuration")},
|
||||||
|
{"current", VSH_OT_BOOL, 0, N_("modify/get current state configuration")},
|
||||||
|
{"title", VSH_OT_BOOL, 0, N_("modify the title instead of description")},
|
||||||
|
{"edit", VSH_OT_BOOL, 0, N_("open an editor to modify the description")},
|
||||||
|
{"new-desc", VSH_OT_ARGV, 0, N_("message")},
|
||||||
|
{NULL, 0, 0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool
|
||||||
|
cmdDesc(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
virDomainPtr dom;
|
||||||
|
bool config = vshCommandOptBool(cmd, "config");
|
||||||
|
bool live = vshCommandOptBool(cmd, "live");
|
||||||
|
/* current is ignored */
|
||||||
|
|
||||||
|
bool title = vshCommandOptBool(cmd, "title");
|
||||||
|
bool edit = vshCommandOptBool(cmd, "edit");
|
||||||
|
|
||||||
|
int state;
|
||||||
|
int type;
|
||||||
|
char *desc = NULL;
|
||||||
|
char *desc_edited = NULL;
|
||||||
|
char *tmp = NULL;
|
||||||
|
char *tmpstr;
|
||||||
|
const vshCmdOpt *opt = NULL;
|
||||||
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||||
|
bool pad = false;
|
||||||
|
bool ret = false;
|
||||||
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
||||||
|
|
||||||
|
if (!vshConnectionUsability(ctl, ctl->conn))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((state = vshDomainState(ctl, dom, NULL)) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
while ((opt = vshCommandOptArgv(cmd, opt))) {
|
||||||
|
if (pad)
|
||||||
|
virBufferAddChar(&buf, ' ');
|
||||||
|
pad = true;
|
||||||
|
virBufferAdd(&buf, opt->data, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (live)
|
||||||
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
||||||
|
if (config)
|
||||||
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
||||||
|
if (title)
|
||||||
|
type = VIR_DOMAIN_METADATA_TITLE;
|
||||||
|
else
|
||||||
|
type = VIR_DOMAIN_METADATA_DESCRIPTION;
|
||||||
|
|
||||||
|
if (virBufferError(&buf)) {
|
||||||
|
vshPrint(ctl, "%s", _("Failed to collect new description/title"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
desc = virBufferContentAndReset(&buf);
|
||||||
|
|
||||||
|
if (edit || desc) {
|
||||||
|
if (!desc) {
|
||||||
|
desc = vshGetDomainDescription(ctl, dom, title,
|
||||||
|
config?VIR_DOMAIN_XML_INACTIVE:0);
|
||||||
|
if (!desc)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (edit) {
|
||||||
|
/* Create and open the temporary file. */
|
||||||
|
if (!(tmp = editWriteToTempFile(ctl, desc)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* Start the editor. */
|
||||||
|
if (editFile(ctl, tmp) == -1)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* Read back the edited file. */
|
||||||
|
if (!(desc_edited = editReadBackFile(ctl, tmp)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* strip a possible newline at the end of file; some
|
||||||
|
* editors enforce a newline, this makes editing the title
|
||||||
|
* more convinient */
|
||||||
|
if (title &&
|
||||||
|
(tmpstr = strrchr(desc_edited, '\n')) &&
|
||||||
|
*(tmpstr+1) == '\0')
|
||||||
|
*tmpstr = '\0';
|
||||||
|
|
||||||
|
/* Compare original XML with edited. Has it changed at all? */
|
||||||
|
if (STREQ(desc, desc_edited)) {
|
||||||
|
vshPrint(ctl, _("Domain description not changed.\n"));
|
||||||
|
ret = true;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
VIR_FREE(desc);
|
||||||
|
desc = desc_edited;
|
||||||
|
desc_edited = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virDomainSetMetadata(dom, type, desc, NULL, NULL, flags) < 0) {
|
||||||
|
vshError(ctl, "%s",
|
||||||
|
_("Failed to set new domain description"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
vshPrint(ctl, "%s", _("Domain description updated successfully"));
|
||||||
|
} else {
|
||||||
|
desc = vshGetDomainDescription(ctl, dom, title,
|
||||||
|
config?VIR_DOMAIN_XML_INACTIVE:0);
|
||||||
|
if (!desc)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (strlen(desc) > 0)
|
||||||
|
vshPrint(ctl, "%s", desc);
|
||||||
|
else
|
||||||
|
vshPrint(ctl, _("No description for domain: %s"),
|
||||||
|
virDomainGetName(dom));
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(desc_edited);
|
||||||
|
VIR_FREE(desc);
|
||||||
|
if (tmp) {
|
||||||
|
unlink(tmp);
|
||||||
|
VIR_FREE(tmp);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -16245,6 +16426,7 @@ static const vshCmdDef domManagementCmds[] = {
|
|||||||
{"cpu-compare", cmdCPUCompare, opts_cpu_compare, info_cpu_compare, 0},
|
{"cpu-compare", cmdCPUCompare, opts_cpu_compare, info_cpu_compare, 0},
|
||||||
{"create", cmdCreate, opts_create, info_create, 0},
|
{"create", cmdCreate, opts_create, info_create, 0},
|
||||||
{"define", cmdDefine, opts_define, info_define, 0},
|
{"define", cmdDefine, opts_define, info_define, 0},
|
||||||
|
{"desc", cmdDesc, opts_desc, info_desc, 0},
|
||||||
{"destroy", cmdDestroy, opts_destroy, info_destroy, 0},
|
{"destroy", cmdDestroy, opts_destroy, info_destroy, 0},
|
||||||
{"detach-device", cmdDetachDevice, opts_detach_device,
|
{"detach-device", cmdDetachDevice, opts_detach_device,
|
||||||
info_detach_device, 0},
|
info_detach_device, 0},
|
||||||
@ -18011,6 +18193,65 @@ vshDomainStateReasonToString(int state, int reason)
|
|||||||
return N_("unknown");
|
return N_("unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* extract description or title from domain xml */
|
||||||
|
static char *
|
||||||
|
vshGetDomainDescription(vshControl *ctl, virDomainPtr dom, bool title,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
char *desc = NULL;
|
||||||
|
char *domxml = NULL;
|
||||||
|
virErrorPtr err = NULL;
|
||||||
|
xmlDocPtr doc = NULL;
|
||||||
|
xmlXPathContextPtr ctxt = NULL;
|
||||||
|
int type;
|
||||||
|
|
||||||
|
if (title)
|
||||||
|
type = VIR_DOMAIN_METADATA_TITLE;
|
||||||
|
else
|
||||||
|
type = VIR_DOMAIN_METADATA_DESCRIPTION;
|
||||||
|
|
||||||
|
if ((desc = virDomainGetMetadata(dom, type, NULL, flags))) {
|
||||||
|
return desc;
|
||||||
|
} else {
|
||||||
|
err = virGetLastError();
|
||||||
|
|
||||||
|
if (err && err->code == VIR_ERR_NO_DOMAIN_METADATA) {
|
||||||
|
desc = vshStrdup(ctl, "");
|
||||||
|
virResetLastError();
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err && err->code != VIR_ERR_NO_SUPPORT)
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fall back to xml */
|
||||||
|
/* get domain's xml description and extract the title/description */
|
||||||
|
if (!(domxml = virDomainGetXMLDesc(dom, flags))) {
|
||||||
|
vshError(ctl, "%s", _("Failed to retrieve domain XML"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
doc = virXMLParseStringCtxt(domxml, _("(domain_definition)"), &ctxt);
|
||||||
|
if (!doc) {
|
||||||
|
vshError(ctl, "%s", _("Couldn't parse domain XML"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (title)
|
||||||
|
desc = virXPathString("string(./title[1])", ctxt);
|
||||||
|
else
|
||||||
|
desc = virXPathString("string(./description[1])", ctxt);
|
||||||
|
|
||||||
|
if (!desc)
|
||||||
|
desc = vshStrdup(ctl, "");
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
VIR_FREE(domxml);
|
||||||
|
xmlXPathFreeContext(ctxt);
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return a non-NULL string representation of a typed parameter; exit
|
/* Return a non-NULL string representation of a typed parameter; exit
|
||||||
* if we are out of memory. */
|
* if we are out of memory. */
|
||||||
static char *
|
static char *
|
||||||
|
@ -279,7 +279,7 @@ The XML also show the NUMA topology information if available.
|
|||||||
|
|
||||||
Inject NMI to the guest.
|
Inject NMI to the guest.
|
||||||
|
|
||||||
=item B<list> [I<--inactive> | I<--all>] [I<--managed-save>]
|
=item B<list> [I<--inactive> | I<--all>] [I<--managed-save>] [I<--title>]
|
||||||
|
|
||||||
Prints information about existing domains. If no options are
|
Prints information about existing domains. If no options are
|
||||||
specified it prints out information about running domains.
|
specified it prints out information about running domains.
|
||||||
@ -350,6 +350,15 @@ If I<--managed-save> is specified, then domains that have managed save
|
|||||||
state (only possible if they are in the B<shut off> state) will
|
state (only possible if they are in the B<shut off> state) will
|
||||||
instead show as B<saved> in the listing.
|
instead show as B<saved> in the listing.
|
||||||
|
|
||||||
|
If I<--title> is specified, then the domain note is printed. The output then
|
||||||
|
the output looks as follows.
|
||||||
|
|
||||||
|
B<virsh> list --note
|
||||||
|
Id Name State Title
|
||||||
|
-----------------------------------------------
|
||||||
|
0 Domain-0 running Mailserver 1
|
||||||
|
2 fedora paused
|
||||||
|
|
||||||
=item B<freecell> [B<cellno> | I<--all>]
|
=item B<freecell> [B<cellno> | I<--all>]
|
||||||
|
|
||||||
Prints the available amount of memory on the machine or within a
|
Prints the available amount of memory on the machine or within a
|
||||||
@ -426,6 +435,29 @@ Define a domain from an XML <file>. The domain definition is registered
|
|||||||
but not started. If domain is already running, the changes will take
|
but not started. If domain is already running, the changes will take
|
||||||
effect on the next boot.
|
effect on the next boot.
|
||||||
|
|
||||||
|
=item B<desc> [I<--live> | I<--config>] [I<--title>] [I<--edit>]
|
||||||
|
[I<--new-desc> New description or title message]
|
||||||
|
|
||||||
|
Show or modify description and title of a domain. These values are user
|
||||||
|
fields that allow to store arbitrary textual data to allow easy
|
||||||
|
identification of domains. Title should be short, although it's not enforced.
|
||||||
|
|
||||||
|
Flags I<--live> or I<--config> select whether this command works on live
|
||||||
|
or persistent definitions of the domain. By default both are influenced, while
|
||||||
|
modifying and running definition is used while reading the note.
|
||||||
|
|
||||||
|
If both I<--live> and I<--config> are specified, the I<--config> option takes
|
||||||
|
precedence on getting the current description and both live configuration
|
||||||
|
and config are updated while setting the description.
|
||||||
|
|
||||||
|
Flag I<--edit> specifies that an editor with the contents of current
|
||||||
|
description or title should be opened and the contents saved back afterwards.
|
||||||
|
|
||||||
|
Flag I<--title> selects operation on the title field instead of description.
|
||||||
|
|
||||||
|
If neither of I<--edit> and I<--new_desc> are specified the note or description
|
||||||
|
is displayed instead of being modified.
|
||||||
|
|
||||||
=item B<destroy> I<domain-id>
|
=item B<destroy> I<domain-id>
|
||||||
|
|
||||||
Immediately terminate the domain domain-id. This doesn't give the domain
|
Immediately terminate the domain domain-id. This doesn't give the domain
|
||||||
|
Loading…
Reference in New Issue
Block a user