Skip to content

Comments

added aks node fleet and corrected input var.azs#505

Open
rauneetverma wants to merge 1 commit intomasterfrom
aks-node-fleet
Open

added aks node fleet and corrected input var.azs#505
rauneetverma wants to merge 1 commit intomasterfrom
aks-node-fleet

Conversation

@rauneetverma
Copy link
Contributor

@rauneetverma rauneetverma commented Feb 4, 2026

Description

This PR creates the module for aks node fleet which helps us to create multiple nodepools using one resource one.
Also have fixed the var.azs reference in kubernetes_node_pool/aks/0.1 using inputs var.inputs.network_details.attributes.legacy_outputs.vpc_details.azs.

Related issues

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

Checklist

  • I have created feat/bugfix branch out of develop branch
  • Code passes linting/formatting checks
  • Changes to resources have been tested in our dev environments
  • I have made corresponding changes to the documentation

Testing

Reviewer instructions

Summary by CodeRabbit

Release Notes

  • New Features
    • Added AKS node pool creation and management with configurable instance types, min/max node counts, and disk sizing
    • Support for node taints and labels for Kubernetes scheduling flexibility
    • Spot instance support with eviction policies and priority handling
    • Advanced OS configuration including sysctl customization for Linux nodes
    • Comprehensive documentation for AKS node pool configuration and deployment

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 4, 2026

Walkthrough

This pull request introduces a new AKS node fleet module for Kubernetes node pool management alongside an update to the existing Kubernetes node pool base module. The AKS node fleet provides a parent module that orchestrates multiple node pool configurations through a nested flavor module, with schema validation and Terraform resource definitions for Azure Kubernetes Service node pools.

Changes

Cohort / File(s) Summary
Kubernetes Node Pool Base Module
modules/kubernetes_node_pool/aks/0.1/main.tf
Changed zone source from var.cluster.azs[0] to var.inputs.network_details.attributes.legacy_outputs.vpc_details.azs[0], updating how the first AZ is resolved for node pool placement.
AKS Node Pool Flavor Module
modules/node_fleet/aks_node_fleet/0.1/aks/0.1/README.md, facets.yaml, variables.tf, main.tf, output.tf
New AKS flavor module implementing configurable node pool resources with documentation, schema definition, input variables, Terraform configuration for azurerm_kubernetes_cluster_node_pool resource with advanced settings (taints, labels, auto-scaling, spot pricing, sysctl config), and output mappings for name, taints, and labels.
AKS Node Fleet Root Module
modules/node_fleet/aks_node_fleet/0.1/facets.yaml, locals.tf, main.tf, outputs.tf, variables.tf
New parent module orchestrating multiple AKS node pools via for_each iteration over node_pools configuration, with JSON schema validation, taint processing logic, module instantiation of nested flavor module, and output aggregation of topology spread constraints and node pool metadata.
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes both main changes: adding the AKS node fleet module and correcting the var.azs input reference.
Description check ✅ Passed The description covers the main changes and marks the change type, but lacks details on testing, branch creation, and code quality checks.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch aks-node-fleet

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Fix all issues with AI agents
In `@modules/kubernetes_node_pool/aks/0.1/main.tf`:
- Line 58: The zones expression is using compact(...) only for the length check
but then indexing the original azs list, which can return empty/null; change it
to consistently use the compacted list (e.g., compute valid_azs =
compact(var.inputs.network_details.attributes.legacy_outputs.vpc_details.azs) or
an inline compact) and then set zones = length(local.valid_azs) == 0 ? null :
[local.valid_azs[0]] so you always pick the first non-empty AZ (update the
reference to use local.valid_azs or compact(...) in the ternary and keep the
rest of the attribute name unchanged).

In `@modules/node_fleet/aks_node_fleet/0.1/aks/0.1/main.tf`:
- Line 25: The current ternary that returns the constant "windos" when
local.os_type == "Windows" collapses distinct Windows pool names; update the
expression that sets the name (the local.name conditional) to generate a
deterministic, unique Windows-safe name instead — for example, produce a
truncated version of local.name (e.g., first N chars) or truncated+hash (e.g.,
substr(local.name,0,N) + "-" + substr(sha256(local.name),0,M)) when
local.os_type == "Windows" so you preserve uniqueness across pools while keeping
the name length valid.
- Around line 17-18: Guard the for-expressions against missing spec.taints by
replacing direct iteration over var.instance.spec.taints with a safe fallback
(e.g. iterate over try(var.instance.spec.taints, [])); update the taints
assignment (the line using taints = [for taint in var.instance.spec.taints :
...]) and any outputs that reference var.instance.spec.taints to use the same
try(...) fallback, and apply this change in both the aks_node_fleet and
kubernetes_node_pool modules so the for-expressions and outputs won't fail when
spec or taints is omitted.
- Line 24: The provider meta-argument is using a string literal
"azurerm3-105-0"; change it to an unquoted identifier by removing the quotes
(i.e., set provider = azurerm3-105-0) and ensure the corresponding provider
block uses the matching alias azurerm3-105-0 so Terraform can resolve the
referenced provider.
- Around line 2-12: Add a local for the autoscaling flag and make node_count
conditional: extract enable_auto_scaling from local.aks_advanced into a new
local (e.g., local.enable_auto_scaling = lookup(local.aks_advanced,
"enable_auto_scaling", false)) and replace the unconditional node_count with a
computed local (e.g., local.node_count = local.enable_auto_scaling ? null :
lookup(local.aks_advanced, "node_count", 1)); update any references to
node_count in the AKS node pool config to use local.node_count so node_count is
null when autoscaling is enabled and avoids provider errors.

