render / rpms / libvirt

Forked from rpms/libvirt 9 months ago
Clone
e6dfe8
From 00b89ea9a9e0713ed663c4426f1f4f2e44d846b6 Mon Sep 17 00:00:00 2001
e6dfe8
Message-Id: <00b89ea9a9e0713ed663c4426f1f4f2e44d846b6@dist-git>
e6dfe8
From: Pino Toscano <ptoscano@redhat.com>
e6dfe8
Date: Thu, 12 Apr 2018 17:26:21 +0200
e6dfe8
Subject: [PATCH] vmx: convert any amount of NICs
e6dfe8
MIME-Version: 1.0
e6dfe8
Content-Type: text/plain; charset=UTF-8
e6dfe8
Content-Transfer-Encoding: 8bit
e6dfe8
e6dfe8
Scan the parsed VMX file, and gather the biggest index of the network
e6dfe8
interfaces there: this way, it is possible to parse all the available
e6dfe8
network interfaces, instead of just 4 maximum.
e6dfe8
e6dfe8
Add the VMX file attached to RHBZ#1560917 as testcase esx-in-the-wild-8.
e6dfe8
e6dfe8
https://bugzilla.redhat.com/show_bug.cgi?id=1560917
e6dfe8
e6dfe8
Signed-off-by: Pino Toscano <ptoscano@redhat.com>
e6dfe8
(cherry picked from commit 5c744a2d445c01fdb9d83a9c3857ba6c0091d834)
e6dfe8
e6dfe8
https://bugzilla.redhat.com/show_bug.cgi?id=1566524
e6dfe8
e6dfe8
Signed-off-by: Pino Toscano <ptoscano@redhat.com>
e6dfe8
Reviewed-by: Ján Tomko <jtomko@redhat.com>
e6dfe8
---
e6dfe8
 src/vmx/vmx.c                                 |  43 ++++-
e6dfe8
 .../vmx2xmldata/vmx2xml-esx-in-the-wild-8.vmx | 163 ++++++++++++++++++
e6dfe8
 .../vmx2xmldata/vmx2xml-esx-in-the-wild-8.xml |  89 ++++++++++
e6dfe8
 tests/vmx2xmltest.c                           |   1 +
e6dfe8
 4 files changed, 288 insertions(+), 8 deletions(-)
e6dfe8
 create mode 100644 tests/vmx2xmldata/vmx2xml-esx-in-the-wild-8.vmx
e6dfe8
 create mode 100644 tests/vmx2xmldata/vmx2xml-esx-in-the-wild-8.xml
e6dfe8
e6dfe8
diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c
e6dfe8
index 3433f39d5c..2afb2e9b34 100644
e6dfe8
--- a/src/vmx/vmx.c
e6dfe8
+++ b/src/vmx/vmx.c
e6dfe8
@@ -1286,6 +1286,36 @@ virVMXGatherSCSIControllers(virVMXContext *ctx, virDomainDefPtr def,
e6dfe8
     return result;
e6dfe8
 }
e6dfe8
 
e6dfe8
+struct virVMXConfigScanResults {
e6dfe8
+    int networks_max_index;
e6dfe8
+};
e6dfe8
+
e6dfe8
+static int
e6dfe8
+virVMXConfigScanResultsCollector(const char* name,
e6dfe8
+                                 virConfValuePtr value ATTRIBUTE_UNUSED,
e6dfe8
+                                 void *opaque)
e6dfe8
+{
e6dfe8
+    struct virVMXConfigScanResults *results = opaque;
e6dfe8
+
e6dfe8
+    if (STRCASEPREFIX(name, "ethernet")) {
e6dfe8
+        unsigned int idx;
e6dfe8
+        char *p;
e6dfe8
+
e6dfe8
+        if (virStrToLong_uip(name + 8, &p, 10, &idx) < 0 ||
e6dfe8
+            *p != '.') {
e6dfe8
+            virReportError(VIR_ERR_INTERNAL_ERROR,
e6dfe8
+                           _("failed to parse the index of the VMX key '%s'"),
e6dfe8
+                           name);
e6dfe8
+            return -1;
e6dfe8
+        }
e6dfe8
+
e6dfe8
+        if ((int) idx > results->networks_max_index)
e6dfe8
+            results->networks_max_index = (int) idx;
e6dfe8
+    }
e6dfe8
+
e6dfe8
+    return 0;
e6dfe8
+}
e6dfe8
+
e6dfe8
 
