-
Notifications
You must be signed in to change notification settings - Fork 545
Expand file tree
/
Copy pathProtectableItemListCommand.cs
More file actions
113 lines (100 loc) · 4.71 KB
/
Copy pathProtectableItemListCommand.cs
File metadata and controls
113 lines (100 loc) · 4.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Azure.Mcp.Tools.AzureBackup.Models;
using Azure.Mcp.Tools.AzureBackup.Options;
using Azure.Mcp.Tools.AzureBackup.Options.ProtectableItem;
using Azure.Mcp.Tools.AzureBackup.Services;
using Microsoft.Extensions.Logging;
using Microsoft.Mcp.Core.Commands;
using Microsoft.Mcp.Core.Extensions;
using Microsoft.Mcp.Core.Models.Command;
namespace Azure.Mcp.Tools.AzureBackup.Commands.ProtectableItem;
[CommandMetadata(
Id = "9f6b0a1e-1c2d-4e5f-8a9b-7c6d5e4f3a21",
Name = "list",
Title = "List Protectable Items",
Description = """
Lists items that can be backed up (protectable items) in a Recovery Services vault,
such as SQL databases and SAP HANA databases discovered on registered VMs.
Use this to find databases and workloads available for backup protection.
Only supported for RSV vaults; DPP datasources are protected by ARM resource ID directly.
Filter results by workload-type (e.g., SQL, SAPHana) or container.
""",
Destructive = false,
Idempotent = true,
OpenWorld = false,
ReadOnly = true,
Secret = false,
LocalRequired = false)]
public sealed class ProtectableItemListCommand(ILogger<ProtectableItemListCommand> logger, IAzureBackupService azureBackupService) : BaseAzureBackupCommand<ProtectableItemListOptions>()
{
private readonly ILogger<ProtectableItemListCommand> _logger = logger;
private readonly IAzureBackupService _azureBackupService = azureBackupService;
protected override void RegisterOptions(Command command)
{
base.RegisterOptions(command);
command.Options.Add(AzureBackupOptionDefinitions.WorkloadType);
command.Options.Add(AzureBackupOptionDefinitions.Container);
command.Validators.Add(commandResult =>
{
// NEW-4: reject unknown --workload-type at the command boundary so it surfaces
// as a 400 ValidationError instead of leaking the inner ArgumentException
// from the service layer as a 500.
//
// Read the value directly (no HasOptionResult gate) so whitespace-only inputs --
// which System.CommandLine may report as "no result" -- still fail validation
// here instead of slipping past and being rejected by the service layer.
var value = commandResult.GetValueOrDefault<string>(AzureBackupOptionDefinitions.WorkloadType.Name);
if (value is not null && !WorkloadTypeNormalizer.IsSupported(value))
{
commandResult.AddError(WorkloadTypeNormalizer.FormatUnknownMessage(value));
}
});
}
protected override ProtectableItemListOptions BindOptions(ParseResult parseResult)
{
var options = base.BindOptions(parseResult);
options.WorkloadType = parseResult.GetValueOrDefault<string>(AzureBackupOptionDefinitions.WorkloadType.Name);
options.Container = parseResult.GetValueOrDefault<string>(AzureBackupOptionDefinitions.Container.Name);
return options;
}
public override async Task<CommandResponse> ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken)
{
if (!Validate(parseResult.CommandResult, context.Response).IsValid)
{
return context.Response;
}
var options = BindOptions(parseResult);
AzureBackupTelemetryTags.AddSubscriptionTag(context.Activity, options.Subscription);
AzureBackupTelemetryTags.AddVaultAndWorkloadTags(context.Activity, options.VaultType ?? "rsv", options.WorkloadType);
try
{
var result = await _azureBackupService.ListProtectableItemsAsync(
options.Vault!,
options.ResourceGroup!,
options.Subscription!,
options.WorkloadType,
options.Container,
options.VaultType,
options.Tenant,
options.RetryPolicy,
cancellationToken);
context.Response.Results = ResponseResult.Create(
new(result),
AzureBackupJsonContext.Default.ProtectableItemListCommandResult);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error listing protectable items. Vault: {Vault}", options.Vault);
HandleException(context, ex);
}
return context.Response;
}
protected override string GetErrorMessage(Exception ex) => ex switch
{
ArgumentException argEx => argEx.Message,
RequestFailedException reqEx => reqEx.Message,
_ => base.GetErrorMessage(ex)
};
internal record ProtectableItemListCommandResult(List<ProtectableItemInfo> Items);
}