In `@modules/node_fleet/aks_node_fleet/0.1/facets.yaml`:
- Around line 98-105: The disk_size schema currently uses pattern "^[0-9]+G$"
which permits values outside the documented 50–1000G range; update the pattern
for the disk_size property in facets.yaml (the disk_size field) to enforce
numeric values between 50 and 1000 followed by "G" (for example use a regex that
matches 50–99, 100–999, or 1000 such as one that captures [5-9]\d, [1-9]\d{2},
or 1000) so the validation aligns with the x-ui-error-message.

In `@modules/node_fleet/aks_node_fleet/0.1/locals.tf`:
- Around line 10-15: processed_taints is building a numeric-keyed map from
local.taints but the AKS module expects an array; replace usages of
processed_taints with the original array (local.taints) or convert
processed_taints into a proper list—i.e., stop transforming into a map in
locals.tf (remove the for idx, taint : ... map) and set the module input taints
= local.taints in main.tf (or create a list comprehension that yields an array)
so the input matches the variable/schema type: array.

In `@modules/node_fleet/aks_node_fleet/0.1/main.tf`:
- Line 14: The default for disk_size in the lookup call (disk_size =
lookup(each.value, "disk_size", "G")) is invalid and violates the pattern
^[0-9]+G$; change the default to null for an optional parameter or a valid size
string (e.g., "50G") so downstream trim/digits conversion doesn't produce an
empty string — update the lookup default and any callers expecting a non-null
string accordingly, and ensure any logic using trim(disk_size, "G") guards
against null/empty before integer conversion.
🧹 Nitpick comments (1)
modules/node_fleet/aks_node_fleet/0.1/aks/0.1/variables.tf (1)

13-19: Prefer null defaults over empty strings for numeric fields.
Empty strings can leak into node pool configuration and cause provider validation errors if defaults are used.

✅ Suggested defaults
-      "instance_type"  = "",
-      "min_node_count" = "",
-      "max_node_count" = "",
-      "disk_size"      = "",
+      "instance_type"  = null,
+      "min_node_count" = null,
+      "max_node_count" = null,
+      "disk_size"      = null,

tags = local.tags
spot_max_price = local.priority == "Spot" ? lookup(local.aks_advanced, "spot_max_price", "-1") : local.spot_max_price
zones = length(compact(var.cluster.azs)) == 0 ? null : [var.cluster.azs[0]]
zones = length(compact(var.inputs.network_details.attributes.legacy_outputs.vpc_details.azs)) == 0 ? null : [var.inputs.network_details.attributes.legacy_outputs.vpc_details.azs[0]]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Inconsistent use of compact() may result in selecting an empty zone value.

The condition uses compact(...) to filter out empty strings/nulls when checking length, but the index access [0] is performed on the original (non-compacted) list. If the original list starts with empty or null values (e.g., ["", "eastus"]), the length check passes but azs[0] returns an empty string instead of the first valid zone.

🐛 Proposed fix: use compacted list consistently
-  zones          = length(compact(var.inputs.network_details.attributes.legacy_outputs.vpc_details.azs)) == 0 ? null : [var.inputs.network_details.attributes.legacy_outputs.vpc_details.azs[0]]
+  zones          = length(compact(var.inputs.network_details.attributes.legacy_outputs.vpc_details.azs)) == 0 ? null : [compact(var.inputs.network_details.attributes.legacy_outputs.vpc_details.azs)[0]]

Alternatively, for better readability, consider extracting to a local:

locals {
  # ... existing locals ...
  valid_azs = compact(var.inputs.network_details.attributes.legacy_outputs.vpc_details.azs)
}

# Then on line 58:
zones = length(local.valid_azs) == 0 ? null : [local.valid_azs[0]]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
zones = length(compact(var.inputs.network_details.attributes.legacy_outputs.vpc_details.azs)) == 0 ? null : [var.inputs.network_details.attributes.legacy_outputs.vpc_details.azs[0]]
zones = length(compact(var.inputs.network_details.attributes.legacy_outputs.vpc_details.azs)) == 0 ? null : [compact(var.inputs.network_details.attributes.legacy_outputs.vpc_details.azs)[0]]
🤖 Prompt for AI Agents
In `@modules/kubernetes_node_pool/aks/0.1/main.tf` at line 58, The zones
expression is using compact(...) only for the length check but then indexing the
original azs list, which can return empty/null; change it to consistently use
the compacted list (e.g., compute valid_azs =
compact(var.inputs.network_details.attributes.legacy_outputs.vpc_details.azs) or
an inline compact) and then set zones = length(local.valid_azs) == 0 ? null :
[local.valid_azs[0]] so you always pick the first non-empty AZ (update the
reference to use local.valid_azs or compact(...) in the ternary and keep the
rest of the attribute name unchanged).

