Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions docs/azmcp-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -1080,8 +1080,36 @@ azmcp monitor metrics query --subscription <subscription> \
azmcp azuremanagedlustre filesystem list --subscription <subscription> \
--resource-group <resource-group>

azmcp azuremanagedlustre filesystem sku get --subscription <subscription> \
--location <location>
# Create an Azure Managed Lustre filesystem
azmcp azuremanagedlustre filesystem create --subscription <subscription> \
--sku <sku> \
--size <filesystem-size-in-tib> \
--subnet-id <subnet-id> \
--zone <zone> \
--maintenance-day <maintenance-day> \
--maintenance-time <maintenance-time> \
[--hsm-container <hsm-container>] \
[--hsm-log-container <hsm-log-container>] \
[--import-prefix <import-prefix>] \
[--root-squash-mode <root-squash-mode>] \
[--no-squash-nid-list <no-squash-nid-list>] \
[--squash-uid <squash-uid>] \
[--squash-gid <squash-gid>] \
[--custom-encryption] \
[--key-url <key-url>] \
[--source-vault <source-vault>] \
[--user-assigned-identity-id <user-assigned-identity-id>]

# Update an existing Azure Managed Lustre filesystem
azmcp azuremanagedlustre filesystem update --subscription <subscription> \
--resource-group <resource-group> \
--name <filesystem-name> \
[--maintenance-day <maintenance-day>] \
[--maintenance-time <HH:mm>] \
[--root-squash-mode <mode>] \
[--no-squash-nid-list <nid1,nid2,...>] \
[--squash-uid <uid>] \
[--squash-gid <gid>]

# Returns the required number of IP addresses for a specific Azure Managed Lustre SKU and filesystem size
azmcp azuremanagedlustre filesystem subnetsize ask --subscription <subscription> \
Expand All @@ -1094,6 +1122,10 @@ azmcp azuremanagedlustre filesystem subnetsize validate --subscription <subscrip
--sku <azure-managed-lustre-sku> \
--size <filesystem-size-in-tib> \
--location <filesystem-location>

