-
Couldn't load subscription status.
- Fork 686
feat: support multiple SSM parameters for large runner matcher configs (#4790) #4792
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: support multiple SSM parameters for large runner matcher configs (#4790) #4792
Conversation
trigger ci with a minor change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@edersonbrilhante nice contribution. I just tried the parameter split with the multi-runner example in this repo. By adding a few config and adding more labes. Result is I got this error, related to the added foreach
│
│ on ../../modules/webhook/webhook.tf line 27, in resource "aws_ssm_parameter" "runner_matcher_config":
│ 27: for_each = { for idx, val in local.matcher_chunks : idx => val }
│ ├────────────────
│ │ local.matcher_chunks will be known only after apply
│
│ The "for_each" map includes keys derived from resource attributes that cannot be determined until apply, and so Terraform cannot determine the full set of keys that will
│ identify the instances of this resource.
│
│ When working with unknown values in for_each, it's better to define the map keys statically in your configuration and place apply-time results only in the map values.
│
│ Alternatively, you could use the -target planning option to first apply only the resources that the for_each value depends on, and then apply a second time to fully
│ converge.
Wondering you you tested the change? I was not able to get it working right now.
|
I did test it, but I forgot to include a large configuration and only tested the normal case. My bad. I found the same bug now. |
|
@npalm I just pushed my fix. I tested a normal config and a tested a really big one with 7 ssm resources and it worked fine now. |
|
Thx for the updates, will not be able to able to get the PR merged in the next weeks. I will catch up end of the month. Sorry for tthe delay. |
|
No problem. :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Implements support for splitting the runner matcher configuration across multiple SSM parameters to avoid size limits for large configurations. The primary change allows PARAMETER_RUNNER_MATCHER_CONFIG_PATH to accept multiple parameter paths separated by a colon.
- Added logic to split large runner matcher configurations into chunks based on SSM parameter tier limits
- Updated infrastructure to create multiple SSM parameters when needed and pass them as a list
- Modified configuration loader to handle multiple parameter paths and combine them at runtime
Reviewed Changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| modules/webhook/webhook.tf | Implements chunking logic and creates multiple SSM parameters for large configs |
| modules/webhook/eventbridge/webhook.tf | Updates environment variable to join multiple parameter paths with colons |
| modules/webhook/eventbridge/variables.tf | Changes ssm_parameter_runner_matcher_config from object to list of objects |
| modules/webhook/eventbridge/dispatcher.tf | Updates IAM policy and environment variables to handle multiple parameters |
| modules/webhook/direct/webhook.tf | Updates environment variables to join multiple parameter paths with colons |
| modules/webhook/direct/variables.tf | Changes ssm_parameter_runner_matcher_config from object to list of objects |
| lambdas/functions/webhook/src/ConfigLoader.ts | Implements logic to load and combine configuration from multiple SSM parameters |
| lambdas/functions/webhook/src/ConfigLoader.test.ts | Adds test coverage for multi-parameter configuration loading |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| if (!paramPathsEnv || paramPathsEnv === 'undefined' || paramPathsEnv === 'null' || !paramPathsEnv.includes(':')) { | ||
| await this.loadParameter(paramPathsEnv, 'matcherConfig'); | ||
| return; | ||
| } | ||
|
|
||
| const paths = paramPathsEnv | ||
| .split(':') | ||
| .map((p) => p.trim()) | ||
| .filter(Boolean); | ||
| let combinedString = ''; | ||
|
|
||
| for (const path of paths) { | ||
| await this.loadParameter(path, 'matcherConfig'); | ||
| combinedString += this.matcherConfig; | ||
| } | ||
|
|
||
| try { | ||
| this.matcherConfig = JSON.parse(combinedString); | ||
| } catch (error) { | ||
| this.configLoadingErrors.push(`Failed to parse combined matcher config: ${(error as Error).message}`); | ||
| } |
Copilot
AI
Oct 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The condition logic is incorrect. When there's no colon in the path (single parameter), the function should still load the parameter, but the condition will return true and call loadParameter with the full path. However, when there IS a colon (multiple parameters), the condition returns false and proceeds to the multi-path logic. The condition should be !paramPathsEnv.includes(':') to handle single parameters correctly.
| if (!paramPathsEnv || paramPathsEnv === 'undefined' || paramPathsEnv === 'null' || !paramPathsEnv.includes(':')) { | |
| await this.loadParameter(paramPathsEnv, 'matcherConfig'); | |
| return; | |
| } | |
| const paths = paramPathsEnv | |
| .split(':') | |
| .map((p) => p.trim()) | |
| .filter(Boolean); | |
| let combinedString = ''; | |
| for (const path of paths) { | |
| await this.loadParameter(path, 'matcherConfig'); | |
| combinedString += this.matcherConfig; | |
| } | |
| try { | |
| this.matcherConfig = JSON.parse(combinedString); | |
| } catch (error) { | |
| this.configLoadingErrors.push(`Failed to parse combined matcher config: ${(error as Error).message}`); | |
| } | |
| if (!paramPathsEnv || paramPathsEnv === 'undefined' || paramPathsEnv === 'null') { | |
| // Optionally, log or handle missing matcher config path | |
| return; | |
| } else if (paramPathsEnv.includes(':')) { | |
| const paths = paramPathsEnv | |
| .split(':') | |
| .map((p) => p.trim()) | |
| .filter(Boolean); | |
| let combinedString = ''; | |
| for (const path of paths) { | |
| await this.loadParameter(path, 'matcherConfig'); | |
| combinedString += this.matcherConfig; | |
| } | |
| try { | |
| this.matcherConfig = JSON.parse(combinedString); | |
| } catch (error) { | |
| this.configLoadingErrors.push(`Failed to parse combined matcher config: ${(error as Error).message}`); | |
| } | |
| } else { | |
| await this.loadParameter(paramPathsEnv, 'matcherConfig'); | |
| } |
| let combinedString = ''; | ||
|
|
||
| for (const path of paths) { | ||
| await this.loadParameter(path, 'matcherConfig'); | ||
| combinedString += this.matcherConfig; | ||
| } | ||
|
|
||
| try { | ||
| this.matcherConfig = JSON.parse(combinedString); | ||
| } catch (error) { | ||
| this.configLoadingErrors.push(`Failed to parse combined matcher config: ${(error as Error).message}`); | ||
| } |
Copilot
AI
Oct 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code concatenates this.matcherConfig as a string, but matcherConfig is typed as RunnerMatcherConfig[] (an array). This will result in [object Object] being concatenated instead of the JSON string. Should concatenate the parameter value directly or store it in a temporary variable.
| let combinedString = ''; | |
| for (const path of paths) { | |
| await this.loadParameter(path, 'matcherConfig'); | |
| combinedString += this.matcherConfig; | |
| } | |
| try { | |
| this.matcherConfig = JSON.parse(combinedString); | |
| } catch (error) { | |
| this.configLoadingErrors.push(`Failed to parse combined matcher config: ${(error as Error).message}`); | |
| } | |
| let combinedMatcherConfig: RunnerMatcherConfig[] = []; | |
| for (const path of paths) { | |
| await this.loadParameter(path, 'matcherConfig'); | |
| if (Array.isArray(this.matcherConfig)) { | |
| combinedMatcherConfig.push(...this.matcherConfig); | |
| } else { | |
| this.configLoadingErrors.push(`Matcher config at path "${path}" is not an array`); | |
| } | |
| } | |
| this.matcherConfig = combinedMatcherConfig; |
PR Description
Implements support for splitting the runner matcher configuration across multiple SSM parameters.
PARAMETER_RUNNER_MATCHER_CONFIG_PATHcan now accept multiple parameter paths separated by a colon (:).This avoids SSM size limits for large configurations and improves scalability for environments with many runner types and labels.
Closes #4790