示例#1
0
            /// <summary>
            /// Downloads and installs an XVA or OVA virtual machine template, optionally renaming it.
            /// </summary>
            /// <param name="uri">The HTTP or FTP URI for the template file.</param>
            /// <param name="name">The optional template name.</param>
            /// <param name="repositoryNameOrUuid">
            /// Optionally specifies the target storage repository by name or UUID.
            /// This defaults to <b>Local storage</b>.
            /// </param>
            /// <returns>The installed template.</returns>
            /// <exception cref="XenException">Thrown if the operation failed.</exception>
            public XenTemplate Install(string uri, string name = null, string repositoryNameOrUuid = "Local storage")
            {
                Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(uri), nameof(uri));
                Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(repositoryNameOrUuid), nameof(repositoryNameOrUuid));

                if (!Uri.TryCreate(uri, UriKind.Absolute, out var uriParsed))
                {
                    throw new ArgumentException($"[{uri}] is not a valid URI", nameof(uri));
                }

                var sr = client.Repository.GetTargetStorageRepository(repositoryNameOrUuid);

                if (uriParsed.Scheme != "http" && uriParsed.Scheme != "ftp")
                {
                    throw new ArgumentException($"[{uri}] uses an unsupported scheme.  Only [http/ftp] are allowed.", nameof(uri));
                }

                var response = client.SafeInvoke("vm-import", $"url={uri}", $"sr-uuid={sr.Uuid}");
                var uuid     = response.OutputText.Trim();
                var template = Find(uuid: uuid);

                if (!string.IsNullOrEmpty(name))
                {
                    template = Rename(template, name);
                }

                return(template);
            }
