Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Data Exchange est un service d’intégration (également appelé échange de paire clé-valeur ou KVP) qui peut être utilisé pour partager de petites informations entre une machine virtuelle (invité) et son hôte Hyper-V. Les informations générales sur la machine virtuelle et l’hôte sont automatiquement créées et stockées en tant que paires clé-valeur. Vous pouvez également créer vos propres paires pour partager des données personnalisées.
Les paires clé-valeur se composent d’une « clé » et d’une « valeur ». Les deux sont des chaînes ; aucun autre type de données n’est pris en charge. Lorsqu’une paire clé-valeur est créée ou modifiée, elle devient visible à la fois pour l’invité et l’hôte. Les données KVP se déplacent sur le Hyper-V VMbus et ne nécessitent aucune connectivité réseau entre l’invité et l’hôte.
Une fois créées, les paires clé-valeur restent jusqu’à ce qu’elles soient supprimées. Toute application qui crée des paires clé-valeur doit les supprimer lorsqu’elles ne sont plus nécessaires. Les paires clé-valeur se déplacent avec la machine virtuelle pendant la migration dynamique.
Systèmes invités Windows
Sur les invités Windows, les données KVP sont stockées dans le registre sous :
HKLM\SOFTWARE\Microsoft\Virtual Machine
Les données sont organisées dans ces sous-clés :
- Machine virtuelle\Auto : données décrivant l’invité. Créés par des pilotes de service d’intégration après leur chargement. Visible par l’hôte en tant que données intrinsèques.
- Machine virtuelle\Externe : données envoyées à l’invité à partir de l’hôte par un utilisateur.
- Machine virtuelle\Invité : données créées sur l’invité. Visible par l’hôte en tant que données non intrinsèques.
- Machine virtuelle\Système invité\Paramètre : données transmises au système invité par l'hôte et qui décrivent l’hôte.
L’ajout de valeurs à partir de l’invité est aussi simple que la création d’une nouvelle valeur de chaîne sous HKLM\SOFTWARE\Microsoft\Virtual Machine\Guest. Vous devez être administrateur dans le système invité pour modifier cet emplacement. Vous pouvez utiliser WMI (PowerShell ou d’autres outils) à partir de l’hôte ou d’une machine distante (avec des autorisations) pour récupérer la valeur.
Pour plus d’informations sur les limites de taille du Registre, consultez l’article (hérité) Limites de taille des éléments de Registre.
Ajouter une nouvelle paire clé-valeur dans l’invité
Dans cet exemple, la valeur de Status est définie sur Ready:
$regPath = "HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest"
Set-ItemProperty -Path $regPath -Name "Status" -Value "Ready" -Type String
Vous pouvez utiliser la même syntaxe pour modifier la valeur.
Interroger des paires clé-valeur dans le système invité
Pour interroger la valeur de la sous-clé externe (données envoyées à l’invité à partir de l’hôte) :
$regPath = "HKLM:\SOFTWARE\Microsoft\Virtual Machine\External"
Get-ItemProperty -Path $regPath -Name "Name"
Invités Linux
Linux n’a pas de registre, donc les éléments KVP sont stockés dans le système de fichiers. Un processus démon, doit hv_kvp_daemonêtre en cours d’exécution pour gérer le traitement. Pour la plupart des distributions avec Linux Integration Services (LIS) ou des pilotes in-kernel installés, ce démon démarre automatiquement. Dans certains cas, des étapes supplémentaires peuvent être nécessaires pour installer et démarrer le démon.
Les services d’intégration Linux implémentent l’échange de données avec des pools KVP. Un pool KVP est un fichier stocké dans un chemin spécifique. Il existe quatre fichiers de pool :
/var/lib/hyperv/.kvp_pool_0
/var/lib/hyperv/.kvp_pool_1
/var/lib/hyperv/.kvp_pool_2
/var/lib/hyperv/.kvp_pool_3
Ces fichiers de pool correspondent aux jeux de clés de Registre Windows suivants :
- Pool 0 :
Virtual Machine\External - Pool 1 :
Virtual Machine\Guest - Pool 2 :
Virtual Machine\Auto - Pool 3 :
Virtual Machine\Guest\Parameter
Note
Pour plus d’informations sur la prise en charge du KVP Linux, consultez Linux et FreeBSD Virtual Machines on Hyper-V.
L’infrastructure de paire clé-valeur peut ne pas fonctionner correctement sans une mise à jour logicielle Linux. Contactez votre fournisseur de distribution pour obtenir une mise à jour si vous rencontrez des problèmes.
Structure du pool
Chaque fichier de pool contient des enregistrements avec cette structure :
struct kvp_record
{
unsigned char key[ HV_KVP_EXCHANGE_MAK_KEY_SIZE ];
unsigned char value[ HV_KVP_EXCHANGE_MAX_VALUE_SIZE ];
};
Ces constantes de taille sont définies dans hyperv.h (un en-tête de noyau distribué avec les sources du noyau Linux).
Lire et afficher des valeurs à partir du pool 0
Cet exemple lit les valeurs KVP du pool 0 et les affiche.
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include "../include/linux/hyperv.h"
typedef struct kvp_record
{
unsigned char key [HV_KVP_EXCHANGE_MAX_KEY_SIZE];
unsigned char value [HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
} KVP_RECORD;
KVP_RECORD myRecords[200];
void KVPAcquireLock(int fd)
{
struct flock fl = {F_RDLCK, SEEK_SET, 0, 0, 0};
fl.l_pid = getpid();
if (-1 == fcntl(fd, F_SETLKW, &fl))
{
perror("fcntl lock");
exit (-10);
}
}
void KVPReleaseLock(int fd)
{
struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
fl.l_pid = getpid();
if (-1 == fcntl(fd, F_SETLK, &fl))
{
perror("fcntl unlock");
exit (-20);
}
}
int main (int argc, char **argv)
{
char poolName[] = "/var/lib/hyperv/.kvp_pool_0";
int i;
int fd;
int bytesRead;
int numRecords;
fd = open(poolName, O_RDONLY);
if (-1 == fd)
{
printf("Error: Unable to open pool file %s\n", poolName);
exit (-30);
}
KVPAcquireLock(fd);
bytesRead = read(fd, myRecords, sizeof(myRecords));
KVPReleaseLock(fd);
numRecords = bytesRead / sizeof(struct kvp_record);
printf("Number of records : %d\n", numRecords);
for (i = 0; i < numRecords; i++)
{
printf(" Key : %s\n Value: %s\n\n", myRecords[i].key, myRecords[i].value);
}
close(fd);
return 0;
}
Créer un élément KVP dans le pool 1
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include "../include/linux/hyperv.h"
typedef struct kvp_record
{
unsigned char key [HV_KVP_EXCHANGE_MAX_KEY_SIZE];
unsigned char value [HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
} KVP_RECORD;
void KVPAcquireWriteLock(int fd)
{
struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
fl.l_pid = getpid();
if (-1 == fcntl(fd, F_SETLKW, &fl))
{
perror("fcntl lock");
exit (-10);
}
}
void KVPReleaseLock(int fd)
{
struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
fl.l_pid = getpid();
if (-1 == fcntl(fd, F_SETLK, &fl))
{
perror("fcntl unlock");
exit (-20);
}
}
int main (int argc, char **argv)
{
char poolName[] = "/var/lib/hyperv/.kvp_pool_1";
int fd;
KVP_RECORD newKvp;
if (3 != argc)
{
printf("Usage: WritePool keyName valueString\n\n");
exit (-5);
}
fd = open(poolName, O_WRONLY);
if (-1 == fd)
{
printf("Error: Unable to open pool file %s\n", poolName);
exit (-30);
}
memset((void *)&newKvp, 0, sizeof(KVP_RECORD));
memcpy(newKvp.key, argv[1], strlen(argv[1]));
memcpy(newKvp.value, argv[2], strlen(argv[2]));
KVPAcquireWriteLock(fd);
write(fd, (void *)&newKvp, sizeof(KVP_RECORD));
KVPReleaseLock(fd);
close(fd);
return 0;
}
Supprimer un élément KVP du pool 1
Cet exemple supprime un élément.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <uapi/linux/hyperv.h>
typedef struct kvp_record
{
unsigned char key [HV_KVP_EXCHANGE_MAX_KEY_SIZE];
unsigned char value [HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
} KVP_RECORD;
void KVPAcquireWriteLock(int fd)
{
struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
fl.l_pid = getpid();
if (-1 == fcntl(fd, F_SETLKW, &fl))
{
perror("fcntl lock");
exit (-10);
}
}
void KVPReleaseLock(int fd)
{
struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
fl.l_pid = getpid();
if (-1 == fcntl(fd, F_SETLK, &fl))
{
perror("fcntl unlock");
exit (-20);
}
}
int find_record_offset(int fd, char *key)
{
int bytesRead;
int offset = 0;
int retval = -1;
KVP_RECORD kvpRec;
while (1)
{
lseek(fd, offset, SEEK_SET);
bytesRead = read(fd, &kvpRec, sizeof(KVP_RECORD));
if (0 == bytesRead)
{
break;
}
if (0 == strcmp(key, (const char *) kvpRec.key))
{
retval = offset;
break;
}
offset += sizeof(KVP_RECORD);
}
return retval;
}
int main (int argc, char **argv)
{
char poolName[] = "/var/lib/hyperv/.kvp_pool_1";
int fd;
int exitVal = -1;
int bytesRead;
int bytesWritten;
int offset_to_delete;
int offset_last_record;
KVP_RECORD kvpRec;
if (2 != argc)
{
printf("Usage: WritePool keyName valueString\n\n");
exit (-5);
}
fd = open(poolName, O_RDWR, 0644);
if (-1 == fd)
{
printf("Error: Unable to open pool file %s\n", poolName);
exit (-10);
}
KVPAcquireWriteLock(fd);
offset_to_delete = find_record_offset(fd, argv[1]);
if (offset_to_delete < 0)
{
exitVal = -15;
goto cleanup2;
}
offset_last_record = lseek(fd, -sizeof(KVP_RECORD), SEEK_END);
if (offset_last_record < 0)
{
exitVal = -20;
goto cleanup2;
}
if (offset_last_record != offset_to_delete)
{
lseek(fd, offset_last_record, SEEK_SET);
bytesRead = read(fd, &kvpRec, sizeof(KVP_RECORD));
lseek(fd, offset_to_delete, SEEK_SET);
bytesWritten = write(fd, &kvpRec, sizeof(KVP_RECORD));
}
ftruncate(fd, offset_last_record);
exitVal = 0;
cleanup2:
KVPReleaseLock(fd);
cleanup1:
close(fd);
return exitVal;
}
Utilisation de paires clé-valeur depuis l'hôte à l’aide de WMI
Les exemples suivants utilisent l’espace de noms WMI v2. Pour WMI v1 (versions antérieures), supprimez le \v2 segment du chemin d’accès de l’espace de noms.
Note
Si vous utilisez Windows 8 ou Windows 8.1, installez le client Hyper-V pour obtenir les espaces de noms.
Lire la valeur depuis le serveur
Cet exemple obtient la valeur de la clé à partir d’une machine Status virtuelle nommée Vm1:
$vm = Get-WmiObject -Namespace root\virtualization\v2 -Class \
Msvm_ComputerSystem -Filter {ElementName = 'Vm1'}
$vm.GetRelated("Msvm_KvpExchangeComponent").GuestExchangeItems | % { \
$GuestExchangeItemXml = ([XML]$_).SelectSingleNode(\
"/INSTANCE/PROPERTY[@NAME='Name']/VALUE[child::text() = 'Status']")
if ($GuestExchangeItemXml -ne $null)
{
$GuestExchangeItemXml.SelectSingleNode(\
"/INSTANCE/PROPERTY[@NAME='Data']/VALUE/child::text()" ).Value
}
}
Ajouter ou modifier des paires clé-valeur à partir de l’hôte
Pour ajouter une paire clé-valeur à partir de l’hôte, obtenez des instances du service de gestion et de la machine virtuelle et créez une instance de Msvm_KvpExchangeDataItem. Lors de la création de la nouvelle instance, spécifiez le Name, Dataet Source (doit être 0). Ensuite, appelez AddKvpItems.
L’interrogation de paires clé-valeur créées par l’hôte est similaire aux requêtes invitées, mais nécessite un tronçon d’association supplémentaire vers Msvm_KvpExchangeComponentSettingData. La modification et la suppression de valeurs fonctionnent de la même façon : spécifiez le même nom de clé et appelez la méthode Modify ou Remove appropriée.
Important
Les exemples ci-dessous utilisent l’espace de noms v2. Si vous utilisez Windows Server 2008 ou Windows Server 2008 R2, supprimez le \v2 segment.
Ajouter une nouvelle paire clé-valeur
$VmMgmt = Get-WmiObject -Namespace root\virtualization\v2 -Class \
Msvm_VirtualSystemManagementService
$vm = Get-WmiObject -Namespace root\virtualization\v2 -Class \
Msvm_ComputerSystem -Filter {ElementName='VM1'}
$kvpDataItem = ([WMIClass][String]::Format("\\{0}\\{1}:{2}", \
$VmMgmt.ClassPath.Server, \
$VmMgmt.ClassPath.NamespacePath, \
"Msvm_KvpExchangeDataItem")).CreateInstance()
$kvpDataItem.Name = "Name"
$kvpDataItem.Data = "Data"
$kvpDataItem.Source = 0
$VmMgmt.AddKvpItems($Vm, $kvpDataItem.PSBase.GetText(1))
Interroger des paires clé-valeur sur l’hôte
$VmMgmt = Get-WmiObject -Namespace root\virtualization\v2 -Class \
Msvm_VirtualSystemManagementService
$vm = Get-WmiObject -Namespace root\virtualization\v2 -Class \
Msvm_ComputerSystem -Filter {ElementName='VM1'}
($vm.GetRelated("Msvm_KvpExchangeComponent")[0] ).GetRelated("Msvm_KvpExchangeComponentSettingData").HostExchangeItems | % { \
$GuestExchangeItemXml = ([XML]$_).SelectSingleNode(\
"/INSTANCE/PROPERTY[@NAME='Name']/VALUE[child::text() = 'Name2']")
if ($GuestExchangeItemXml -ne $null)
{
$GuestExchangeItemXml.SelectSingleNode(\
"/INSTANCE/PROPERTY[@NAME='Data']/VALUE/child::text()" ).Value
}
}
Modifier une paire clé-valeur
$VmMgmt = Get-WmiObject -Namespace root\virtualization\v2 -Class \
Msvm_VirtualSystemManagementService
$vm = Get-WmiObject -Namespace root\virtualization\v2 -Class \
Msvm_ComputerSystem -Filter {ElementName='VM1'}
$kvpDataItem = ([WMIClass][String]::Format("\\{0}\\{1}:{2}", \
$VmMgmt.ClassPath.Server, \
$VmMgmt.ClassPath.NamespacePath, \
"Msvm_KvpExchangeDataItem")).CreateInstance()
$kvpDataItem.Name = "Name"
$kvpDataItem.Data = "Data2"
$kvpDataItem.Source = 0
$VmMgmt.ModifyKvpItems($Vm, $kvpDataItem.PSBase.GetText(1))
Supprimer une paire clé-valeur
$VmMgmt = Get-WmiObject -Namespace root\virtualization\v2 -Class \
Msvm_VirtualSystemManagementService
$vm = Get-WmiObject -Namespace root\virtualization\v2 -Class \
Msvm_ComputerSystem -Filter {ElementName='VM1'}
$kvpDataItem = ([WMIClass][String]::Format("\\{0}\\{1}:{2}", \
$VmMgmt.ClassPath.Server, \
$VmMgmt.ClassPath.NamespacePath, \
"Msvm_KvpExchangeDataItem")).CreateInstance()
$kvpDataItem.Name = "Name"
$kvpDataItem.Data = [String]::Empty
$kvpDataItem.Source = 0
$VmMgmt.RemoveKvpItems($Vm, $kvpDataItem.PSBase.GetText(1))