-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve (de)activation of capabilities (#304)
* Improve (de)activation of capabilities * Deactivate dynamic memory and secure boot by default * Add unit tests Closes #289
- Loading branch information
1 parent
0111226
commit 140ab15
Showing
13 changed files
with
587 additions
and
249 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
107 changes: 57 additions & 50 deletions
107
src/core/src/Eryph.VmManagement/Converging/ConvergeSecureBoot.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,65 +1,72 @@ | ||
using System; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using Eryph.ConfigModel; | ||
using Eryph.Core; | ||
using Eryph.VmManagement.Data; | ||
using Eryph.VmManagement.Data.Core; | ||
using Eryph.VmManagement.Data.Full; | ||
using LanguageExt; | ||
using LanguageExt.Common; | ||
|
||
using static LanguageExt.Prelude; | ||
|
||
namespace Eryph.VmManagement.Converging; | ||
|
||
public class ConvergeSecureBoot : ConvergeTaskBase | ||
public class ConvergeSecureBoot( | ||
ConvergeContext context) | ||
: ConvergeTaskBase(context) | ||
{ | ||
public ConvergeSecureBoot(ConvergeContext context) : base(context) | ||
{ | ||
} | ||
|
||
public override async Task<Either<Error, TypedPsObject<VirtualMachineInfo>>> Converge( | ||
TypedPsObject<VirtualMachineInfo> vmInfo) | ||
{ | ||
var secureBootCapability = Context.Config.Capabilities?.FirstOrDefault(x => x.Name == | ||
EryphConstants.Capabilities.SecureBoot); | ||
|
||
if (secureBootCapability == null) | ||
return vmInfo; | ||
|
||
var templateName = | ||
secureBootCapability.Details?.FirstOrDefault(x => x.StartsWith("template:", | ||
StringComparison.OrdinalIgnoreCase))?.Split(':')[1] | ||
?? "MicrosoftWindows"; | ||
|
||
var onOffState = (secureBootCapability.Details?.Any(x => | ||
string.Equals(x, EryphConstants.CapabilityDetails.Disabled, StringComparison.OrdinalIgnoreCase))).GetValueOrDefault() ? OnOffState.Off : OnOffState.On; | ||
|
||
return await (from currentFirmware in Context.Engine.GetObjectsAsync<VMFirmwareInfo>(new PsCommandBuilder() | ||
.AddCommand("get-VMFirmware") | ||
.AddArgument(vmInfo.PsObject)).ToError().ToAsync().Bind( | ||
r => r.HeadOrLeft(Error.New("VM firmware not found")).ToAsync()) | ||
from uSecureBoot in currentFirmware.Value.SecureBootTemplate == templateName && currentFirmware.Value.SecureBoot == onOffState | ||
? Unit.Default | ||
: Unit.Default.Apply(async _ => | ||
{ | ||
if (vmInfo.Value.State == VirtualMachineState.Running) | ||
return Error.New("Cannot change secure boot settings of a running catlet."); | ||
|
||
if(onOffState == OnOffState.On) | ||
await Context.ReportProgress($"Configuring secure boot settings (Template: {templateName})").ConfigureAwait(false); | ||
else | ||
await Context.ReportProgress($"Configuring secure boot settings (Secure Boot: Off)").ConfigureAwait(false); | ||
|
||
return await Context.Engine.RunAsync(PsCommandBuilder.Create() | ||
.AddCommand("Set-VMFirmware") | ||
.AddParameter("VM", vmInfo.PsObject) | ||
.AddParameter("EnableSecureBoot", onOffState) | ||
.AddParameter("SecureBootTemplate", templateName)).ToError(); | ||
|
||
}).ToAsync() | ||
from newVmInfo in vmInfo.RecreateOrReload(Context.Engine) | ||
select newVmInfo).ToEither(); | ||
public override Task<Either<Error, TypedPsObject<VirtualMachineInfo>>> Converge( | ||
TypedPsObject<VirtualMachineInfo> vmInfo) => | ||
ConvergeSecureBootState(vmInfo).ToEither(); | ||
|
||
private EitherAsync<Error, TypedPsObject<VirtualMachineInfo>> ConvergeSecureBootState( | ||
TypedPsObject<VirtualMachineInfo> vmInfo) => | ||
from _ in RightAsync<Error, Unit>(unit) | ||
let expectedSecureBootState = CatletCapabilities.IsSecureBootEnabled( | ||
Context.Config.Capabilities.ToSeq()) | ||
let expectedSecureBootTemplate = CatletCapabilities.FindSecureBootTemplate( | ||
Context.Config.Capabilities.ToSeq()) | ||
.IfNone("MicrosoftWindows") | ||
from vmFirmwareInfo in GetFirmwareInfo(vmInfo) | ||
let currentSecureBootState = vmFirmwareInfo.SecureBoot == OnOffState.On | ||
let currentSecureBootTemplate = vmFirmwareInfo.SecureBootTemplate | ||
from __ in expectedSecureBootState == currentSecureBootState | ||
&& expectedSecureBootTemplate == currentSecureBootTemplate | ||
? RightAsync<Error, Unit>(unit) | ||
: ConfigureSecureBoot(vmInfo, expectedSecureBootState, expectedSecureBootTemplate) | ||
from updatedVmInfo in vmInfo.RecreateOrReload(Context.Engine) | ||
select updatedVmInfo; | ||
|
||
private EitherAsync<Error, Unit> ConfigureSecureBoot( | ||
TypedPsObject<VirtualMachineInfo> vmInfo, | ||
bool enableSecureBoot, | ||
string secureBootTemplate) => | ||
from _1 in guard(vmInfo.Value.State is VirtualMachineState.Off or VirtualMachineState.OffCritical, | ||
Error.New("Cannot change secure boot settings if the catlet is not stopped. Stop the catlet and retry.")) | ||
.ToEitherAsync() | ||
from _2 in Context.ReportProgressAsync(enableSecureBoot | ||
? $"Configuring secure boot settings (Template: {secureBootTemplate})" | ||
: "Configuring secure boot settings (Secure Boot: Off)") | ||
// Hyper-V allows us to set the SecureBootTemplate even if SecureBoot is disabled. | ||
// Hence, this works as expected. | ||
let command = PsCommandBuilder.Create() | ||
.AddCommand("Set-VMFirmware") | ||
.AddParameter("VM", vmInfo.PsObject) | ||
.AddParameter("EnableSecureBoot", enableSecureBoot ? OnOffState.On : OnOffState.Off) | ||
.AddParameter("SecureBootTemplate", secureBootTemplate) | ||
from _3 in Context.Engine.RunAsync(command).ToError().ToAsync() | ||
select unit; | ||
|
||
} | ||
} | ||
private EitherAsync<Error, VMFirmwareInfo> GetFirmwareInfo( | ||
TypedPsObject<VirtualMachineInfo> vmInfo) => | ||
from _ in RightAsync<Error, Unit>(unit) | ||
let command = PsCommandBuilder.Create() | ||
.AddCommand("Get-VMFirmware") | ||
.AddParameter("VM", vmInfo.PsObject) | ||
from vmSecurityInfos in Context.Engine.GetObjectValuesAsync<VMFirmwareInfo>(command) | ||
.ToError() | ||
from vMSecurityInfo in vmSecurityInfos.HeadOrNone() | ||
.ToEitherAsync(Error.New($"Failed to fetch firmware information for the VM {vmInfo.Value.Id}.")) | ||
select vMSecurityInfo; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.