e6dfe8
 
e6dfe8
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
e6dfe8
@@ -1322,6 +1352,7 @@ virVMXParseConfig(virVMXContext *ctx,
e6dfe8
     bool hgfs_disabled = true;
e6dfe8
     long long sharedFolder_maxNum = 0;
e6dfe8
     int cpumasklen;
e6dfe8
+    struct virVMXConfigScanResults results = { -1 };
e6dfe8
 
e6dfe8
     if (ctx->parseFileName == NULL) {
e6dfe8
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
e6dfe8
@@ -1357,6 +1388,9 @@ virVMXParseConfig(virVMXContext *ctx,
e6dfe8
             goto cleanup;
e6dfe8
     }
e6dfe8
 
e6dfe8
+    if (virConfWalk(conf, virVMXConfigScanResultsCollector, &results) < 0)
e6dfe8
+        goto cleanup;
e6dfe8
+
e6dfe8
     /* Allocate domain def */
e6dfe8
     if (!(def = virDomainDefNew()))
e6dfe8
         goto cleanup;
e6dfe8
@@ -1751,7 +1785,7 @@ virVMXParseConfig(virVMXContext *ctx,
e6dfe8
     }
e6dfe8
 
e6dfe8
     /* def:nets */
e6dfe8
-    for (controller = 0; controller < 4; ++controller) {
e6dfe8
+    for (controller = 0; controller <= results.networks_max_index; ++controller) {
e6dfe8
         virDomainNetDefPtr net = NULL;
e6dfe8
         if (virVMXParseEthernet(conf, controller, &net) < 0)
e6dfe8
             goto cleanup;
e6dfe8
@@ -2539,13 +2573,6 @@ virVMXParseEthernet(virConfPtr conf, int controller, virDomainNetDefPtr *def)
e6dfe8
         return -1;
e6dfe8
     }
e6dfe8
 
e6dfe8
-    if (controller < 0 || controller > 3) {
e6dfe8
-        virReportError(VIR_ERR_INTERNAL_ERROR,
e6dfe8
-                       _("Ethernet controller index %d out of [0..3] range"),
e6dfe8
-                       controller);
e6dfe8
-        return -1;
e6dfe8
-    }
e6dfe8
-
e6dfe8
     snprintf(prefix, sizeof(prefix), "ethernet%d", controller);
e6dfe8
 
e6dfe8
     VMX_BUILD_NAME(present);
e6dfe8
diff --git a/tests/vmx2xmldata/vmx2xml-esx-in-the-wild-8.vmx b/tests/vmx2xmldata/vmx2xml-esx-in-the-wild-8.vmx
e6dfe8
new file mode 100644
e6dfe8
index 0000000000..1e3dbf23ce
e6dfe8
--- /dev/null
e6dfe8
+++ b/tests/vmx2xmldata/vmx2xml-esx-in-the-wild-8.vmx
e6dfe8
@@ -0,0 +1,163 @@
e6dfe8
+.encoding = "UTF-8"
e6dfe8
+config.version = "8"
e6dfe8
+virtualHW.version = "11"
e6dfe8
+vmci0.present = "TRUE"
e6dfe8
+svga.vramSize = "8388608"
e6dfe8
+memSize = "2048"
e6dfe8
+sched.cpu.units = "mhz"
e6dfe8
+tools.upgrade.policy = "manual"
e6dfe8
+scsi0.virtualDev = "pvscsi"
e6dfe8
+scsi0.present = "TRUE"
e6dfe8
+sata0.present = "TRUE"
e6dfe8
+sata0:0.deviceType = "cdrom-image"
e6dfe8
+sata0:0.fileName = "/vmfs/volumes/692eb778-2d4937fe/CentOS-4.7.ServerCD-x86_64.iso"
e6dfe8
+sata0:0.present = "TRUE"
e6dfe8
+scsi0:0.deviceType = "scsi-hardDisk"
e6dfe8
+scsi0:0.fileName = "RHEL7_6.vmdk"
e6dfe8
+sched.scsi0:0.shares = "normal"
e6dfe8
+scsi0:0.present = "TRUE"
e6dfe8
+floppy0.startConnected = "FALSE"
e6dfe8
+floppy0.clientDevice = "TRUE"
e6dfe8
+floppy0.fileName = "vmware-null-remote-floppy"
e6dfe8
+ethernet0.virtualDev = "vmxnet3"
e6dfe8
+ethernet0.networkName = "VM Network"
e6dfe8
+ethernet0.addressType = "static"
e6dfe8
+ethernet0.address = "00:1a:4a:16:01:55"
e6dfe8
+ethernet0.present = "TRUE"
e6dfe8
+displayName = "RHEL7_10_NICs"
e6dfe8
+guestOS = "rhel7-64"
e6dfe8
+toolScripts.afterPowerOn = "TRUE"
e6dfe8
+toolScripts.afterResume = "TRUE"
e6dfe8
+toolScripts.beforeSuspend = "TRUE"
e6dfe8
+toolScripts.beforePowerOff = "TRUE"
e6dfe8
+tools.syncTime = "FALSE"
e6dfe8
+messageBus.tunnelEnabled = "FALSE"
e6dfe8
+uuid.bios = "42 35 94 20 99 dc 42 61-52 64 ba 58 dd ae 20 e4"
e6dfe8
+vc.uuid = "50 35 1d e6 7d 56 29 ab-9d 72 c7 f9 ea 3f cf d0"
e6dfe8
+sched.cpu.latencySensitivity = "normal"
e6dfe8
+tools.guest.desktop.autolock = "FALSE"
e6dfe8
+nvram = "RHEL7_6.nvram"
e6dfe8
+pciBridge0.present = "TRUE"
e6dfe8
+svga.present = "TRUE"
e6dfe8
+pciBridge4.present = "TRUE"
e6dfe8
+pciBridge4.virtualDev = "pcieRootPort"
e6dfe8
+pciBridge4.functions = "8"
e6dfe8
+pciBridge5.present = "TRUE"
e6dfe8
+pciBridge5.virtualDev = "pcieRootPort"
e6dfe8
+pciBridge5.functions = "8"
e6dfe8
+pciBridge6.present = "TRUE"
e6dfe8
+pciBridge6.virtualDev = "pcieRootPort"
e6dfe8
+pciBridge6.functions = "8"
e6dfe8
+pciBridge7.present = "TRUE"
e6dfe8
+pciBridge7.virtualDev = "pcieRootPort"
e6dfe8
+pciBridge7.functions = "8"
e6dfe8
+hpet0.present = "true"
e6dfe8
+sched.scsi0:0.throughputCap = "off"
e6dfe8
+ethernet0.uptCompatibility = "TRUE"
e6dfe8
+ethernet0.pciSlotNumber = "192"
e6dfe8
+monitor.phys_bits_used = "42"
e6dfe8
+pciBridge0.pciSlotNumber = "17"
e6dfe8
+pciBridge4.pciSlotNumber = "21"
e6dfe8
+pciBridge5.pciSlotNumber = "22"
e6dfe8
+pciBridge6.pciSlotNumber = "23"
e6dfe8
+pciBridge7.pciSlotNumber = "24"
e6dfe8
+replay.supported = "false"
e6dfe8
+sata0.pciSlotNumber = "33"
e6dfe8
+scsi0.pciSlotNumber = "160"
e6dfe8
+scsi0.sasWWID = "50 05 05 60 99 dc 42 60"
e6dfe8
+softPowerOff = "FALSE"
e6dfe8
+virtualHW.productCompatibility = "hosted"
e6dfe8
+vmci0.pciSlotNumber = "32"
e6dfe8
+vmotion.checkpointFBSize = "8388608"
e6dfe8
+vmotion.checkpointSVGAPrimarySize = "8388608"
e6dfe8
+tools.remindInstall = "FALSE"
e6dfe8
+toolsInstallManager.lastInstallError = "0"
e6dfe8
+toolsInstallManager.updateCounter = "1"
e6dfe8
+migrate.hostlog = "RHEL7_6-2a23b979.hlog"
e6dfe8
+sched.cpu.min = "0"
e6dfe8
+sched.cpu.shares = "normal"
e6dfe8
+sched.mem.min = "0"
e6dfe8
+sched.mem.minSize = "0"
e6dfe8
+sched.mem.shares = "normal"
e6dfe8
+scsi0:1.deviceType = "scsi-hardDisk"
e6dfe8
+scsi0:1.fileName = "RHEL7_6_1.vmdk"
e6dfe8
+scsi0:1.mode = "independent-nonpersistent"
e6dfe8
+sched.scsi0:1.shares = "normal"
e6dfe8
+sched.scsi0:1.throughputCap = "off"
e6dfe8
+scsi0:1.present = "TRUE"
e6dfe8
+scsi0:2.deviceType = "scsi-hardDisk"
e6dfe8
+scsi0:2.fileName = "/vmfs/volumes/5669422e-699d77db-c144-00e0815e303e/block4/block4.vmdk"
e6dfe8
+sched.scsi0:2.shares = "normal"
e6dfe8
+sched.scsi0:2.throughputCap = "off"
e6dfe8
+scsi0:2.present = "TRUE"
e6dfe8
+numvcpus = "8"
e6dfe8
+cpuid.coresPerSocket = "2"
e6dfe8
+sched.swap.derivedName = "/vmfs/volumes/29dcc8ec-e8d62d3b-0000-000000000000/RHEL7_6/RHEL7_6-05efff7d.vswp"
e6dfe8
+uuid.location = "56 4d d9 db b7 4e df ce-58 6a 77 56 82 53 aa 18"
e6dfe8
+replay.filename = ""
e6dfe8
+scsi0:2.redo = ""
e6dfe8
+scsi0:1.redo = ""
e6dfe8
+scsi0:0.redo = ""
e6dfe8
+vmci0.id = "-575790876"
e6dfe8
+cleanShutdown = "TRUE"
e6dfe8
+ethernet1.virtualDev = "e1000"
e6dfe8
+ethernet1.networkName = "VM Network"
e6dfe8
+ethernet1.addressType = "vpx"
e6dfe8
+ethernet1.generatedAddress = "00:1a:4a:16:21:85"
e6dfe8
+ethernet1.present = "TRUE"
e6dfe8
+ethernet2.virtualDev = "e1000e"
e6dfe8
+ethernet2.networkName = "VM Network"
e6dfe8
+ethernet2.addressType = "vpx"
e6dfe8
+ethernet2.generatedAddress = "00:1a:4a:16:21:82"
e6dfe8
+ethernet2.present = "TRUE"
e6dfe8
+ethernet3.virtualDev = "vmxnet3"
e6dfe8
+ethernet3.networkName = "VM Network"
e6dfe8
+ethernet3.addressType = "vpx"
e6dfe8
+ethernet3.generatedAddress = "00:1a:4a:16:21:69"
e6dfe8
+ethernet3.uptCompatibility = "TRUE"
e6dfe8
+ethernet3.present = "TRUE"
e6dfe8
+ethernet4.virtualDev = "vmxnet3"
e6dfe8
+ethernet4.networkName = "VM Network"
e6dfe8
+ethernet4.addressType = "vpx"
e6dfe8
+ethernet4.generatedAddress = "00:1a:4a:16:21:80"
e6dfe8
+ethernet4.uptCompatibility = "TRUE"
e6dfe8
+ethernet4.present = "TRUE"
e6dfe8
+ethernet5.virtualDev = "vmxnet3"
e6dfe8
+ethernet5.networkName = "VM Network"
e6dfe8
+ethernet5.addressType = "vpx"
e6dfe8
+ethernet5.generatedAddress = "00:1a:4a:16:21:a3"
e6dfe8
+ethernet5.uptCompatibility = "TRUE"
e6dfe8
+ethernet5.present = "TRUE"
e6dfe8
+ethernet6.virtualDev = "vmxnet3"
e6dfe8
+ethernet6.networkName = "VM Network"
e6dfe8
+ethernet6.addressType = "vpx"
e6dfe8
+ethernet6.generatedAddress = "00:1a:4a:16:21:a8"
e6dfe8
+ethernet6.uptCompatibility = "TRUE"
e6dfe8
+ethernet6.present = "TRUE"
e6dfe8
+ethernet7.virtualDev = "vmxnet3"
e6dfe8
+ethernet7.networkName = "VM Network"
e6dfe8
+ethernet7.addressType = "vpx"
e6dfe8
+ethernet7.generatedAddress = "00:1a:4a:16:21:a9"
e6dfe8
+ethernet7.uptCompatibility = "TRUE"
e6dfe8
+ethernet7.present = "TRUE"
e6dfe8
+ethernet8.virtualDev = "vmxnet3"
e6dfe8
+ethernet8.networkName = "VM Network"
e6dfe8
+ethernet8.addressType = "vpx"
e6dfe8
+ethernet8.generatedAddress = "00:1a:4a:16:21:78"
e6dfe8
+ethernet8.uptCompatibility = "TRUE"
e6dfe8
+ethernet8.present = "TRUE"
e6dfe8
+ethernet9.virtualDev = "vmxnet3"
e6dfe8
+ethernet9.networkName = "VM Network"
e6dfe8
+ethernet9.addressType = "vpx"
e6dfe8
+ethernet9.generatedAddress = "00:1a:4a:16:21:81"
e6dfe8
+ethernet9.uptCompatibility = "TRUE"
e6dfe8
+ethernet9.present = "TRUE"
e6dfe8
+ethernet1.pciSlotNumber = "34"
e6dfe8
+ethernet2.pciSlotNumber = "224"
e6dfe8
+ethernet3.pciSlotNumber = "256"
e6dfe8
+ethernet4.pciSlotNumber = "1184"
e6dfe8
+ethernet5.pciSlotNumber = "1216"
e6dfe8
+ethernet6.pciSlotNumber = "1248"
e6dfe8
+ethernet7.pciSlotNumber = "1280"
e6dfe8
+ethernet8.pciSlotNumber = "2208"
e6dfe8
+ethernet9.pciSlotNumber = "2240"
e6dfe8
diff --git a/tests/vmx2xmldata/vmx2xml-esx-in-the-wild-8.xml b/tests/vmx2xmldata/vmx2xml-esx-in-the-wild-8.xml
e6dfe8
new file mode 100644
e6dfe8
index 0000000000..c85ccf3649
e6dfe8
--- /dev/null
e6dfe8
+++ b/tests/vmx2xmldata/vmx2xml-esx-in-the-wild-8.xml
e6dfe8
@@ -0,0 +1,89 @@
e6dfe8
+<domain type='vmware'>
e6dfe8
+  <name>RHEL7_10_NICs</name>
e6dfe8
+  <uuid>42359420-99dc-4261-5264-ba58ddae20e4</uuid>
e6dfe8
+  <memory unit='KiB'>2097152</memory>
e6dfe8
+  <currentMemory unit='KiB'>2097152</currentMemory>
e6dfe8
+  <vcpu placement='static'>8</vcpu>
e6dfe8
+  <cputune>
e6dfe8
+    <shares>8000</shares>
e6dfe8
+  </cputune>
e6dfe8
+  <os>
e6dfe8
+    <type arch='x86_64'>hvm</type>
e6dfe8
+  </os>
e6dfe8
+  <clock offset='utc'/>
e6dfe8
+  <on_poweroff>destroy</on_poweroff>
e6dfe8
+  <on_reboot>restart</on_reboot>
e6dfe8
+  <on_crash>destroy</on_crash>
e6dfe8
+  <devices>
e6dfe8
+    <disk type='file' device='disk'>
e6dfe8
+      <source file='[datastore] directory/RHEL7_6.vmdk'/>
e6dfe8
+      <target dev='sda' bus='scsi'/>
e6dfe8
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
e6dfe8
+    </disk>
e6dfe8
+    <disk type='file' device='disk'>
e6dfe8
+      <source file='[datastore] directory/RHEL7_6_1.vmdk'/>
e6dfe8
+      <target dev='sdb' bus='scsi'/>
e6dfe8
+      <transient/>
e6dfe8
+      <address type='drive' controller='0' bus='0' target='0' unit='1'/>
e6dfe8
+    </disk>
e6dfe8
+    <disk type='file' device='disk'>
e6dfe8
+      <source file='[5669422e-699d77db-c144-00e0815e303e] block4/block4.vmdk'/>
e6dfe8
+      <target dev='sdc' bus='scsi'/>
e6dfe8
+      <address type='drive' controller='0' bus='0' target='0' unit='2'/>
e6dfe8
+    </disk>
e6dfe8
+    <controller type='scsi' index='0' model='vmpvscsi'/>
e6dfe8
+    <interface type='bridge'>
e6dfe8
+      <mac address='00:1a:4a:16:01:55'/>
e6dfe8
+      <source bridge='VM Network'/>
e6dfe8
+      <model type='vmxnet3'/>
e6dfe8
+    </interface>
e6dfe8
+    <interface type='bridge'>
e6dfe8
+      <mac address='00:1a:4a:16:21:85'/>
e6dfe8
+      <source bridge='VM Network'/>
e6dfe8
+      <model type='e1000'/>
e6dfe8
+    </interface>
e6dfe8
+    <interface type='bridge'>
e6dfe8
+      <mac address='00:1a:4a:16:21:82'/>
e6dfe8
+      <source bridge='VM Network'/>
e6dfe8
+      <model type='e1000e'/>
e6dfe8
+    </interface>
e6dfe8
+    <interface type='bridge'>
e6dfe8
+      <mac address='00:1a:4a:16:21:69'/>
e6dfe8
+      <source bridge='VM Network'/>
e6dfe8
+      <model type='vmxnet3'/>
e6dfe8
+    </interface>
e6dfe8
+    <interface type='bridge'>
e6dfe8
+      <mac address='00:1a:4a:16:21:80'/>
e6dfe8
+      <source bridge='VM Network'/>
e6dfe8
+      <model type='vmxnet3'/>
e6dfe8
+    </interface>
e6dfe8
+    <interface type='bridge'>
e6dfe8
+      <mac address='00:1a:4a:16:21:a3'/>
e6dfe8
+      <source bridge='VM Network'/>
e6dfe8
+      <model type='vmxnet3'/>
e6dfe8
+    </interface>
e6dfe8
+    <interface type='bridge'>
e6dfe8
+      <mac address='00:1a:4a:16:21:a8'/>
e6dfe8
+      <source bridge='VM Network'/>
e6dfe8
+      <model type='vmxnet3'/>
e6dfe8
+    </interface>
e6dfe8
+    <interface type='bridge'>
e6dfe8
+      <mac address='00:1a:4a:16:21:a9'/>
e6dfe8
+      <source bridge='VM Network'/>
e6dfe8
+      <model type='vmxnet3'/>
e6dfe8
+    </interface>
e6dfe8
+    <interface type='bridge'>
e6dfe8
+      <mac address='00:1a:4a:16:21:78'/>
e6dfe8
+      <source bridge='VM Network'/>
e6dfe8
+      <model type='vmxnet3'/>
e6dfe8
+    </interface>
e6dfe8
+    <interface type='bridge'>
e6dfe8
+      <mac address='00:1a:4a:16:21:81'/>
e6dfe8
+      <source bridge='VM Network'/>
e6dfe8
+      <model type='vmxnet3'/>
e6dfe8
+    </interface>
e6dfe8
+    <video>
e6dfe8
+      <model type='vmvga' vram='8192' primary='yes'/>
e6dfe8
+    </video>
e6dfe8
+  </devices>
e6dfe8
+</domain>
e6dfe8
diff --git a/tests/vmx2xmltest.c b/tests/vmx2xmltest.c
e6dfe8
index 00385dfa71..fd0d9fbea4 100644
e6dfe8
--- a/tests/vmx2xmltest.c
e6dfe8
+++ b/tests/vmx2xmltest.c
e6dfe8
@@ -268,6 +268,7 @@ mymain(void)
e6dfe8
     DO_TEST("esx-in-the-wild-5", "esx-in-the-wild-5");
e6dfe8
     DO_TEST("esx-in-the-wild-6", "esx-in-the-wild-6");
e6dfe8
     DO_TEST("esx-in-the-wild-7", "esx-in-the-wild-7");
e6dfe8
+    DO_TEST("esx-in-the-wild-8", "esx-in-the-wild-8");
e6dfe8
 
e6dfe8
     DO_TEST("gsx-in-the-wild-1", "gsx-in-the-wild-1");
e6dfe8
     DO_TEST("gsx-in-the-wild-2", "gsx-in-the-wild-2");
e6dfe8
-- 
e6dfe8
2.17.0
e6dfe8