private EnvelopeType Export(string targetDir, VM vm, Action <float> updatePercentage) { if (vm.power_state != vm_power_state.Halted && vm.power_state != vm_power_state.Suspended) { log.Error($"Cannot export VM {vm.Name()} ({vm.opaque_ref}); it is neither halted nor suspended."); throw new Exception(string.Format(Messages.ERROR_VM_NOT_HALTED, vm.Name())); } log.Info($"Exporting metadata for {vm.name_label}..."); #region CREATE ENVELOPE / ADD VIRTUAL SYSTEM EnvelopeType ovfEnv = OVF.CreateEnvelope(m_applianceFileName); string vsId = OVF.AddVirtualSystem(ovfEnv, vm.name_label); string vhsId = OVF.AddVirtualHardwareSection(ovfEnv, vsId); #endregion #region TRY TO ID OS VM_guest_metrics vmgm = Connection.Resolve(vm.guest_metrics); if (vmgm?.os_version != null && vmgm.os_version.TryGetValue("name", out string osName)) { ushort osId = ValueMaps.OperatingSystem(osName); if (osId == 0xFFFF) { osId = 1; // change to OTHER since search failed. } string version = OVF.GetContentMessage("SECTION_OPERATINGSYSTEM_INFO"); if (vmgm.os_version.TryGetValue("major", out string major) && vmgm.os_version.TryGetValue("minor", out string minor)) { version = string.Format(OVF.GetContentMessage("SECTION_OPERATINGSYSTEM_VERSION"), major, minor); } string[] osNameParts = osName.Split('|'); if (osNameParts.Length > 0) { OVF.UpdateOperatingSystemSection(ovfEnv, vsId, osNameParts[0], version, osId); } } #endregion #region ADD VirtualSystemType identification var pv = vm.IsHVM() ? "hvm" : "xen"; var arch = string.IsNullOrEmpty(vm.domarch) ? "unknown" : vm.domarch; var vmType = string.Format("{0}-3.0-{1}", pv, arch); OVF.AddVirtualSystemSettingData(ovfEnv, vsId, vhsId, vm.name_label, OVF.GetContentMessage("VSSD_CAPTION"), vm.name_description, Guid.NewGuid().ToString(), vmType); #endregion #region ADD CPUS OVF.SetCPUs(ovfEnv, vsId, (ulong)vm.VCPUs_max); #endregion #region ADD MEMORY OVF.SetMemory(ovfEnv, vsId, (ulong)(vm.memory_dynamic_max / Util.BINARY_MEGA), "MB"); #endregion #region ADD NETWORKS foreach (XenRef <VIF> vifRef in vm.VIFs) { VIF vif = Connection.Resolve(vifRef); if (vif == null) { continue; } XenAPI.Network net = Connection.Resolve(vif.network); if (net == null) { continue; } OVF.AddNetwork(ovfEnv, vsId, net.uuid, net.name_label, net.name_description, vif.MAC); } #endregion #region SET STARTUP OPTIONS OVF.AddStartupSection(ovfEnv, true, vsId, vm.order, vm.start_delay, vm.shutdown_delay); #endregion #region EXPORT DISKS int diskIndex = 0; var vbdRefs = vm.VBDs; for (int i = 0; i < vbdRefs.Count; i++) { int curVbd = i; XenRef <VBD> vbdRef = vbdRefs[i]; VBD vbd = Connection.Resolve(vbdRef); if (vbd == null) { continue; } if (vbd.type == vbd_type.CD) { string rasdid = OVF.AddCDROM(ovfEnv, vsId, vbd.uuid, OVF.GetContentMessage("RASD_16_CAPTION"), OVF.GetContentMessage("RASD_16_DESCRIPTION")); OVF.SetTargetDeviceInRASD(ovfEnv, vsId, rasdid, vbd.userdevice); continue; } VDI vdi = Connection.Resolve(vbd.VDI); if (vdi == null) { continue; } try { var diskFilename = $"{vdi.uuid}.vhd"; var diskPath = Path.Combine(targetDir, diskFilename); if (File.Exists(diskPath)) { var oldFileName = diskFilename; diskFilename = $"{vdi.uuid}_{Thread.CurrentThread.ManagedThreadId}.vhd"; diskPath = Path.Combine(targetDir, diskFilename); log.InfoFormat("VHD Name collision, renamed {0} to {1}", oldFileName, diskFilename); } string diskName = vdi.name_label; if (string.IsNullOrEmpty(diskName)) { diskName = $"{OVF.GetContentMessage("RASD_19_CAPTION")} {diskIndex}"; } if (!MetaDataOnly) { log.Info($"Exporting disk {diskName} to {diskFilename} for {vm.name_label}..."); var taskRef = Task.create(Connection.Session, "export_raw_vdi_task", $"Exporting VDI {vdi.uuid} to {diskFilename}"); HTTP_actions.get_export_raw_vdi(b => { Description = string.Format(Messages.EXPORTING_VDI, diskName, diskFilename, Util.DiskSizeString(b, 2, "F2"), Util.DiskSizeString(vdi.virtual_size)); updatePercentage((curVbd + (float)b / vdi.virtual_size) / vbdRefs.Count); }, () => Cancelling, XenAdminConfigManager.Provider.GetProxyTimeout(true), Connection.Hostname, XenAdminConfigManager.Provider.GetProxyFromSettings(Connection), diskPath, taskRef, Connection.Session.opaque_ref, vdi.uuid, "vhd"); if (m_shouldVerify) { Description = string.Format(Messages.EXPORTING_VDI_VERIFICATION, diskFilename); using (var stream = new FileStream(diskPath, FileMode.Open, FileAccess.Read)) using (var sw = new StringWriter()) { var vhdChecker = new FileChecker(stream); var result = vhdChecker.Check(sw, ReportLevels.All); log.InfoFormat("Verifying disk {0}:\n{1}", diskFilename, sw.ToString().Replace("\0", "")); if (!result) { throw new Exception(string.Format(Messages.EXPORTING_VDI_VERIFICATION_FAILURE, diskFilename)); } } } } string diskId = Guid.NewGuid().ToString(); OVF.AddDisk(ovfEnv, vsId, diskId, diskFilename, vbd.bootable, diskName, vdi.name_description, (ulong)vdi.physical_utilisation, (ulong)vdi.virtual_size); OVF.SetTargetDeviceInRASD(ovfEnv, vsId, diskId, vbd.userdevice); diskIndex++; } catch (HTTP.CancelledException) { throw new CancelledException(); } } #endregion #region ADD XEN SPECIFICS var _params = vm.HVM_boot_params; if (_params != null && _params.Count > 0) { OVF.AddOtherSystemSettingData(ovfEnv, vsId, "HVM_boot_params", string.Join(";", _params.Select(kvp => string.Format("{0}={1}", kvp.Key, kvp.Value))), OVF.GetContentMessage("OTHER_SYSTEM_SETTING_DESCRIPTION_6")); } if (!string.IsNullOrEmpty(vm.HVM_boot_policy)) { OVF.AddOtherSystemSettingData(ovfEnv, vsId, "HVM_boot_policy", vm.HVM_boot_policy, OVF.GetContentMessage("OTHER_SYSTEM_SETTING_DESCRIPTION_2")); } if (vm.HVM_shadow_multiplier != 1.0) { OVF.AddOtherSystemSettingData(ovfEnv, vsId, "HVM_shadow_multiplier", Convert.ToString(vm.HVM_shadow_multiplier), OVF.GetContentMessage("OTHER_SYSTEM_SETTING_DESCRIPTION_1")); } var platform = vm.platform; if (platform != null && platform.Count > 0) { OVF.AddOtherSystemSettingData(ovfEnv, vsId, "platform", string.Join(";", platform.Select(kvp => string.Format("{0}={1}", kvp.Key, kvp.Value))), OVF.GetContentMessage("OTHER_SYSTEM_SETTING_DESCRIPTION_3")); } var nvram = vm.NVRAM; if (nvram != null && nvram.Count > 0) { OVF.AddOtherSystemSettingData(ovfEnv, vsId, "NVRAM", string.Join(";", nvram.Select(kvp => string.Format("{0}={1}", kvp.Key, kvp.Value))), OVF.GetContentMessage("OTHER_SYSTEM_SETTING_DESCRIPTION_7")); } if (!string.IsNullOrEmpty(vm.PV_args)) { OVF.AddOtherSystemSettingData(ovfEnv, vsId, "PV_args", vm.PV_args, OVF.GetContentMessage("OTHER_SYSTEM_SETTING_DESCRIPTION_1")); } if (!string.IsNullOrEmpty(vm.PV_bootloader)) { OVF.AddOtherSystemSettingData(ovfEnv, vsId, "PV_bootloader", vm.PV_bootloader, OVF.GetContentMessage("OTHER_SYSTEM_SETTING_DESCRIPTION_1")); } if (!string.IsNullOrEmpty(vm.PV_bootloader_args)) { OVF.AddOtherSystemSettingData(ovfEnv, vsId, "PV_bootloader_args", vm.PV_bootloader_args, OVF.GetContentMessage("OTHER_SYSTEM_SETTING_DESCRIPTION_1")); } if (!string.IsNullOrEmpty(vm.PV_kernel)) { OVF.AddOtherSystemSettingData(ovfEnv, vsId, "PV_kernel", vm.PV_kernel, OVF.GetContentMessage("OTHER_SYSTEM_SETTING_DESCRIPTION_1")); } if (!string.IsNullOrEmpty(vm.PV_legacy_args)) { OVF.AddOtherSystemSettingData(ovfEnv, vsId, "PV_legacy_args", vm.PV_legacy_args, OVF.GetContentMessage("OTHER_SYSTEM_SETTING_DESCRIPTION_1")); } if (!string.IsNullOrEmpty(vm.PV_ramdisk)) { OVF.AddOtherSystemSettingData(ovfEnv, vsId, "PV_ramdisk", vm.PV_ramdisk, OVF.GetContentMessage("OTHER_SYSTEM_SETTING_DESCRIPTION_1")); } if (vm.hardware_platform_version >= 0) { OVF.AddOtherSystemSettingData(ovfEnv, vsId, "hardware_platform_version", vm.hardware_platform_version.ToString(), OVF.GetContentMessage("OTHER_SYSTEM_SETTING_DESCRIPTION_1")); } if (!string.IsNullOrEmpty(vm.recommendations)) { OVF.AddOtherSystemSettingData(ovfEnv, vsId, "recommendations", vm.recommendations.ToString(), OVF.GetContentMessage("OTHER_SYSTEM_SETTING_DESCRIPTION_1")); } if (vm.has_vendor_device) { //serialise it with a different name to avoid it being deserialised automatically and getting the wrong type OVF.AddOtherSystemSettingData(ovfEnv, vsId, "VM_has_vendor_device", vm.has_vendor_device.ToString(), OVF.GetContentMessage("OTHER_SYSTEM_SETTING_DESCRIPTION_1")); } foreach (XenRef <VGPU> gpuRef in vm.VGPUs) { VGPU vgpu = Connection.Resolve(gpuRef); if (vgpu != null) { var vgpuGroup = Connection.Resolve(vgpu.GPU_group); var vgpuType = Connection.Resolve(vgpu.type); var sb = new StringBuilder(); sb.AppendFormat("GPU_types={{{0}}};", vgpuGroup?.GPU_types == null || vgpuGroup.GPU_types.Length < 1 ? "" : string.Join(";", vgpuGroup.GPU_types)); sb.AppendFormat("VGPU_type_vendor_name={0};", vgpuType?.vendor_name ?? ""); sb.AppendFormat("VGPU_type_model_name={0};", vgpuType?.model_name ?? ""); OVF.AddOtherSystemSettingData(ovfEnv, vsId, "vgpu", sb.ToString(), OVF.GetContentMessage("OTHER_SYSTEM_SETTING_DESCRIPTION_4"), true); } } string pvsSiteUuid = string.Empty; var allProxies = Connection.Cache.PVS_proxies; foreach (var p in allProxies.Where(p => p != null && p.VIF != null)) { var vif = Connection.Resolve(p.VIF); if (vif != null) { var vmFromVif = Connection.Resolve(vif.VM); if (vmFromVif != null && vmFromVif.uuid == vm.uuid) { var pvsSite = Connection.Resolve(p.site); if (pvsSite != null) { pvsSiteUuid = pvsSite.uuid; } break; } } } if (!string.IsNullOrEmpty(pvsSiteUuid)) { var sb = new StringBuilder(); sb.AppendFormat("PVS_SITE={{{0}}};", string.Format("uuid={0}", pvsSiteUuid)); OVF.AddOtherSystemSettingData(ovfEnv, vsId, "pvssite", sb.ToString(), OVF.GetContentMessage("OTHER_SYSTEM_SETTING_DESCRIPTION_5")); } #endregion OVF.FinalizeEnvelope(ovfEnv); return(ovfEnv); }
protected override void DoRun() { if (!_dontCheck.IsPresent) { using (Stream s = new FileStream(_vhdFile.Value, FileMode.Open, FileAccess.Read)) { FileChecker vhdChecker = new FileChecker(s); if (!vhdChecker.Check(Console.Out, ReportLevels.All)) { Console.WriteLine("Aborting: Invalid VHD file"); Environment.Exit(1); } } } using (DiskImageFile vhdFile = new DiskImageFile(_vhdFile.Value, FileAccess.Read)) { DiskImageFileInfo info = vhdFile.Information; FileInfo fileInfo = new FileInfo(_vhdFile.Value); Console.WriteLine("File Info"); Console.WriteLine("---------"); Console.WriteLine(" File Name: {0}", fileInfo.FullName); Console.WriteLine(" File Size: {0} bytes", fileInfo.Length); Console.WriteLine(" File Creation Time: {0} (UTC)", fileInfo.CreationTimeUtc); Console.WriteLine(" File Write Time: {0} (UTC)", fileInfo.LastWriteTimeUtc); Console.WriteLine(); Console.WriteLine("Common Disk Info"); Console.WriteLine("-----------------"); Console.WriteLine(" Cookie: {0:x8}", info.Cookie); Console.WriteLine(" Features: {0:x8}", info.Features); Console.WriteLine(" File Format Version: {0}.{1}", ((info.FileFormatVersion >> 16) & 0xFFFF), (info.FileFormatVersion & 0xFFFF)); Console.WriteLine(" Creation Time: {0} (UTC)", info.CreationTimestamp); Console.WriteLine(" Creator App: {0:x8}", info.CreatorApp); Console.WriteLine(" Creator Version: {0}.{1}", ((info.CreatorVersion >> 16) & 0xFFFF), (info.CreatorVersion & 0xFFFF)); Console.WriteLine(" Creator Host OS: {0}", info.CreatorHostOS); Console.WriteLine(" Original Size: {0} bytes", info.OriginalSize); Console.WriteLine(" Current Size: {0} bytes", info.CurrentSize); Console.WriteLine(" Geometry (C/H/S): {0}", info.Geometry); Console.WriteLine(" Disk Type: {0}", info.DiskType); Console.WriteLine(" Checksum: {0:x8}", info.FooterChecksum); Console.WriteLine(" Unique Id: {0}", info.UniqueId); Console.WriteLine(" Saved State: {0}", info.SavedState); Console.WriteLine(); if (info.DiskType == FileType.Differencing || info.DiskType == FileType.Dynamic) { Console.WriteLine(); Console.WriteLine("Dynamic Disk Info"); Console.WriteLine("-----------------"); Console.WriteLine(" Cookie: {0}", info.DynamicCookie); Console.WriteLine(" Header Version: {0}.{1}", ((info.DynamicHeaderVersion >> 16) & 0xFFFF), (info.DynamicHeaderVersion & 0xFFFF)); Console.WriteLine(" Block Count: {0}", info.DynamicBlockCount); Console.WriteLine(" Block Size: {0} bytes", info.DynamicBlockSize); Console.WriteLine(" Checksum: {0:x8}", info.DynamicChecksum); Console.WriteLine(" Parent Unique Id: {0}", info.DynamicParentUniqueId); Console.WriteLine(" Parent Write Time: {0} (UTC)", info.DynamicParentTimestamp); Console.WriteLine(" Parent Name: {0}", info.DynamicParentUnicodeName); Console.Write(" Parent Locations: "); foreach (string parentLocation in info.DynamicParentLocators) { Console.Write("{0}\n ", parentLocation); } Console.WriteLine(); } } }