From a0f3711f7cbb21077c811fe025f5ce3d2a7c7641 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 26 Feb 2026 17:01:53 -0500 Subject: [PATCH 1/3] feat: support setting externally created route table on private azure subnet --- lib/types/workload.go | 58 +++++-------------- python-pulumi/src/ptd/azure_workload.py | 14 +---- .../azure_workload_persistent.py | 15 +++-- 3 files changed, 28 insertions(+), 59 deletions(-) diff --git a/lib/types/workload.go b/lib/types/workload.go index 7cb2cff..c44ac33 100644 --- a/lib/types/workload.go +++ b/lib/types/workload.go @@ -107,14 +107,15 @@ type AzureWorkloadConfig struct { } type NetworkConfig struct { - VnetCidr string `yaml:"vnet_cidr"` - PublicSubnetCidr string `yaml:"public_subnet_cidr"` - PrivateSubnetCidr string `yaml:"private_subnet_cidr"` - DbSubnetCidr string `yaml:"db_subnet_cidr"` - NetAppSubnetCidr string `yaml:"netapp_subnet_cidr"` - AppGatewaySubnetCidr string `yaml:"app_gateway_subnet_cidr"` - ProvisionedVnetID string `yaml:"provisioned_vnet_id"` - VnetRsgName string `yaml:"vnet_rsg_name"` + VnetCidr string `yaml:"vnet_cidr"` + PublicSubnetCidr string `yaml:"public_subnet_cidr"` + PrivateSubnetCidr string `yaml:"private_subnet_cidr"` + DbSubnetCidr string `yaml:"db_subnet_cidr"` + NetAppSubnetCidr string `yaml:"netapp_subnet_cidr"` + AppGatewaySubnetCidr string `yaml:"app_gateway_subnet_cidr"` + ProvisionedVnetID string `yaml:"provisioned_vnet_id"` + VnetRsgName string `yaml:"vnet_rsg_name"` + PrivateSubnetRouteTableID string `yaml:"private_subnet_route_table_id"` } // AzureUserNodePoolConfig defines configuration for a single user node pool in AKS @@ -139,19 +140,8 @@ type AzureWorkloadClusterConfig struct { PublicEndpointAccess bool `yaml:"public_endpoint_access"` SystemNodePoolInstanceType string `yaml:"system_node_pool_instance_type"` - // Legacy field - maintained for backward compatibility - // Used to configure the hardcoded "userpool" in AgentPoolProfiles for legacy clusters - UserNodePoolInstanceType string `yaml:"user_node_pool_instance_type,omitempty"` - - // New field - defines additional user node pools as separate AgentPool resources - // Works for both new clusters (all user pools) and legacy clusters (additional pools) - UserNodePools []AzureUserNodePoolConfig `yaml:"user_node_pools,omitempty"` - - // Optional: explicit flag to control whether to include legacy user pool in agentPoolProfiles - // Set to true for existing clusters to maintain the hardcoded "userpool" in AgentPoolProfiles - // Set to false (or omit) for new clusters to have all user pools as separate AgentPool resources - // Legacy clusters can have BOTH the hardcoded userpool AND additional user_node_pools - UseLegacyUserPool *bool `yaml:"use_legacy_user_pool,omitempty"` + // Required: defines user node pools as separate AgentPool resources + UserNodePools []AzureUserNodePoolConfig `yaml:"user_node_pools"` // Optional: Root disk size for system node pool in GB (defaults to 128) SystemNodePoolRootDiskSize *int `yaml:"system_node_pool_root_disk_size,omitempty"` @@ -186,27 +176,11 @@ func (c *AzureWorkloadClusterConfig) ValidateOutboundType() error { return nil } -// ResolveUserNodePools resolves which user node pools should be created based on configuration -// For NEW clusters (use_legacy_user_pool = false or omitted): user_node_pools is REQUIRED -// For LEGACY clusters (use_legacy_user_pool = true): user_node_pools is optional (adds ADDITIONAL pools) +// ResolveUserNodePools validates that user_node_pools is defined +// All Azure workloads must define user_node_pools in configuration func (c *AzureWorkloadClusterConfig) ResolveUserNodePools() ([]AzureUserNodePoolConfig, error) { - useLegacy := c.UseLegacyUserPool != nil && *c.UseLegacyUserPool - - // If user_node_pools is explicitly defined, use it - if len(c.UserNodePools) > 0 { - return c.UserNodePools, nil + if len(c.UserNodePools) == 0 { + return nil, fmt.Errorf("user_node_pools must be defined in cluster configuration") } - - // For legacy clusters, user_node_pools being empty is OK - // The legacy userpool in AgentPoolProfiles is sufficient - if useLegacy { - // But we still need UserNodePoolInstanceType for the legacy pool - if c.UserNodePoolInstanceType == "" { - return nil, fmt.Errorf("legacy clusters require user_node_pool_instance_type to be set") - } - return []AzureUserNodePoolConfig{}, nil - } - - // For new clusters, user_node_pools is required - return nil, fmt.Errorf("new clusters must define user_node_pools in configuration") + return c.UserNodePools, nil } diff --git a/python-pulumi/src/ptd/azure_workload.py b/python-pulumi/src/ptd/azure_workload.py index dae9a08..dfd9fbe 100644 --- a/python-pulumi/src/ptd/azure_workload.py +++ b/python-pulumi/src/ptd/azure_workload.py @@ -32,6 +32,7 @@ class NetworkConfig: public_subnet_cidr: str | None = None vnet_rsg_name: str | None = None dns_forward_domains: list[dict[str, str]] = dataclasses.field(default_factory=list) + private_subnet_route_table_id: str | None = None def __post_init__(self): """Validate DNS forward domain entries if configured.""" @@ -93,20 +94,9 @@ class AzureWorkloadClusterConfig(ptd.WorkloadClusterConfig): public_endpoint_access: bool = True system_node_pool_instance_type: str | None = "Standard_D2s_v6" - # Legacy field - maintained for backward compatibility - # Used to configure the hardcoded "userpool" in AgentPoolProfiles for legacy clusters - user_node_pool_instance_type: str | None = "Standard_D2s_v6" - - # defines additional user node pools as separate AgentPool resources - # Works for both new clusters (all user pools) and legacy clusters (additional pools) + # Required: defines user node pools as separate AgentPool resources user_node_pools: list[AzureUserNodePoolConfig] | None = None - # Optional: explicit flag to control whether to include legacy user pool in agentPoolProfiles - # Set to True for existing clusters to maintain the hardcoded "userpool" in AgentPoolProfiles - # Set to False (or omit) for new clusters to have all user pools as separate AgentPool resources - # Legacy clusters can have BOTH the hardcoded userpool AND additional user_node_pools - use_legacy_user_pool: bool | None = None - # Optional: Root disk size for system node pool in GB (defaults to 128) system_node_pool_root_disk_size: int | None = None diff --git a/python-pulumi/src/ptd/pulumi_resources/azure_workload_persistent.py b/python-pulumi/src/ptd/pulumi_resources/azure_workload_persistent.py index b097580..2ac41eb 100644 --- a/python-pulumi/src/ptd/pulumi_resources/azure_workload_persistent.py +++ b/python-pulumi/src/ptd/pulumi_resources/azure_workload_persistent.py @@ -177,11 +177,6 @@ def _define_vnet(self): resource_group_name=self.vnet_rsg_name, virtual_network_name=self.vnet_name, address_prefix=self.workload.cfg.network.private_subnet_cidr, - **( - {"nat_gateway": network.SubResourceArgs(id=self.nat_gw.id)} - if self.workload.cfg.network.public_subnet_cidr - else {} - ), service_endpoints=[ network.ServiceEndpointPropertiesFormatArgs( locations=[self.workload.cfg.region], @@ -193,6 +188,16 @@ def _define_vnet(self): ), ], network_security_group=network.SubResourceArgs(id=private_nsg.id), + **( + {"nat_gateway": network.SubResourceArgs(id=self.nat_gw.id)} + if self.workload.cfg.network.public_subnet_cidr + else {} + ), + **( + {"route_table": network.SubResourceArgs(id=self.workload.cfg.network.private_subnet_route_table_id)} + if self.workload.cfg.network.private_subnet_route_table_id + else {} + ), opts=pulumi.ResourceOptions( parent=self.vnet if hasattr(self, "vnet") and self.vnet else None, protect=self.workload.cfg.protect_persistent_resources, From a7af92d183319c8c8e7c68a1072956f27e12b5af Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 26 Feb 2026 17:12:02 -0500 Subject: [PATCH 2/3] fix: undo unrelated change --- lib/types/workload.go | 59 +++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/lib/types/workload.go b/lib/types/workload.go index c44ac33..2f03f4c 100644 --- a/lib/types/workload.go +++ b/lib/types/workload.go @@ -107,15 +107,15 @@ type AzureWorkloadConfig struct { } type NetworkConfig struct { - VnetCidr string `yaml:"vnet_cidr"` - PublicSubnetCidr string `yaml:"public_subnet_cidr"` - PrivateSubnetCidr string `yaml:"private_subnet_cidr"` - DbSubnetCidr string `yaml:"db_subnet_cidr"` - NetAppSubnetCidr string `yaml:"netapp_subnet_cidr"` - AppGatewaySubnetCidr string `yaml:"app_gateway_subnet_cidr"` - ProvisionedVnetID string `yaml:"provisioned_vnet_id"` - VnetRsgName string `yaml:"vnet_rsg_name"` - PrivateSubnetRouteTableID string `yaml:"private_subnet_route_table_id"` + VnetCidr string `yaml:"vnet_cidr"` + PublicSubnetCidr string `yaml:"public_subnet_cidr"` + PrivateSubnetCidr string `yaml:"private_subnet_cidr"` + PrivateSubnetRouteTableID string `yaml:"private_subnet_route_table_id"` + DbSubnetCidr string `yaml:"db_subnet_cidr"` + NetAppSubnetCidr string `yaml:"netapp_subnet_cidr"` + AppGatewaySubnetCidr string `yaml:"app_gateway_subnet_cidr"` + ProvisionedVnetID string `yaml:"provisioned_vnet_id"` + VnetRsgName string `yaml:"vnet_rsg_name"` } // AzureUserNodePoolConfig defines configuration for a single user node pool in AKS @@ -140,8 +140,19 @@ type AzureWorkloadClusterConfig struct { PublicEndpointAccess bool `yaml:"public_endpoint_access"` SystemNodePoolInstanceType string `yaml:"system_node_pool_instance_type"` - // Required: defines user node pools as separate AgentPool resources - UserNodePools []AzureUserNodePoolConfig `yaml:"user_node_pools"` + // Legacy field - maintained for backward compatibility + // Used to configure the hardcoded "userpool" in AgentPoolProfiles for legacy clusters + UserNodePoolInstanceType string `yaml:"user_node_pool_instance_type,omitempty"` + + // New field - defines additional user node pools as separate AgentPool resources + // Works for both new clusters (all user pools) and legacy clusters (additional pools) + UserNodePools []AzureUserNodePoolConfig `yaml:"user_node_pools,omitempty"` + + // Optional: explicit flag to control whether to include legacy user pool in agentPoolProfiles + // Set to true for existing clusters to maintain the hardcoded "userpool" in AgentPoolProfiles + // Set to false (or omit) for new clusters to have all user pools as separate AgentPool resources + // Legacy clusters can have BOTH the hardcoded userpool AND additional user_node_pools + UseLegacyUserPool *bool `yaml:"use_legacy_user_pool,omitempty"` // Optional: Root disk size for system node pool in GB (defaults to 128) SystemNodePoolRootDiskSize *int `yaml:"system_node_pool_root_disk_size,omitempty"` @@ -176,11 +187,27 @@ func (c *AzureWorkloadClusterConfig) ValidateOutboundType() error { return nil } -// ResolveUserNodePools validates that user_node_pools is defined -// All Azure workloads must define user_node_pools in configuration +// ResolveUserNodePools resolves which user node pools should be created based on configuration +// For NEW clusters (use_legacy_user_pool = false or omitted): user_node_pools is REQUIRED +// For LEGACY clusters (use_legacy_user_pool = true): user_node_pools is optional (adds ADDITIONAL pools) func (c *AzureWorkloadClusterConfig) ResolveUserNodePools() ([]AzureUserNodePoolConfig, error) { - if len(c.UserNodePools) == 0 { - return nil, fmt.Errorf("user_node_pools must be defined in cluster configuration") + useLegacy := c.UseLegacyUserPool != nil && *c.UseLegacyUserPool + + // If user_node_pools is explicitly defined, use it + if len(c.UserNodePools) > 0 { + return c.UserNodePools, nil } - return c.UserNodePools, nil + + // For legacy clusters, user_node_pools being empty is OK + // The legacy userpool in AgentPoolProfiles is sufficient + if useLegacy { + // But we still need UserNodePoolInstanceType for the legacy pool + if c.UserNodePoolInstanceType == "" { + return nil, fmt.Errorf("legacy clusters require user_node_pool_instance_type to be set") + } + return []AzureUserNodePoolConfig{}, nil + } + + // For new clusters, user_node_pools is required + return nil, fmt.Errorf("new clusters must define user_node_pools in configuration") } From 569c8b354f29fc5183cdb45ebb6dc5d569eacfff Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 26 Feb 2026 17:14:41 -0500 Subject: [PATCH 3/3] fix: undo unrelated change --- python-pulumi/src/ptd/azure_workload.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/python-pulumi/src/ptd/azure_workload.py b/python-pulumi/src/ptd/azure_workload.py index dfd9fbe..32f46ad 100644 --- a/python-pulumi/src/ptd/azure_workload.py +++ b/python-pulumi/src/ptd/azure_workload.py @@ -94,9 +94,20 @@ class AzureWorkloadClusterConfig(ptd.WorkloadClusterConfig): public_endpoint_access: bool = True system_node_pool_instance_type: str | None = "Standard_D2s_v6" - # Required: defines user node pools as separate AgentPool resources + # Legacy field - maintained for backward compatibility + # Used to configure the hardcoded "userpool" in AgentPoolProfiles for legacy clusters + user_node_pool_instance_type: str | None = "Standard_D2s_v6" + + # defines additional user node pools as separate AgentPool resources + # Works for both new clusters (all user pools) and legacy clusters (additional pools) user_node_pools: list[AzureUserNodePoolConfig] | None = None + # Optional: explicit flag to control whether to include legacy user pool in agentPoolProfiles + # Set to True for existing clusters to maintain the hardcoded "userpool" in AgentPoolProfiles + # Set to False (or omit) for new clusters to have all user pools as separate AgentPool resources + # Legacy clusters can have BOTH the hardcoded userpool AND additional user_node_pools + use_legacy_user_pool: bool | None = None + # Optional: Root disk size for system node pool in GB (defaults to 128) system_node_pool_root_disk_size: int | None = None