示例#2
0
            /// <summary>
            /// <para>
            /// Creates a virtual machine from a template, optionally initializing its memory and
            /// disk size.
            /// </para>
            /// <note>
            /// This does not start the machine.
            /// </note>
            /// </summary>
            /// <param name="name">Name for the new virtual machine.</param>
            /// <param name="templateName">Identifies the template.</param>
            /// <param name="processors">Optionally specifies the number of processors to assign.  This defaults to <b>2</b>.</param>
            /// <param name="memoryBytes">Optionally specifies the memory assigned to the machine (overriding the template).</param>
            /// <param name="diskBytes">Optionally specifies the disk assigned to the machine (overriding the template).</param>
            /// <param name="snapshot">Optionally specifies that the virtual machine should snapshot the template.  This defaults to <c>false</c>.</param>
            /// <param name="extraDrives">
            /// Optionally specifies any additional virtual drives to be created and
            /// then attached to the new virtual machine (e.g. for Ceph OSD).
            /// </param>
            /// <param name="primaryStorageRepository">
            /// Optionally specifies the storage repository where the virtual machine's
            /// primary disk will be created.  This defaults to <b>Local storage</b>.
            /// </param>
            /// <param name="extraStorageRespository">
            /// Optionally specifies the storage repository where any extra drives for
            /// the virtual machine will be created.  This defaults to <b>Local storage</b>.
            /// </param>
            /// <returns>The new <see cref="XenVirtualMachine"/>.</returns>
            /// <exception cref="XenException">Thrown if the operation failed.</exception>
            /// <remarks>
            /// <note>
            /// <paramref name="snapshot"/> is ignored if the virtual machine template is not
            /// hosted by the same storage repository where the virtual machine is to be created.
            /// </note>
            /// </remarks>
            public XenVirtualMachine Create(
                string name,
                string templateName,
                int processors   = 2,
                long memoryBytes = 0,
                long diskBytes   = 0,
                bool snapshot    = false,
                IEnumerable <XenVirtualDrive> extraDrives = null,
                string primaryStorageRepository           = "Local storage",
                string extraStorageRespository            = "Local storage")
            {
                Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(templateName));
                Covenant.Requires <ArgumentException>(processors > 0);
                Covenant.Requires <ArgumentException>(memoryBytes >= 0);
                Covenant.Requires <ArgumentException>(diskBytes >= 0);
                Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(primaryStorageRepository));
                Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(extraStorageRespository));

                if (client.Template.Find(templateName) == null)
                {
                    throw new XenException($"Template [{templateName}] does not exist.");
                }

                // We need to determine whether the VM template is persisted to the same storage
                // repository as the desired target for the VM.  If the storage repos are the same,
                // we won't pass the [sr-uuid] parameter so that XenServer will do a fast clone.
                // This is necessary because the xe command looks like it never does a fast clone
                // when [sr-uuid] is passed, even if the template and target VM storage repositories
                // are the same.
                //
                //      https://github.com/jefflill/NeonForge/issues/326
                //
                // Unfortunately, there doesn't appear to be a clean way to inspect a VM template
                // to list its disks and determine where they live.  So we'll list the virtual disk
                // interfaces and look for the disk named like:
                //
                //      <template-name> 0
                //
                // where <template-name> identifies the template and "0" indicates the disk number.
                //
                // NOTE: This assumes that neonHIVE VM templates have only a single disk, which
                //       will probably always be the case since we only add disks after the VMs
                //       are created.

                var primarySR       = client.Repository.Find(name: primaryStorageRepository, mustExist: true);
                var vdiListResponse = client.InvokeItems("vdi-list");
                var templateVdiName = $"{templateName} 0";
                var templateSrUuid  = (string)null;
                var srUuidArg       = (string)null;

                foreach (var vdiProperties in vdiListResponse.Results)
                {
                    if (vdiProperties["name-label"] == templateVdiName)
                    {
                        templateSrUuid = vdiProperties["sr-uuid"];
                        break;
                    }
                }

                if (!snapshot || templateSrUuid != primarySR.Uuid)
                {
                    srUuidArg = $"sr-uuid={primarySR.Uuid}";
                }

                // Create the VM.

                var vmInstallResponse = client.SafeInvoke("vm-install", $"template={templateName}", $"new-name-label={name}", srUuidArg);
                var uuid = vmInstallResponse.OutputText.Trim();

                // Configure processors

                client.SafeInvoke("vm-param-set",
                                  $"uuid={uuid}",
                                  $"VCPUs-at-startup={processors}",
                                  $"VCPUs-max={processors}");

                // Configure memory.

                if (memoryBytes > 0)
                {
                    client.SafeInvoke("vm-memory-limits-set",
                                      $"uuid={uuid}",
                                      $"dynamic-max={memoryBytes}",
                                      $"dynamic-min={memoryBytes}",
                                      $"static-max={memoryBytes}",
                                      $"static-min={memoryBytes}");
                }

                // Configure the primary disk.

                if (diskBytes > 0)
                {
                    var disks = client.SafeInvokeItems("vm-disk-list", $"uuid={uuid}").Results;
                    var vdi   = disks.FirstOrDefault(items => items.ContainsKey("Disk 0 VDI"));

                    if (vdi == null)
                    {
                        throw new XenException($"Cannot locate disk for [{name}] virtual machine.");
                    }

                    var vdiUuid = vdi["uuid"];

                    client.SafeInvoke("vdi-resize", $"uuid={vdiUuid}", $"disk-size={diskBytes}");
                }

                // Configure any additional disks.

                if (extraDrives != null && extraDrives.Count() > 0)
                {
                    var driveIndex = 1; // The boot device has index=0
                    var extraSR    = client.Repository.Find(name: extraStorageRespository, mustExist: true);

                    foreach (var drive in extraDrives)
                    {
                        client.SafeInvoke("vm-disk-add", $"uuid={uuid}", $"sr-uuid={extraSR.Uuid}", $"disk-size={drive.Size}", $"device={driveIndex}");
                        driveIndex++;
                    }
                }

                return(client.Machine.Find(uuid: uuid));
            }