Comment on lines +2 to +12
aks_advanced = lookup(lookup(lookup(var.instance, "advanced", {}), "aks", {}), "node_pool", {})
aks_upgrade_settings = lookup(local.aks_advanced, "upgrade_settings", {})
aks_kubelet_config = lookup(local.aks_advanced, "kubelet_config", {})
aks_linux_os_config = lookup(local.aks_advanced, "linux_os_config", {})
aks_sysctl_config = lookup(local.aks_linux_os_config, "sysctl_config", {})
metadata = lookup(var.instance, "metadata", {})
priority = lookup(local.aks_advanced, "priority", "Regular")
user_defined_tags = lookup(local.aks_advanced, "tags", {})
facets_defined_cloud_tags = lookup(var.environment, "cloud_tags", {})
tags = merge(local.user_defined_tags, local.facets_defined_cloud_tags)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -name "main.tf" -path "*/aks_node_fleet/*" -o -name "main.tf" -path "*/aks/0.1/*" | head -20

Repository: Facets-cloud/facets-modules

Length of output: 221


🏁 Script executed:

cd modules && find . -name "main.tf" | grep -i aks | head -10

Repository: Facets-cloud/facets-modules

Length of output: 197


🏁 Script executed:

git ls-files | grep -E "aks.*main\.tf|main\.tf.*aks" | head -20

Repository: Facets-cloud/facets-modules

Length of output: 215


🏁 Script executed:

git ls-files | grep "node_fleet" | head -20

Repository: Facets-cloud/facets-modules

Length of output: 707


🌐 Web query:

Terraform azurerm_kubernetes_cluster_node_pool enable_auto_scaling node_count requirements

💡 Result:

  • If enable_auto_scaling = true (AzureRM v3.x) you must also set min_count and max_count for the node pool.
  • With autoscaling enabled, don’t manage node_count (typically omit it / set it to null). Changing node_count while autoscaling is enabled can fail with an error like “cannot change node_count when enable_auto_scaling is set to true. [2]
  • Ensure your effective node count stays within your autoscaler range over time; Azure may temporarily run outside the min/max (for example after restart) and later converge back as autoscaling actions occur. [3]
  • Provider version note: in AzureRM v4.x the argument was renamed from enable_auto_scalingauto_scaling_enabled. [1]

Example (recommended pattern when autoscaling is on):

resource "azurerm_kubernetes_cluster_node_pool" "user" {
  kubernetes_cluster_id = azurerm_kubernetes_cluster.aks.id
  name                  = "user"
  vm_size               = "Standard_D2s_v3"

  enable_auto_scaling = true
  min_count           = 1
  max_count           = 5

  node_count = null # or omit entirely
}

(Pattern shown in practice.) [4]

Sources: [1] [2] [3] [4]


🏁 Script executed:

cat -n modules/node_fleet/aks_node_fleet/0.1/aks/0.1/main.tf

Repository: Facets-cloud/facets-modules

Length of output: 10890


🏁 Script executed:

wc -l modules/node_fleet/aks_node_fleet/0.1/aks/0.1/main.tf

Repository: Facets-cloud/facets-modules

Length of output: 128


Make node_count conditional on autoscaling to prevent provider errors.

When enable_auto_scaling is true, setting node_count causes the Terraform provider to error or drift. The current code (lines 34–37) unconditionally sets node_count regardless of the autoscaling state. Extract enable_auto_scaling to a local variable in the locals block (lines 2–11) and conditionally set node_count to null when autoscaling is enabled.