# Lists the available Azure Managed Lustre SKUs in a specific location
azmcp azuremanagedlustre filesystem sku get --subscription <subscription> \
--location <location>
```

### Azure Native ISV Operations
Expand Down
2 changes: 1 addition & 1 deletion eng/pipelines/templates/jobs/live-test.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
parameters:
- name: TimeoutInMinutes
type: number
default: 60
default: 75

jobs:
- job: LiveTest
Expand Down
3 changes: 3 additions & 0 deletions servers/Azure.Mcp.Server/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ The Azure MCP Server updates automatically by default whenever a new release com
[[#705](https://github.com/microsoft/mcp/pull/705)]
- Added the following Azure Managed Lustre commands:
- `azmcp_azuremanagedlustre_filesystem_subnetsize_validate`: Check if the subnet can host the target Azure Managed Lustre SKU and size [[#110](https://github.com/microsoft/mcp/issues/110)].
- Added the following Azure Managed Lustre commands: [[#50](https://github.com/microsoft/mcp/issues/50)]
- `azmcp_azuremanagedlustre_filesystem_create`: Create an Azure Managed Lustre filesystems.
- `azmcp_azuremanagedlustre_filesystem_update`: Update an Azure Managed Lustre filesystems.

### Breaking Changes

Expand Down
1 change: 1 addition & 0 deletions servers/Azure.Mcp.Server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ To use Azure Entra ID, review the [troubleshooting guide](https://github.com/mic
* "List the Azure Managed Lustre clusters in resource group 'my-resource-group'"
* "How many IP Addresses I need to create a 128 TiB cluster of AMLFS 500?"
* "Check if 'my-subnet-id' can host an Azure Managed Lustre with 'my-size' TiB and 'my-sku' in 'my-region'
* Create a 4 TIB Azure Managed Lustre filesystem in 'my-region' attaching to 'my-subnet' in virtual network 'my-virtual-network'

### 📊 Azure Monitor

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public void ConfigureServices(IServiceCollection services)
services.AddSingleton<IAzureManagedLustreService, AzureManagedLustreService>();

services.AddSingleton<FileSystemListCommand>();
services.AddSingleton<FileSystemCreateCommand>();
services.AddSingleton<FileSystemUpdateCommand>();
services.AddSingleton<SubnetSizeAskCommand>();
services.AddSingleton<SubnetSizeValidateCommand>();
services.AddSingleton<SkuGetCommand>();
Expand All @@ -26,14 +28,20 @@ public void ConfigureServices(IServiceCollection services)
public CommandGroup RegisterCommands(IServiceProvider serviceProvider)
{
var azureManagedLustre = new CommandGroup(Name,
"Azure Managed Lustre operations - Commands for listing and inspecting Azure Managed Lustre file systems (AMLFS) used for high-performance computing workloads.");
"Azure Managed Lustre operations - Commands for creating, updating, listing and inspecting Azure Managed Lustre file systems (AMLFS) used for high-performance computing workloads. The tool focuses on managing all the aspects related to Azure Managed Lustre filesystem instances.");

var fileSystem = new CommandGroup("filesystem", "Azure Managed Lustre file system operations - Commands for listing managed Lustre file systems.");
azureManagedLustre.AddSubGroup(fileSystem);

var list = serviceProvider.GetRequiredService<FileSystemListCommand>();
fileSystem.AddCommand(list.Name, list);

var create = serviceProvider.GetRequiredService<FileSystemCreateCommand>();
fileSystem.AddCommand(create.Name, create);

var update = serviceProvider.GetRequiredService<FileSystemUpdateCommand>();
fileSystem.AddCommand(update.Name, update);

var subnetSize = new CommandGroup("subnetsize", "Subnet size planning and validation operations for Azure Managed Lustre.");
fileSystem.AddSubGroup(subnetSize);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ namespace Azure.Mcp.Tools.AzureManagedLustre.Commands;
[JsonSerializable(typeof(SubnetSizeValidateCommand.FileSystemCheckSubnetResult))]
[JsonSerializable(typeof(FileSystemListCommand.FileSystemListResult))]
[JsonSerializable(typeof(SkuGetCommand.SkuGetResult))]
[JsonSerializable(typeof(FileSystemCreateCommand.FileSystemCreateResult))]
[JsonSerializable(typeof(FileSystemUpdateCommand.FileSystemUpdateResult))]
[JsonSerializable(typeof(LustreFileSystem))]
[JsonSerializable(typeof(AzureManagedLustreSkuInfo))]
[JsonSerializable(typeof(AzureManagedLustreSkuCapability))]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.CommandLine.Parsing;
using System.Diagnostics.CodeAnalysis;
using System.Net;
using Azure.Mcp.Core.Commands;
using Azure.Mcp.Core.Commands.Subscription;
using Azure.Mcp.Core.Extensions;
using Azure.Mcp.Tools.AzureManagedLustre.Options;
using Microsoft.Extensions.Logging;

Expand All @@ -15,4 +18,93 @@ public abstract class BaseAzureManagedLustreCommand<
{
// Currently no additional options beyond subscription + resource group
protected readonly ILogger<BaseAzureManagedLustreCommand<TOptions>> _logger = logger;

public void ValidateRootSquashOptions(CommandResult commandResult)
{
var rootSquashMode = commandResult.GetValueOrDefault(AzureManagedLustreOptionDefinitions.RootSquashModeOption);
var noSquashNidLists = commandResult.GetValueOrDefault(AzureManagedLustreOptionDefinitions.NoSquashNidListsOption);
var squashUid = commandResult.GetValueOrDefault(AzureManagedLustreOptionDefinitions.SquashUidOption);
var squashGid = commandResult.GetValueOrDefault(AzureManagedLustreOptionDefinitions.SquashGidOption);


// If root squash mode is provided and not 'none', require UID, GID and no squash NID list
if (!string.IsNullOrWhiteSpace(rootSquashMode) && !rootSquashMode.Equals("None", StringComparison.OrdinalIgnoreCase))
{
if (!(squashUid.HasValue && squashGid.HasValue && !string.IsNullOrWhiteSpace(noSquashNidLists)))
{
commandResult.AddError("When --root-squash-mode is not 'None', --squash-uid, --squash-gid and --no-squash-nid-list must be provided.");
}
}
}

public void ValidateMaintanenceOptionsCreate(CommandResult commandResult)
{
ValidateMaintenanceOptions(commandResult, false);
}

public void ValidateMaintanenceOptionsUpdate(CommandResult commandResult)
{
ValidateMaintenanceOptions(commandResult, true);
}

public void ValidateMaintenanceOptions(CommandResult commandResult, bool update = false)
{
// Read values from the same option instances used during registration
var maintenanceDay = update ? commandResult.GetValueOrDefault(AzureManagedLustreOptionDefinitions.OptionalMaintenanceDayOption) : commandResult.GetValueOrDefault(AzureManagedLustreOptionDefinitions.MaintenanceDayOption);
var maintenanceTime = update ? commandResult.GetValueOrDefault(AzureManagedLustreOptionDefinitions.OptionalMaintenanceTimeOption) : commandResult.GetValueOrDefault(AzureManagedLustreOptionDefinitions.MaintenanceTimeOption);
var updateWithoutMaintenance = string.IsNullOrWhiteSpace(maintenanceDay) && string.IsNullOrWhiteSpace(maintenanceTime) && update;

if ((string.IsNullOrWhiteSpace(maintenanceDay) || string.IsNullOrWhiteSpace(maintenanceTime)) && !updateWithoutMaintenance)
{
commandResult.AddError("When updating maintenance window, both --maintenance-day and --maintenance-time must be specified.");
}
}

public void ValidateHSMOptions(CommandResult commandResult)
{
// Read values from the same option instances used during registration
var hsmContainer = commandResult.GetValueOrDefault(AzureManagedLustreOptionDefinitions.HsmContainerOption);
var hsmLogContainer = commandResult.GetValueOrDefault(AzureManagedLustreOptionDefinitions.HsmLogContainerOption);
var hsmEnabled = !string.IsNullOrWhiteSpace(hsmContainer) || !string.IsNullOrWhiteSpace(hsmLogContainer);


// Always require both values if one is specified.
if (hsmEnabled && (string.IsNullOrWhiteSpace(hsmContainer) || string.IsNullOrWhiteSpace(hsmLogContainer)))
{
commandResult.AddError("When enabling Azure Blob Integration both data container and log container must be specified.");
}
}

public void ValidateEncryptionOptions(CommandResult commandResult)
{
// Read values from the same option instances used during registration
var encryptionEnabled = commandResult.GetValueOrDefault(AzureManagedLustreOptionDefinitions.CustomEncryptionOption);
var keyUrl = commandResult.GetValueOrDefault(AzureManagedLustreOptionDefinitions.KeyUrlOption);
var sourceVault = commandResult.GetValueOrDefault(AzureManagedLustreOptionDefinitions.SourceVaultOption);
var userAssignedIdentityId = commandResult.GetValueOrDefault(AzureManagedLustreOptionDefinitions.UserAssignedIdentityIdOption);

if (encryptionEnabled == true)
{
if (string.IsNullOrWhiteSpace(keyUrl) || string.IsNullOrWhiteSpace(sourceVault) || string.IsNullOrWhiteSpace(userAssignedIdentityId))
{
commandResult.AddError("Missing Required options: key-url, source-vault, user-assigned-identity when custom-encryption is set");
;
}
}
}

public void ValidateHasUpdateOptions(CommandResult commandResult)
{
var maintenanceDay = commandResult.GetValueOrDefault(AzureManagedLustreOptionDefinitions.OptionalMaintenanceDayOption);
var maintenanceTime = commandResult.GetValueOrDefault(AzureManagedLustreOptionDefinitions.OptionalMaintenanceTimeOption);
var rootSquashMode = commandResult.GetValueOrDefault(AzureManagedLustreOptionDefinitions.RootSquashModeOption);

if (string.IsNullOrWhiteSpace(maintenanceDay) &&
string.IsNullOrWhiteSpace(maintenanceTime) &&
string.IsNullOrWhiteSpace(rootSquashMode)
)
{
commandResult.AddError("At least one of maintenance-day/time or root-squash fields must be provided.");
}
}
}
Loading
Loading