// TODO: refactor this as InitializationProgress public async Task <Vm> Refresh(VmTemplate template) { string target = template.Name + "#" + template.IsolationTag; Vm vm = await Load(target); if (vm == null) { vm = new Vm() { Name = target, Status = "created" }; int progress = await VerifyDisks(template); if (progress == 100) { vm.Status = "initialized"; } else if (progress >= 0) { vm.Task = new VmTask { Name = "initializing", Progress = progress }; } } //include task return(vm); }
public async Task <Vm> Deploy(VmTemplate template) { var vm = await Load(template.Name + "#" + template.IsolationTag); if (vm != null) { return(vm); } VimClient host = FindHostByAffinity(template.IsolationTag); _logger.LogDebug("deploy: host " + host.Name); NormalizeTemplate(template, host.Options); _logger.LogDebug("deploy: normalized " + template.Name); if (!template.Disks.IsEmpty()) { bool found = await host.FileExists(template.Disks[0].Path); if (!found) { throw new Exception("Template disks have not been prepared."); } } if (!host.Options.Uplink.StartsWith("nsx.")) { _logger.LogDebug("deploy: reserve vlans "); _vlanman.ReserveVlans(template, host.Options.IsVCenter); } _logger.LogDebug("deploy: " + template.Name + " " + host.Name); return(await host.Deploy(template)); }
public async Task <int> CreateDisks(VmTemplate template) { if (template.Disks.Length == 0) { return(-1); } int progress = await VerifyDisks(template); if (progress < 0) { VimClient host = FindHostByRandom(); if (template.Disks[0].Source.HasValue()) { Task cloneTask = host.CloneDisk(template.Id, template.Disks[0].Source, template.Disks[0].Path); progress = 0; } else { await host.CreateDisk(template.Disks[0]); progress = 100; } } return(progress); }
protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); Badge.OnModelCreating(builder); User.OnModelCreating(builder); // module section Module.OnModelCreating(builder); Lab.OnModelCreating(builder); LabVm.OnModelCreating(builder); UserModule.OnModelCreating(builder); // user module section UserModule.OnModelCreating(builder); UserLab.OnModelCreating(builder); UserLabVm.OnModelCreating(builder); // hypervisor Hypervisor.OnModelCreating(builder); HypervisorNode.OnModelCreating(builder); // configure many to many relationship UserUserModule.OnModelCreating(builder); ContactEmail.OnModelCreating(builder); BridgeInstance.OnModelCreating(builder); VmInterfaceTemplate.OnModelCreating(builder); VmInterfaceInstance.OnModelCreating(builder); BridgeTemplate.OnModelCreating(builder); VmTemplate.OnModelCreating(builder); }
public async Task <int> VerifyDisks(VmTemplate template) { await Delay(); NormalizeTemplate(template, _optPod); int progress = -1; VmDisk disk = template.Disks.FirstOrDefault(); if (disk != null) { if (disk.Path.Contains("blank-")) { return(100); } MockDisk mock = _disks.FirstOrDefault(o => o.Path == disk.Path); if (mock == null) { _disks.Add(new MockDisk { CreatedAt = DateTime.Now, Path = disk.Path, Disk = disk }); } progress = 100; // if (mock != null) // { // float elapsed = (int)DateTime.Now.Subtract(mock.CreatedAt).TotalSeconds; // progress = (int) Math.Min(100, (elapsed / 10) * 100); // } } return(progress); }
public TemplateUtility(string detail, string diskname = "placeholder") { if (detail.HasValue()) { _template = JsonSerializer.Deserialize <VmTemplate>(detail, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); } else { diskname = Regex.Replace(diskname, @"[^\w\d]", "-").Replace("--", "-").Trim('-').ToLower(); _template = new VmTemplate { Ram = 4, VideoRam = 0, Cpu = "1x2", Adapters = 1, Eth = new VmNet[] { new VmNet { Net = "lan", Type = "e1000" } }, Disks = new VmDisk[] { new VmDisk { Path = $"[ds] {Guid.Empty.ToString()}/{diskname}.vmdk", Source = "", Controller = "lsilogic", Size = 10 } } }; } }
public async Task <int> CreateDisks(VmTemplate template) { NormalizeTemplate(template, _optPod); string key = template.Name; //template.IsolationTag + "-" + template.Id; Vm vm = (await Find(key)).FirstOrDefault(); if (vm != null) { return(100); } int progress = await VerifyDisks(template); if (progress < 0) { VmDisk disk = template.Disks.First(); // if (!_tasks.ContainsKey(key)) // _tasks.Add(key, new VmTask { // Name = "initializing", // WhenCreated = DateTime.UtcNow, // Id = key // }); _logger.LogDebug("disk: creating " + disk.Path); _disks.Add(new MockDisk { CreatedAt = DateTime.Now, Path = disk.Path, Disk = disk }); } return(progress); }
public async Task <int> UploadVmTemplate( string name, Stream fileStream, long length, Hypervisor hypervisor, VmTemplate vmTemplate, Action <double> callback = null) { var safeFileName = vmTemplate.Id + ".ova"; const string baseDir = "/root/uploads"; var dirName = "VmTemplate_" + vmTemplate.Id; var dirPath = string.Join("/", baseDir, dirName); var filePath = string.Join("/", dirPath, safeFileName); var node = await ProxmoxManager.GetPrimaryHypervisorNode(hypervisor); var api = ProxmoxManager.GetProxmoxApi(node); int vmId; // Upload File using (var sftp = new SftpClient(GetConnectionInfoFromHypervisor(hypervisor))) { sftp.Connect(); try { sftp.CreateDirectory(dirPath); sftp.ChangeDirectory(dirPath); sftp.UploadFile(fileStream, filePath, true, progress => { if (callback != null) { callback((double)progress / length * 100); } }); using (var ssh = new SshClient(GetConnectionInfoFromHypervisor(hypervisor))) { ssh.Connect(); await ExtractOva(ssh, filePath, dirPath); vmId = await CreateVmAndImportDisk(name, ssh, sftp, api, dirPath); var unusedDisk = await api.GetVmUnusedDisk(vmId); await api.SetVmScsi0(vmId, unusedDisk); await api.ConvertVmToTemplate(vmId); ssh.Disconnect(); } Cleanup(sftp, dirPath); } catch (Exception) { Cleanup(sftp, dirPath); throw; } sftp.Disconnect(); } return(vmId); }
public async Task UploadTemplate(DefaultContext context, string name, User user, Stream stream, long length, Action <double> callback = null) { await context.Database.BeginTransactionAsync(); var hypervisor = await context.Hypervisors.FirstOrDefaultAsync(); context.Entry(user).State = EntityState.Unchanged; var vmTemplate = new VmTemplate { Name = name, Owner = user, IsCoreRouter = false, }; context.Add(vmTemplate); await context.SaveChangesAsync(); var templateId = await UploadVmTemplate( name, stream, length, hypervisor, vmTemplate, callback); var primaryHypervisorNode = await ProxmoxManager.GetPrimaryHypervisorNode(hypervisor); vmTemplate.HypervisorVmTemplates = new List <HypervisorVmTemplate> { new HypervisorVmTemplate { HypervisorNode = primaryHypervisorNode, TemplateVmId = templateId } }; await context.SaveChangesAsync(); context.Database.CommitTransaction(); }
public async Task <int> DeleteDisks(VmTemplate template) { if (template.Disks.Length == 0) { return(-1); } int progress = await VerifyDisks(template); if (progress < 0) { return(-1); } if (progress == 100) { VimClient host = FindHostByRandom(); foreach (VmDisk disk in template.Disks) { //protect stock disks; only delete a disk if it is local to the workspace //i.e. the disk folder matches the workspaceId if (template.IsolationTag.HasValue() && disk.Path.Contains(template.IsolationTag)) { Task deleteTask = host.DeleteDisk(disk.Path); } } return(-1); } throw new Exception("Cannot delete disk that isn't fully created."); }
public async Task <Vm> Refresh(VmTemplate template) { Vm vm = null; NormalizeTemplate(template, _optPod); string key = template.Name; //template.IsolationTag + "-" + template.Id; vm = (await Find(key)).FirstOrDefault(); if (vm != null) { vm.Status = "deployed"; //IncludeTask(key, vm); } else { vm = new Vm() { Name = template.Name, Status = "created" }; if (VerifyDisks(template).Result == 100) { vm.Status = "initialized"; } } IncludeTask(key, vm); return(vm); }
private void NormalizeTemplate(VmTemplate template, HypervisorServiceConfiguration option) { if (template.Iso.HasValue() && !template.Iso.StartsWith(option.IsoStore)) { template.Iso = option.IsoStore + template.Iso + ".iso"; } // if (template.Source.HasValue() && !template.Source.StartsWith(option.StockStore)) // { // template.Source = option.StockStore + template.Source + ".vmdk"; // } foreach (VmDisk disk in template.Disks) { if (!disk.Path.StartsWith(option.DiskStore)) { disk.Path = option.DiskStore + disk.Path + ".vmdk"; } } if (template.IsolationTag.HasValue()) { string tag = "#" + template.IsolationTag; Regex rgx = new Regex("#.*"); if (!template.Name.EndsWith(template.IsolationTag)) { template.Name = rgx.Replace(template.Name, "") + tag; } foreach (VmNet eth in template.Eth) { eth.Net = rgx.Replace(eth.Net, "") + tag; } } }
private void NormalizeTemplate(VmTemplate template, HypervisorServiceConfiguration option, bool privileged = false) { if (!template.Iso.HasValue()) { // need to have a backing file to add the cdrom device template.Iso = option.IsoStore + "null.iso"; } var isopath = new DatastorePath(template.Iso); isopath.Merge(option.IsoStore); template.Iso = isopath.ToString(); foreach (VmDisk disk in template.Disks) { if (!disk.Path.StartsWith(option.DiskStore) ) { DatastorePath dspath = new DatastorePath(disk.Path); dspath.Merge(option.DiskStore); disk.Path = dspath.ToString(); } if (disk.Source.HasValue() && !disk.Source.StartsWith(option.DiskStore) ) { DatastorePath dspath = new DatastorePath(disk.Source); dspath.Merge(option.DiskStore); disk.Source = dspath.ToString(); } } if (template.IsolationTag.HasValue()) { string tag = "#" + template.IsolationTag; Regex rgx = new Regex("#.*"); if (!template.Name.EndsWith(template.IsolationTag)) { template.Name = rgx.Replace(template.Name, "") + tag; } foreach (VmNet eth in template.Eth) { if (privileged && _vlanman.Contains(eth.Net)) { continue; } eth.Net = rgx.Replace(eth.Net, "") + tag; } } }
public static VmTemplate SetHostAffinity(this VmTemplate template, bool requireHostAffinity) { template.HostAffinity = requireHostAffinity; if (requireHostAffinity) { template.AutoStart = false; } return(template); }
public virtual void ReserveVlans(VmTemplate template, bool UseUplinkSwitch) { lock (_vlanMap) { foreach (VmNet eth in template.Eth) { //if net already reserved, use reserved vlan if (_vlans.ContainsKey(eth.Net)) { eth.Vlan = _vlans[eth.Net].Id; } else { int id = 0; if (UseUplinkSwitch) { //get available uplink vlan while (id < _vlanMap.Length && _vlanMap[id]) { id += 1; } if (id > 0 && id < _vlanMap.Length) { eth.Vlan = id; _vlanMap[id] = true; _vlans.Add(eth.Net, new Vlan { Name = eth.Net, Id = id, OnUplink = true }); } else { throw new Exception("Unable to reserve a vlan for " + eth.Net); } } else { //get highest vlan in this isolation group id = 100; foreach (string key in _vlans.Keys.Where(k => k.EndsWith(template.IsolationTag))) { id = Math.Max(id, _vlans[key].Id); } id += 1; eth.Vlan = id; _vlans.Add(eth.Net, new Vlan { Name = eth.Net, Id = id }); } } } } }
public async Task <ActionResult <Vm> > Resolve(int id) { VmTemplate template = await _templateService.GetDeployableTemplate(id, null); Vm vm = await _pod.Refresh(template); if (vm != null) { await AuthorizeAction(vm, "resolve"); } return(Ok(vm)); }
public async Task Provision(VmTemplate template) { await Task.Delay(0); lock (_pgAllocation) { string sw = _client.UplinkSwitch; if (_client.dvs == null && _client.net != null && !template.UseUplinkSwitch) { sw = template.IsolationTag.ToSwitchName(); if (!_swAllocation.ContainsKey(sw)) { AddSwitch(sw).Wait(); _swAllocation.Add(sw, 0); } } foreach (VmNet eth in template.Eth) { if (!_pgAllocation.ContainsKey(eth.Net)) { var pg = AddPortGroup(sw, eth).Result; pg.Counter = 1; _pgAllocation.Add(pg.Net, pg); if (pg.VlanId > 0) { _vlanManager.Activate(new Vlan[] { new Vlan { Id = pg.VlanId, Name = pg.Net, OnUplink = sw == _client.UplinkSwitch } }); } if (_swAllocation.ContainsKey(sw)) { _swAllocation[sw] += 1; } } else { _pgAllocation[eth.Net].Counter += 1; } eth.Key = _pgAllocation[eth.Net].Key; } } }
public async Task <Vm> Deploy(VmTemplate template) { Vm vm = null; await Connect(); _logger.LogDebug("deploy: validate portgroups..."); await _netman.Provision(template); _logger.LogDebug("deploy: transform template..."); //var transformer = new VCenterTransformer { DVSuuid = _dvsuuid }; VirtualMachineConfigSpec vmcs = Transform.TemplateToVmSpec( template, _config.VmStore.Replace("{host}", _hostPrefix), _dvsuuid ); _logger.LogDebug("deploy: create vm..."); ManagedObjectReference task = await _vim.CreateVM_TaskAsync(_vms, vmcs, _pool, null); TaskInfo info = await WaitForVimTask(task); if (info.state == TaskInfoState.success) { _logger.LogDebug("deploy: load vm..."); await Task.Delay(200); vm = await GetVirtualMachine((ManagedObjectReference)info.result); _logger.LogDebug("deploy: create snapshot..."); task = await _vim.CreateSnapshot_TaskAsync( vm.AsVim(), "Root Snap", "Created by TopoMojo Deploy at " + DateTime.UtcNow.ToString("s") + "Z", false, false); info = await WaitForVimTask(task); if (template.AutoStart && info.state == TaskInfoState.success) { _logger.LogDebug("deploy: start vm..."); vm = await Start(vm.Id); } } else { throw new Exception(info.error.localizedMessage); } return(vm); }
public async Task <ActionResult <Vm> > InitializeVmTemplate(string id) { VmTemplate template = await _templateService.GetDeployableTemplate(id, null); string name = $"{template.Name}#{template.IsolationTag}"; AuthorizeAny( () => Actor.IsAdmin, () => CanManageVm(name, Actor.Id).Result ); return(Ok( await _pod.CreateDisks(template) )); }
public static OptionValue[] GetExtraConfig(VmTemplate template) { List <OptionValue> options = new List <OptionValue>(); options.Add(new OptionValue { key = "snapshot.redoNotWithParent", value = "true" }); options.Add(new OptionValue { key = "isolation.tools.setGUIOptions.enable", value = "true" }); options.Add(new OptionValue { key = "isolation.tools.copy.disable", value = "false" }); options.Add(new OptionValue { key = "isolation.tools.paste.disable", value = "false" }); options.Add(new OptionValue { key = "keyboard.typematicMinDelay", value = "2000000" }); options.Add(new OptionValue { key = "guestinfo.isolationTag", value = template.IsolationTag }); options.Add(new OptionValue { key = "guestinfo.templateSource", value = template.Id }); options.Add(new OptionValue { key = "guestinfo.hostname", value = template.Name.Untagged() }); foreach (var setting in template.GuestSettings) { // TODO: rework this quick fix for injecting isolation specific settings if (setting.Key.StartsWith("iftag.") && !setting.Value.Contains(template.IsolationTag)) { continue; } var option = new OptionValue { key = setting.Key, value = setting.Value }; option.key = option.key.Replace("iftag.", "guestinfo."); options.Add(option); } return(options.ToArray()); }
public async Task <int> CreateDisksOld(VmTemplate template) { int progress = await VerifyDisks(template); if (progress < 0) { VmDisk disk = template.Disks.First(); _logger.LogDebug("disk: creating " + disk.Path); _disks.Add(new MockDisk { CreatedAt = DateTime.Now, Path = disk.Path, Disk = disk }); } return(0); }
public async Task <ActionResult <Vm> > Deploy(int id) { VmTemplate template = await _templateService.GetDeployableTemplate(id, null); Vm vm = await _pod.Deploy(template); // SendBroadcast(vm, "deploy"); VmState state = new VmState { Id = id.ToString(), Name = vm.Name.Untagged(), IsRunning = vm.State == VmPowerState.Running }; await _hub.Clients.Group(vm.Name.Tag()).VmEvent(new BroadcastEvent <VmState>(User, "VM.DEPLOY", state)); return(Ok(vm)); }
public async Task <ActionResult <Vm> > DeployVm(string id) { VmTemplate template = await _templateService .GetDeployableTemplate(id, null) ; string name = $"{template.Name}#{template.IsolationTag}"; AuthorizeAny( () => Actor.IsAdmin, () => CanManageVm(name, Actor.Id).Result ); Vm vm = await _pod.Deploy(template, Actor.IsBuilder); if (template.HostAffinity) { await _pod.SetAffinity( template.IsolationTag, new Vm[] { vm }, true ); vm.State = VmPowerState.Running; } // SendBroadcast(vm, "deploy"); VmState state = new VmState { Id = template.Id.ToString(), Name = vm.Name.Untagged(), IsolationId = vm.Name.Tag(), IsRunning = vm.State == VmPowerState.Running }; await Hub.Clients .Group(state.IsolationId) .VmEvent(new BroadcastEvent <VmState>(User, "VM.DEPLOY", state)) ; return(Ok(vm)); }
public async Task <Vm> Deploy(VmTemplate template) { NormalizeTemplate(template, _optPod); string key = template.Name; //string key = template.IsolationTag + "-" + template.Id; Vm vm = null; if (!_vms.ContainsKey(key)) { if (template.Disks.Length > 0) { if (template.Disks[0].Path.Contains("blank")) { throw new Exception("Disks have not been prepared"); } if (VerifyDisks(template).Result != 100) { throw new Exception("Disks have not been prepared."); } } await Delay(); vm = new Vm { Id = Guid.NewGuid().ToString(), Name = template.Name, Path = "[mock] pod/vm", Status = "deployed" }; _logger.LogDebug($"deployed vm {vm.Name}"); _vms.Add(vm.Id, vm); } else { vm = _vms[key]; vm.Status = "deployed"; _logger.LogDebug($"vm {vm.Name} already deployed"); } return(vm); }
public async Task <int> DeleteDisks(VmTemplate template) { int progress = await VerifyDisks(template); if (progress < 0) { return(-1); } if (progress == 100) { VmDisk disk = template.Disks.First(); MockDisk mock = _disks.FirstOrDefault(o => o.Path == disk.Path); if (mock != null) { _logger.LogDebug("disk: deleting " + disk.Path); _disks.Remove(mock); return(-1); } } throw new Exception("Cannot delete disk that isn't fully created."); }
public async Task <int> VerifyDisks(VmTemplate template) { if (template.Disks.Length == 0) { return(100); //show good if no disks to verify } foreach (VimClient vhost in _hostCache.Values) { int progress = await vhost.TaskProgress(template.Id); if (progress >= 0) { return(progress); } } // string pattern = @"blank-(\d+)([^\.]+)"; // Match match = Regex.Match(template.Disks[0].Path, pattern); // if (match.Success) // { // return 100; //show blank disk as created // } VimClient host = FindHostByRandom(); NormalizeTemplate(template, host.Options); // if (template.Disks.Length > 0) // { _logger.LogDebug(template.Source + " " + template.Disks[0].Path); if (await host.FileExists(template.Disks[0].Path)) { return(100); } // } return(-1); }
public static VirtualMachineConfigSpec TemplateToVmSpec(VmTemplate template, string datastore, string dvsuuid) { int key = -101, idekey = 200; VirtualMachineConfigSpec vmcs = new VirtualMachineConfigSpec(); List <VirtualDeviceConfigSpec> devices = new List <VirtualDeviceConfigSpec>(); vmcs.name = template.Name; vmcs.extraConfig = GetExtraConfig(template); vmcs.AddRam(template.Ram); vmcs.AddCpu(template.Cpu); vmcs.AddBootOption(Math.Max(template.Delay, 10)); vmcs.version = (template.Version.HasValue()) ? template.Version : null; vmcs.guestId = (template.Guest.HasValue() ? template.Guest : "other"); if (!vmcs.guestId.EndsWith("Guest")) { vmcs.guestId += "Guest"; } if (datastore.HasValue()) { vmcs.files = new VirtualMachineFileInfo { vmPathName = $"{datastore}/{template.Name}/{template.Name}.vmx" }; } //can't actually be applied via ExtraConfig if (template.GuestSettings.Length > 0 && template.GuestSettings.Any(s => s.Key == "vhv.enable" && s.Value == "true")) { vmcs.nestedHVEnabled = true; vmcs.nestedHVEnabledSpecified = true; } //video card devices.Add(GetVideoController(ref key, template.VideoRam)); //floppy disk if (template.Floppy.HasValue()) { devices.Add(GetFloppy(ref key, template.Floppy)); } //nics foreach (VmNet nic in template.Eth) { devices.Add(GetEthernetAdapter(ref key, nic, dvsuuid)); } // //network serial port // if (!String.IsNullOrEmpty(template.FindOne("nsp").Value())) // devices.Add(GetNetworkSerialPort(ref key, template.FindOne("nsp").Value())); //controller int controllerKey = 0, count = 0; foreach (VmDisk disk in template.Disks) { if (controllerKey == 0) { if (disk.Controller == "ide") { controllerKey = idekey; } else { VirtualDeviceConfigSpec controller = GetSCSIController(ref key, disk.Controller); controllerKey = controller.device.key; devices.Add(controller); } } devices.Add(GetDisk(ref key, disk.Path, controllerKey, count++)); } //iso devices.Add(GetCdrom(ref key, idekey, (template.Iso.HasValue() ? template.Iso : "[iso] null.iso"))); //add all devices to spec vmcs.deviceChange = devices.ToArray(); return(vmcs); }
public async Task <ActionResult <Vm> > Initialize(int id) { VmTemplate template = await _templateService.GetDeployableTemplate(id, null); return(Ok(await _pod.CreateDisks(template))); }