⚙️ Suggested fix
 locals {
   aks_advanced              = lookup(lookup(lookup(var.instance, "advanced", {}), "aks", {}), "node_pool", {})
   aks_upgrade_settings      = lookup(local.aks_advanced, "upgrade_settings", {})
   aks_kubelet_config        = lookup(local.aks_advanced, "kubelet_config", {})
   aks_linux_os_config       = lookup(local.aks_advanced, "linux_os_config", {})
   aks_sysctl_config         = lookup(local.aks_linux_os_config, "sysctl_config", {})
   metadata                  = lookup(var.instance, "metadata", {})
   priority                  = lookup(local.aks_advanced, "priority", "Regular")
   user_defined_tags         = lookup(local.aks_advanced, "tags", {})
   facets_defined_cloud_tags = lookup(var.environment, "cloud_tags", {})
   tags                      = merge(local.user_defined_tags, local.facets_defined_cloud_tags)
+  enable_auto_scaling       = lookup(local.aks_advanced, "enable_auto_scaling", true)

   name = lookup(local.metadata, "name", var.instance_name)

   taints         = [for taint in var.instance.spec.taints : "${taint.key}=${taint.value}:${taint.effect}"]
   spot_max_price = lookup(local.aks_advanced, "spot_max_price", null)
   os_type = lookup(local.aks_advanced, "os_type", "Linux")
 }

 resource "azurerm_kubernetes_cluster_node_pool" "node_pool" {
-  enable_auto_scaling = lookup(local.aks_advanced, "enable_auto_scaling", true)
+  enable_auto_scaling = local.enable_auto_scaling
   max_count           = var.instance.spec.max_node_count
   min_count           = var.instance.spec.min_node_count
-  node_count          = lookup(local.aks_advanced, "node_count", var.instance.spec.min_node_count)
+  node_count          = local.enable_auto_scaling ? null : lookup(local.aks_advanced, "node_count", var.instance.spec.min_node_count)
🤖 Prompt for AI Agents
In `@modules/node_fleet/aks_node_fleet/0.1/aks/0.1/main.tf` around lines 2 - 12,
Add a local for the autoscaling flag and make node_count conditional: extract
enable_auto_scaling from local.aks_advanced into a new local (e.g.,
local.enable_auto_scaling = lookup(local.aks_advanced, "enable_auto_scaling",
false)) and replace the unconditional node_count with a computed local (e.g.,
local.node_count = local.enable_auto_scaling ? null : lookup(local.aks_advanced,
"node_count", 1)); update any references to node_count in the AKS node pool
config to use local.node_count so node_count is null when autoscaling is enabled
and avoids provider errors.

Comment on lines +17 to +18
taints = [for taint in var.instance.spec.taints : "${taint.key}=${taint.value}:${taint.effect}"]
spot_max_price = lookup(local.aks_advanced, "spot_max_price", null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find all usages of spec.taints in the codebase
rg -n 'spec\.taints' -C 3

Repository: Facets-cloud/facets-modules

Length of output: 2927


🏁 Script executed:

cat -n modules/node_fleet/aks_node_fleet/0.1/aks/0.1/main.tf | head -50

Repository: Facets-cloud/facets-modules

Length of output: 3459


🏁 Script executed:

# Find variable definitions related to instance.spec
rg -n 'variable.*instance|spec.*taints' -A 5 modules/node_fleet/aks_node_fleet/0.1/aks/0.1/

Repository: Facets-cloud/facets-modules

Length of output: 2184


🏁 Script executed:

cat -n modules/node_fleet/aks_node_fleet/0.1/aks/0.1/variables.tf

Repository: Facets-cloud/facets-modules

Length of output: 1188


🏁 Script executed:

# Check how many modules have this spec.taints pattern
find . -name "main.tf" -o -name "output.tf" | xargs rg -l 'spec\.taints' | sort

Repository: Facets-cloud/facets-modules

Length of output: 280


Guard against missing spec.taints across all references to avoid plan errors.

The default value in the variable definition only applies if var.instance is completely omitted. If a user provides a partial override without the taints key, the for-expressions will fail. Apply the fix consistently to both main.tf and output.tf in both the aks_node_fleet and kubernetes_node_pool modules.

🛡️ Locations requiring fixes
  • modules/node_fleet/aks_node_fleet/0.1/aks/0.1/main.tf:17
  • modules/node_fleet/aks_node_fleet/0.1/aks/0.1/output.tf:4
  • modules/kubernetes_node_pool/aks/0.1/main.tf:17
  • modules/kubernetes_node_pool/aks/0.1/output.tf:4

Suggested fix pattern:

-  taints = [for taint in var.instance.spec.taints : ...]
+  taints = [for taint in try(var.instance.spec.taints, []) : ...]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
taints = [for taint in var.instance.spec.taints : "${taint.key}=${taint.value}:${taint.effect}"]
spot_max_price = lookup(local.aks_advanced, "spot_max_price", null)
taints = [for taint in try(var.instance.spec.taints, []) : "${taint.key}=${taint.value}:${taint.effect}"]
spot_max_price = lookup(local.aks_advanced, "spot_max_price", null)
🤖 Prompt for AI Agents
In `@modules/node_fleet/aks_node_fleet/0.1/aks/0.1/main.tf` around lines 17 - 18,
Guard the for-expressions against missing spec.taints by replacing direct
iteration over var.instance.spec.taints with a safe fallback (e.g. iterate over
try(var.instance.spec.taints, [])); update the taints assignment (the line using
taints = [for taint in var.instance.spec.taints : ...]) and any outputs that
reference var.instance.spec.taints to use the same try(...) fallback, and apply
this change in both the aks_node_fleet and kubernetes_node_pool modules so the
for-expressions and outputs won't fail when spec or taints is omitted.

}

resource "azurerm_kubernetes_cluster_node_pool" "node_pool" {
provider = "azurerm3-105-0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's explore the repository structure to locate the file
find . -name "main.tf" -path "*aks*" 2>/dev/null | head -20

Repository: Facets-cloud/facets-modules

Length of output: 221


🏁 Script executed:

# Let's also find and read the specific file mentioned in the review
find . -path "*/aks_node_fleet/0.1/aks/0.1/main.tf" 2>/dev/null

Repository: Facets-cloud/facets-modules

Length of output: 126


🏁 Script executed:

# Search for provider declarations and meta-argument usage
rg -n 'provider\s*=' -C3

Repository: Facets-cloud/facets-modules

Length of output: 50385


🏁 Script executed:

# Search for terraform provider blocks (provider configuration)
rg -n '^\s*provider\s*"' -C3

Repository: Facets-cloud/facets-modules

Length of output: 5334


🏁 Script executed:

# Search for alias declarations
rg -nP 'alias\s*=' -C2

Repository: Facets-cloud/facets-modules

Length of output: 5986


🏁 Script executed:

# Read the specific file around line 24
cat -n modules/node_fleet/aks_node_fleet/0.1/aks/0.1/main.tf | head -50

Repository: Facets-cloud/facets-modules

Length of output: 3459


🏁 Script executed:

# Search for provider declarations of azurerm (no "provider" keyword, looking for "provider "azurerm" declarations)
rg 'provider\s+"azurerm' modules/node_fleet/aks_node_fleet/ -A5

Repository: Facets-cloud/facets-modules

Length of output: 53


🏁 Script executed:

# Check if there's a variables or provider configuration file in the aks directory
find modules/node_fleet/aks_node_fleet/0.1/aks/0.1 -type f -name "*.tf" | head -10

Repository: Facets-cloud/facets-modules

Length of output: 239


🏁 Script executed:

# Search for provider blocks to see if azurerm3-105-0 or azurerm is configured
rg 'provider\s+"azurerm' -A10 modules/node_fleet/aks_node_fleet/0.1/

Repository: Facets-cloud/facets-modules

Length of output: 53


🏁 Script executed:

# Check for required_providers blocks that might define these aliases
rg 'required_providers' modules/node_fleet/aks_node_fleet/0.1/ -A20

Repository: Facets-cloud/facets-modules

Length of output: 53


🏁 Script executed:

# Also check parent directory for provider definitions
rg 'provider\s+"azurerm' modules/node_fleet/aks_node_fleet/0.1/main.tf -A10

Repository: Facets-cloud/facets-modules

Length of output: 53


🏁 Script executed:

# Check what files exist at the parent level
ls -la modules/node_fleet/aks_node_fleet/0.1/

Repository: Facets-cloud/facets-modules

Length of output: 534


🏁 Script executed:

# Check the parent main.tf file for provider configuration
cat -n modules/node_fleet/aks_node_fleet/0.1/main.tf

Repository: Facets-cloud/facets-modules

Length of output: 1942


🏁 Script executed:

# Check for any .tf files that might define the provider
cat -n modules/node_fleet/aks_node_fleet/0.1/locals.tf

Repository: Facets-cloud/facets-modules

Length of output: 708


🏁 Script executed:

# Search broader in the node_fleet directory for provider definitions
find modules/node_fleet -name "*.tf" -exec grep -l 'provider\s*"azurerm' {} \;

Repository: Facets-cloud/facets-modules

Length of output: 53


🏁 Script executed:

# Also check if there are any terraform files defining providers at module level
find modules/node_fleet/aks_node_fleet -name "versions.tf" -o -name "provider.tf"

Repository: Facets-cloud/facets-modules

Length of output: 53


🏁 Script executed:

# Search for how provider meta-arguments are used in valid contexts in the codebase
rg 'provider\s*=\s*[a-z]+' modules/ | head -20

Repository: Facets-cloud/facets-modules

Length of output: 1447


🏁 Script executed:

# Look for provider blocks with alias definitions in the entire codebase
rg -A3 'provider\s+"(aws|azurerm)"' modules/ | grep -A3 'alias'

Repository: Facets-cloud/facets-modules

Length of output: 676


🏁 Script executed:

# Check the specific aks/0.1 subdirectory more carefully
cat modules/node_fleet/aks_node_fleet/0.1/aks/0.1/variables.tf

Repository: Facets-cloud/facets-modules

Length of output: 873


🏁 Script executed:

# List all files in the aks/0.1 directory
ls -la modules/node_fleet/aks_node_fleet/0.1/aks/0.1/

Repository: Facets-cloud/facets-modules

Length of output: 480


🏁 Script executed:

# Verify Terraform provider meta-argument syntax by checking what's valid vs invalid
# Search for any documentation or comments about provider configuration in the codebase
rg -i 'provider.*meta' modules/ --max-count=5

Repository: Facets-cloud/facets-modules

Length of output: 675


🏁 Script executed:

# Look for how "azurerm" or similar provider aliases are configured in this codebase
rg 'provider\s+"azurerm' modules/ -C5 | head -40

Repository: Facets-cloud/facets-modules

Length of output: 53


🏁 Script executed:

# Check if there's a pattern of how these string-based providers should be corrected
rg 'provider\s*=\s*"' modules/ | head -20

Repository: Facets-cloud/facets-modules

Length of output: 2068


🏁 Script executed:

# Let's verify Terraform syntax by looking for actual provider block definitions
# that might define these aliases
find modules -name "versions.tf" -o -name "provider.tf" | head -10

Repository: Facets-cloud/facets-modules

Length of output: 933


🏁 Script executed:

# Check if these string-based provider references are documented or commented
rg -B2 'provider\s*=\s*"(aws5|azurerm3-105-0)"' modules/ | head -30

Repository: Facets-cloud/facets-modules

Length of output: 2601


🏁 Script executed:

# Search for any provider block definitions with alias that matches what's being used
rg 'provider\s+"(azurerm|aws)"' modules/node_fleet/aks_node_fleet/ -A5

Repository: Facets-cloud/facets-modules

Length of output: 53


🏁 Script executed:

# Broader search for provider configuration blocks
rg 'provider\s+"azurerm"' modules/ -A10 | head -50

Repository: Facets-cloud/facets-modules

Length of output: 53


🏁 Script executed:

# Let's check one of the versions.tf files to see how providers are actually configured
cat modules/dynamodb/default/0.2/terraform-aws-dynamodb-table-2.0.0/versions.tf

Repository: Facets-cloud/facets-modules

Length of output: 191


🏁 Script executed:

# Check a versions.tf in the aks module area to see provider config
find modules/node_fleet/aks_node_fleet -name "versions.tf" 2>/dev/null

Repository: Facets-cloud/facets-modules

Length of output: 53


🏁 Script executed:

# Let's verify the exact Terraform syntax rule by checking examples with comments
rg 'provider\s*=' modules/ingress/aws_ecs_alb/0.1/main.tf -B2 -A1 | head -30

Repository: Facets-cloud/facets-modules

Length of output: 1333


🏁 Script executed:

# Let's check if there are any provider block configurations in the aks module parent directories
cat modules/node_fleet/aks_node_fleet/0.1/main.tf | grep -A10 'provider'

Repository: Facets-cloud/facets-modules

Length of output: 53


🏁 Script executed:

# Search more broadly for provider block definitions
rg 'provider\s+"azurerm"' modules/ -A10

Repository: Facets-cloud/facets-modules

Length of output: 53


🏁 Script executed:

# Check the specific file more carefully for all provider references
grep -n 'provider' modules/node_fleet/aks_node_fleet/0.1/aks/0.1/main.tf

Repository: Facets-cloud/facets-modules

Length of output: 116


🏁 Script executed:

# Let's confirm the Terraform syntax rule by checking what identifiers would be valid
# Search for any provider blocks that might define azurerm or azurerm3 with an alias
rg 'provider\s+"azurerm' modules/ -A10 | head -50

Repository: Facets-cloud/facets-modules

Length of output: 53


🏁 Script executed:

# Check if there's any provider configuration in parent modules or root
find modules/node_fleet -type f -name "*.tf" -exec grep -l 'provider\s*"azurerm' {} \;

Repository: Facets-cloud/facets-modules

Length of output: 53


🏁 Script executed:

# Let's look at a working example with proper syntax for comparison
rg 'provider\s*=\s*[a-z]+\.[a-z]+' modules/ | head -10

Repository: Facets-cloud/facets-modules

Length of output: 949


Remove the quotes from the provider meta-argument.

The provider meta-argument must reference an unquoted identifier, not a string literal. Change provider = "azurerm3-105-0" to provider = azurerm3-105-0 (or the appropriate provider alias reference if "azurerm3-105-0" is intended as an alias name). Verify that the corresponding provider configuration block is defined with this alias elsewhere in the configuration.

🤖 Prompt for AI Agents
In `@modules/node_fleet/aks_node_fleet/0.1/aks/0.1/main.tf` at line 24, The
provider meta-argument is using a string literal "azurerm3-105-0"; change it to
an unquoted identifier by removing the quotes (i.e., set provider =
azurerm3-105-0) and ensure the corresponding provider block uses the matching
alias azurerm3-105-0 so Terraform can resolve the referenced provider.


resource "azurerm_kubernetes_cluster_node_pool" "node_pool" {
provider = "azurerm3-105-0"
name = local.os_type == "Windows" && length(local.name) >= 6 ? "windos" : local.name //replacing the name to windos if os is window to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid constant Windows node pool names to prevent collisions.

Hard-coding "windos" collapses distinct Windows pool names into one, which will conflict in multi-pool deployments. Prefer a deterministic truncation (or truncation + hash) that preserves uniqueness.

🪪 Suggested fix
-  name                  = local.os_type == "Windows" && length(local.name) >= 6 ? "windos" : local.name //replacing the name to windos if os is window to
+  name                  = local.os_type == "Windows" ? substr(local.name, 0, 6) : local.name
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
name = local.os_type == "Windows" && length(local.name) >= 6 ? "windos" : local.name //replacing the name to windos if os is window to
name = local.os_type == "Windows" ? substr(local.name, 0, 6) : local.name
🤖 Prompt for AI Agents
In `@modules/node_fleet/aks_node_fleet/0.1/aks/0.1/main.tf` at line 25, The
current ternary that returns the constant "windos" when local.os_type ==
"Windows" collapses distinct Windows pool names; update the expression that sets
the name (the local.name conditional) to generate a deterministic, unique
Windows-safe name instead — for example, produce a truncated version of
local.name (e.g., first N chars) or truncated+hash (e.g., substr(local.name,0,N)
+ "-" + substr(sha256(local.name),0,M)) when local.os_type == "Windows" so you
preserve uniqueness across pools while keeping the name length valid.

Comment on lines +98 to +105
disk_size:
title: Disk Size
description: Size of the disk in GiB for nodes in this node pool
type: string
pattern: ^[0-9]+G$
x-ui-placeholder: eg. 50G
x-ui-error-message: Value doesn't match the format eg. 50G. Minimum
is 50G and max is 1000G
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Align disk_size validation with the stated 50–1000G bounds.
Current pattern ^[0-9]+G$ allows values like 1G, which contradicts the error message.

✅ Proposed regex update
-              pattern: ^[0-9]+G$
+              pattern: ^((5[0-9]G)|([6-9][0-9]G)|([1-9][0-9][0-9]G)|(1000G))$
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
disk_size:
title: Disk Size
description: Size of the disk in GiB for nodes in this node pool
type: string
pattern: ^[0-9]+G$
x-ui-placeholder: eg. 50G
x-ui-error-message: Value doesn't match the format eg. 50G. Minimum
is 50G and max is 1000G
disk_size:
title: Disk Size
description: Size of the disk in GiB for nodes in this node pool
type: string
pattern: ^((5[0-9]G)|([6-9][0-9]G)|([1-9][0-9][0-9]G)|(1000G))$
x-ui-placeholder: eg. 50G
x-ui-error-message: Value doesn't match the format eg. 50G. Minimum
is 50G and max is 1000G
🤖 Prompt for AI Agents
In `@modules/node_fleet/aks_node_fleet/0.1/facets.yaml` around lines 98 - 105, The
disk_size schema currently uses pattern "^[0-9]+G$" which permits values outside
the documented 50–1000G range; update the pattern for the disk_size property in
facets.yaml (the disk_size field) to enforce numeric values between 50 and 1000
followed by "G" (for example use a regex that matches 50–99, 100–999, or 1000
such as one that captures [5-9]\d, [1-9]\d{2}, or 1000) so the validation aligns
with the x-ui-error-message.

Comment on lines +10 to +15
processed_taints = {
for idx, taint in local.taints : idx => {
key = taint.key
value = taint.value
effect = taint.effect
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's explore the repository structure to understand the codebase
git ls-files | head -20

Repository: Facets-cloud/facets-modules

Length of output: 774


🏁 Script executed:

# Find the file mentioned in the review
find . -name "locals.tf" -path "*/aks_node_fleet/0.1/*" 2>/dev/null

Repository: Facets-cloud/facets-modules

Length of output: 120


🏁 Script executed:

# Search for where processed_taints is used
rg "processed_taints" -A 3 -B 3

Repository: Facets-cloud/facets-modules

Length of output: 1285


🏁 Script executed:

# Look for the downstream schema or usage patterns
rg "taints" -A 3 -B 3 | head -100

Repository: Facets-cloud/facets-modules

Length of output: 8056


🏁 Script executed:

cat -n modules/node_fleet/aks_node_fleet/0.1/main.tf | head -80

Repository: Facets-cloud/facets-modules

Length of output: 1942


🏁 Script executed:

# Get the complete facets.yaml to understand the schema expectations
cat modules/node_fleet/aks_node_fleet/0.1/facets.yaml

Repository: Facets-cloud/facets-modules

Length of output: 4606


🏁 Script executed:

# Check the aks/0.1 module's variables.tf to see what it expects for taints
cat modules/node_fleet/aks_node_fleet/0.1/aks/0.1/variables.tf

Repository: Facets-cloud/facets-modules

Length of output: 873


🏁 Script executed:

# Check how the taints are used in the aks/0.1 module
cat modules/node_fleet/aks_node_fleet/0.1/aks/0.1/main.tf | grep -A 5 -B 5 "taints"

Repository: Facets-cloud/facets-modules

Length of output: 1132


🏁 Script executed:

# Also check what outputs expects (from the earlier grep)
cat modules/node_fleet/aks_node_fleet/0.1/outputs.tf

Repository: Facets-cloud/facets-modules

Length of output: 280


🏁 Script executed:

# Let's see the full context of how variables are passed
cat -n modules/node_fleet/aks_node_fleet/0.1/aks/0.1/variables.tf | grep -A 20 "taints"

Repository: Facets-cloud/facets-modules

Length of output: 617


🏁 Script executed:

# Check if there are any type constraints for taints in the module
grep -r "taints" modules/node_fleet/aks_node_fleet/0.1/aks/0.1/ --include="*.tf" -B 2 -A 2

Repository: Facets-cloud/facets-modules

Length of output: 2740


🏁 Script executed:

cat -n modules/node_fleet/aks_node_fleet/0.1/locals.tf

Repository: Facets-cloud/facets-modules

Length of output: 708


🏁 Script executed:

# Search for all usages of processed_taints
rg "processed_taints" -B 5 -A 5

Repository: Facets-cloud/facets-modules

Length of output: 1952


🏁 Script executed:

# Check the structure flow more carefully - see what outputs are expected
cat -n modules/node_fleet/aks_node_fleet/0.1/aks/0.1/output.tf

Repository: Facets-cloud/facets-modules

Length of output: 1221


🏁 Script executed:

# Let's create a simple test to understand what gets passed
cat > /tmp/test_taint_flow.txt << 'EOF'
FLOW ANALYSIS:

1. Input in facets.yaml:
   - taints: type: array of objects with key, value, effect

2. In locals.tf (line 10-16):
   processed_taints = {
     for idx, taint in local.taints : idx => { ... }
   }
   This creates a MAP with string keys "0", "1", "2", etc.

3. In main.tf (line 16):
   taints = local.processed_taints
   This passes a MAP to the aks module

4. In aks/0.1/variables.tf:
   "taints" = []
   Expects an ARRAY (default is empty array)

5. In aks/0.1/main.tf:
   taints = [for taint in var.instance.spec.taints : "${taint.key}=${taint.value}:${taint.effect}"]
   Iterates as if it's an array

6. In aks/0.1/output.tf:
   taints = [for taint in var.instance.spec.taints : { ... }]
   Also iterates as if it's an array
EOF
cat /tmp/test_taint_flow.txt

Repository: Facets-cloud/facets-modules

Length of output: 815


🏁 Script executed:

# Check git history or comments for why processed_taints uses a map
git log --oneline -n 20 -- modules/node_fleet/aks_node_fleet/0.1/locals.tf 2>/dev/null || echo "No git history available"

Repository: Facets-cloud/facets-modules

Length of output: 127


🏁 Script executed:

# Check if there are similar patterns in other modules
rg "for idx.*in.*:" modules/ --type tf -B 2 -A 2 | head -40

Repository: Facets-cloud/facets-modules

Length of output: 432


Remove unnecessary map transformation for taints.
processed_taints creates a map with numeric keys, but the downstream aks module expects an array. The variable and schema both define taints as type: array. Either pass local.taints directly or convert to a proper array:

💡 Recommended fix
-  processed_taints = {
-    for idx, taint in local.taints : idx => {
-      key    = taint.key
-      value  = taint.value
-      effect = taint.effect
-    }
+  processed_taints = [
+    for taint in local.taints : {
+      key    = taint.key
+      value  = taint.value
+      effect = taint.effect
+    }
   }

Or simply use taints = local.taints in main.tf since it already matches the expected structure.

🤖 Prompt for AI Agents
In `@modules/node_fleet/aks_node_fleet/0.1/locals.tf` around lines 10 - 15,
processed_taints is building a numeric-keyed map from local.taints but the AKS
module expects an array; replace usages of processed_taints with the original
array (local.taints) or convert processed_taints into a proper list—i.e., stop
transforming into a map in locals.tf (remove the for idx, taint : ... map) and
set the module input taints = local.taints in main.tf (or create a list
comprehension that yields an array) so the input matches the variable/schema
type: array.

min_node_count = lookup(each.value, "min_node_count", null)
node_labels = lookup(each.value, "node_labels", null)
instance_type = lookup(each.value, "instance_type", null)
disk_size = lookup(each.value, "disk_size", "G")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n modules/node_fleet/aks_node_fleet/0.1/main.tf

Repository: Facets-cloud/facets-modules

Length of output: 1942


🏁 Script executed:

# Search for context around disk_size usage in the codebase
rg "disk_size" -B 5 -A 5

Repository: Facets-cloud/facets-modules

Length of output: 29315


🌐 Web query:

Terraform azurerm kubernetes cluster node pool disk_size valid values schema

💡 Result:

In the AzureRM provider, the AKS node pool “disk size” field is os_disk_size_gb (for both azurerm_kubernetes_cluster_node_pool and azurerm_kubernetes_cluster.default_node_pool). It’s an integer (GB); 0 means “use the default OS disk size for the selected vm_size. The underlying AKS/ARM API constraint is min 0, max 2048 (newer API versions) [1]. Older API versions capped this at 1023 [2].


Avoid invalid default disk_size = "G".

The value "G" violates the schema validation pattern (^[0-9]+G$) and will cause runtime failures. When this empty default is used, the downstream code applies trim(disk_size, "G") which produces an empty string, causing integer conversion errors. Use null for optional parameters or a valid size like "50G".

Suggested fix
-      disk_size      = lookup(each.value, "disk_size", "G")
+      disk_size      = lookup(each.value, "disk_size", null)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
disk_size = lookup(each.value, "disk_size", "G")
disk_size = lookup(each.value, "disk_size", null)
🤖 Prompt for AI Agents
In `@modules/node_fleet/aks_node_fleet/0.1/main.tf` at line 14, The default for
disk_size in the lookup call (disk_size = lookup(each.value, "disk_size", "G"))
is invalid and violates the pattern ^[0-9]+G$; change the default to null for an
optional parameter or a valid size string (e.g., "50G") so downstream
trim/digits conversion doesn't produce an empty string — update the lookup
default and any callers expecting a non-null string accordingly, and ensure any
logic using trim(disk_size, "G") guards against null/empty before integer
conversion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant