From 95af4c22520ba5c2f8b7cd9ce2d8ae6389183bdb Mon Sep 17 00:00:00 2001 From: yashdeep Date: Mon, 8 Dec 2025 16:32:17 +0530 Subject: [PATCH 1/9] feat(asg): add InstanceRequirements support via JSON config Add support for specifying instance requirements in Auto Scaling Group mixed instances policy LaunchTemplateOverrides. Configuration is provided via SEMAPHORE_AGENT_MIXED_POLICY_INSTANCE_REQUIREMENTS_JSON parameter as JSON, allowing full control over instance selection attributes. --- lib/argument-store.js | 1 + lib/aws-semaphore-agent-stack.js | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/argument-store.js b/lib/argument-store.js index c4b3118..0282129 100644 --- a/lib/argument-store.js +++ b/lib/argument-store.js @@ -46,6 +46,7 @@ class ArgumentStore { "SEMAPHORE_AGENT_ON_DEMAND_BASE_CAPACITY": "0", "SEMAPHORE_AGENT_ON_DEMAND_PERCENTAGE_ABOVE_BASE": "100", "SEMAPHORE_AGENT_SPOT_ALLOCATION_STRATEGY": "", + "SEMAPHORE_AGENT_MIXED_POLICY_INSTANCE_REQUIREMENTS_JSON": "", } static validOverprovisionStrategies = ["none", "number", "percentage"] diff --git a/lib/aws-semaphore-agent-stack.js b/lib/aws-semaphore-agent-stack.js index 6b0ba61..0ddec9c 100644 --- a/lib/aws-semaphore-agent-stack.js +++ b/lib/aws-semaphore-agent-stack.js @@ -497,7 +497,7 @@ class AwsSemaphoreAgentStack extends Stack { instancesDistribution.spotAllocationStrategy = spotAllocationStrategy; } - autoScalingGroupProps.mixedInstancesPolicy = { + const mixedInstancesPolicy = { instancesDistribution: instancesDistribution, launchTemplate: { launchTemplateSpecification: { @@ -507,6 +507,13 @@ class AwsSemaphoreAgentStack extends Stack { } }; + if (!this.argumentStore.isEmpty("SEMAPHORE_AGENT_MIXED_POLICY_INSTANCE_REQUIREMENTS_JSON")) { + const instanceRequirements = JSON.parse(this.argumentStore.get("SEMAPHORE_AGENT_MIXED_POLICY_INSTANCE_REQUIREMENTS_JSON")); + mixedInstancesPolicy.launchTemplate.overrides = [{ instanceRequirements }]; + } + + autoScalingGroupProps.mixedInstancesPolicy = mixedInstancesPolicy; + let autoScalingGroup = new CfnAutoScalingGroup(this, 'autoScalingGroup', autoScalingGroupProps); const maxInstanceLifetime = this.argumentStore.getAsNumber("SEMAPHORE_AGENT_ASG_MAX_INSTANCE_LIFETIME"); From ebf048b4a306726c52ac76c2326556a6cdc2ecfa Mon Sep 17 00:00:00 2001 From: yashdeep Date: Mon, 8 Dec 2025 22:44:27 +0530 Subject: [PATCH 2/9] updating name of the argument --- lib/argument-store.js | 2 +- lib/aws-semaphore-agent-stack.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/argument-store.js b/lib/argument-store.js index 0282129..207d428 100644 --- a/lib/argument-store.js +++ b/lib/argument-store.js @@ -15,6 +15,7 @@ class ArgumentStore { "SEMAPHORE_AGENT_ASG_DESIRED": "", "SEMAPHORE_AGENT_ASG_METRICS": "", "SEMAPHORE_AGENT_ASG_MAX_INSTANCE_LIFETIME": "0", + "SEMAPHORE_AGENT_ASG_INSTANCE_REQUIREMENTS_JSON": "", "SEMAPHORE_AGENT_DISCONNECT_AFTER_JOB": "true", "SEMAPHORE_AGENT_DISCONNECT_AFTER_IDLE_TIMEOUT": "300", "SEMAPHORE_AGENT_OS": "ubuntu-focal", @@ -46,7 +47,6 @@ class ArgumentStore { "SEMAPHORE_AGENT_ON_DEMAND_BASE_CAPACITY": "0", "SEMAPHORE_AGENT_ON_DEMAND_PERCENTAGE_ABOVE_BASE": "100", "SEMAPHORE_AGENT_SPOT_ALLOCATION_STRATEGY": "", - "SEMAPHORE_AGENT_MIXED_POLICY_INSTANCE_REQUIREMENTS_JSON": "", } static validOverprovisionStrategies = ["none", "number", "percentage"] diff --git a/lib/aws-semaphore-agent-stack.js b/lib/aws-semaphore-agent-stack.js index 0ddec9c..7309991 100644 --- a/lib/aws-semaphore-agent-stack.js +++ b/lib/aws-semaphore-agent-stack.js @@ -507,8 +507,8 @@ class AwsSemaphoreAgentStack extends Stack { } }; - if (!this.argumentStore.isEmpty("SEMAPHORE_AGENT_MIXED_POLICY_INSTANCE_REQUIREMENTS_JSON")) { - const instanceRequirements = JSON.parse(this.argumentStore.get("SEMAPHORE_AGENT_MIXED_POLICY_INSTANCE_REQUIREMENTS_JSON")); + if (!this.argumentStore.isEmpty("SEMAPHORE_AGENT_ASG_INSTANCE_REQUIREMENTS_JSON")) { + const instanceRequirements = JSON.parse(this.argumentStore.get("SEMAPHORE_AGENT_ASG_INSTANCE_REQUIREMENTS_JSON")); mixedInstancesPolicy.launchTemplate.overrides = [{ instanceRequirements }]; } From 4ae47e79582427c80c54b11b0fe3134838201e92 Mon Sep 17 00:00:00 2001 From: yashdeep Date: Tue, 9 Dec 2025 14:35:34 +0530 Subject: [PATCH 3/9] adding on demand allocation strategy --- lib/argument-store.js | 1 + lib/aws-semaphore-agent-stack.js | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/lib/argument-store.js b/lib/argument-store.js index 207d428..fa34582 100644 --- a/lib/argument-store.js +++ b/lib/argument-store.js @@ -46,6 +46,7 @@ class ArgumentStore { "SEMAPHORE_AGENT_ALLOW_PUBLIC_SUBNET": "false", "SEMAPHORE_AGENT_ON_DEMAND_BASE_CAPACITY": "0", "SEMAPHORE_AGENT_ON_DEMAND_PERCENTAGE_ABOVE_BASE": "100", + "SEMAPHORE_AGENT_ON_DEMAND_ALLOCATION_STRATEGY": "", "SEMAPHORE_AGENT_SPOT_ALLOCATION_STRATEGY": "", } diff --git a/lib/aws-semaphore-agent-stack.js b/lib/aws-semaphore-agent-stack.js index 7309991..af5c2dc 100644 --- a/lib/aws-semaphore-agent-stack.js +++ b/lib/aws-semaphore-agent-stack.js @@ -474,6 +474,7 @@ class AwsSemaphoreAgentStack extends Stack { const onDemandBaseCapacity = this.argumentStore.getAsNumber("SEMAPHORE_AGENT_ON_DEMAND_BASE_CAPACITY"); const onDemandPercentageAboveBase = this.argumentStore.getAsNumber("SEMAPHORE_AGENT_ON_DEMAND_PERCENTAGE_ABOVE_BASE"); const spotAllocationStrategy = this.argumentStore.get("SEMAPHORE_AGENT_SPOT_ALLOCATION_STRATEGY"); + const onDemandAllocationStrategy = this.argumentStore.get("SEMAPHORE_AGENT_ON_DEMAND_ALLOCATION_STRATEGY"); let autoScalingGroupProps = { minSize: this.argumentStore.get("SEMAPHORE_AGENT_ASG_MIN_SIZE"), @@ -497,6 +498,10 @@ class AwsSemaphoreAgentStack extends Stack { instancesDistribution.spotAllocationStrategy = spotAllocationStrategy; } + if (onDemandAllocationStrategy != "") { + instancesDistribution.onDemandAllocationStrategy = onDemandAllocationStrategy; + } + const mixedInstancesPolicy = { instancesDistribution: instancesDistribution, launchTemplate: { From 9e13c551ae83ef6603f94d0bcdecf77194dd3501 Mon Sep 17 00:00:00 2001 From: yashdeep Date: Tue, 9 Dec 2025 15:04:30 +0530 Subject: [PATCH 4/9] updating argument name to SEMAPHORE_AGENT_ASG_LAUNCH_TEMPLATE_OVERRIDES_JSON --- lib/argument-store.js | 2 +- lib/aws-semaphore-agent-stack.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/argument-store.js b/lib/argument-store.js index fa34582..cc82d64 100644 --- a/lib/argument-store.js +++ b/lib/argument-store.js @@ -15,7 +15,7 @@ class ArgumentStore { "SEMAPHORE_AGENT_ASG_DESIRED": "", "SEMAPHORE_AGENT_ASG_METRICS": "", "SEMAPHORE_AGENT_ASG_MAX_INSTANCE_LIFETIME": "0", - "SEMAPHORE_AGENT_ASG_INSTANCE_REQUIREMENTS_JSON": "", + "SEMAPHORE_AGENT_ASG_LAUNCH_TEMPLATE_OVERRIDES_JSON": "", "SEMAPHORE_AGENT_DISCONNECT_AFTER_JOB": "true", "SEMAPHORE_AGENT_DISCONNECT_AFTER_IDLE_TIMEOUT": "300", "SEMAPHORE_AGENT_OS": "ubuntu-focal", diff --git a/lib/aws-semaphore-agent-stack.js b/lib/aws-semaphore-agent-stack.js index af5c2dc..24d695b 100644 --- a/lib/aws-semaphore-agent-stack.js +++ b/lib/aws-semaphore-agent-stack.js @@ -512,9 +512,9 @@ class AwsSemaphoreAgentStack extends Stack { } }; - if (!this.argumentStore.isEmpty("SEMAPHORE_AGENT_ASG_INSTANCE_REQUIREMENTS_JSON")) { - const instanceRequirements = JSON.parse(this.argumentStore.get("SEMAPHORE_AGENT_ASG_INSTANCE_REQUIREMENTS_JSON")); - mixedInstancesPolicy.launchTemplate.overrides = [{ instanceRequirements }]; + if (!this.argumentStore.isEmpty("SEMAPHORE_AGENT_ASG_LAUNCH_TEMPLATE_OVERRIDES_JSON")) { + const launchTemplateOverrides = JSON.parse(this.argumentStore.get("SEMAPHORE_AGENT_ASG_LAUNCH_TEMPLATE_OVERRIDES_JSON")); + mixedInstancesPolicy.launchTemplate.overrides = [launchTemplateOverrides]; } autoScalingGroupProps.mixedInstancesPolicy = mixedInstancesPolicy; From 817a194bc9f51031f81a7d001ac853cef336504d Mon Sep 17 00:00:00 2001 From: yashdeep Date: Wed, 10 Dec 2025 06:33:18 +0530 Subject: [PATCH 5/9] adding ability to control SEMAPHORE_AGENT_ASG_CAPACITY_REBALANCE --- lib/argument-store.js | 1 + lib/aws-semaphore-agent-stack.js | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/lib/argument-store.js b/lib/argument-store.js index cc82d64..4b0cbd7 100644 --- a/lib/argument-store.js +++ b/lib/argument-store.js @@ -48,6 +48,7 @@ class ArgumentStore { "SEMAPHORE_AGENT_ON_DEMAND_PERCENTAGE_ABOVE_BASE": "100", "SEMAPHORE_AGENT_ON_DEMAND_ALLOCATION_STRATEGY": "", "SEMAPHORE_AGENT_SPOT_ALLOCATION_STRATEGY": "", + "SEMAPHORE_AGENT_ASG_CAPACITY_REBALANCE": "false" } static validOverprovisionStrategies = ["none", "number", "percentage"] diff --git a/lib/aws-semaphore-agent-stack.js b/lib/aws-semaphore-agent-stack.js index 24d695b..670495d 100644 --- a/lib/aws-semaphore-agent-stack.js +++ b/lib/aws-semaphore-agent-stack.js @@ -545,6 +545,11 @@ class AwsSemaphoreAgentStack extends Stack { } ] } + + const capacityRebalance = this.argumentStore.getAsBool("SEMAPHORE_AGENT_ASG_CAPACITY_REBALANCE"); + if (capacityRebalance) { + autoScalingGroup.capacityRebalance = capacityRebalance ; + } if (!this.argumentStore.isEmpty("SEMAPHORE_AGENT_AZS")) { autoScalingGroup.availabilityZones = this.argumentStore.getAsList("SEMAPHORE_AGENT_AZS"); From bdebecb2d61f52df14e3c8d087c1454686c102cb Mon Sep 17 00:00:00 2001 From: yashdeep Date: Wed, 10 Dec 2025 10:53:49 +0530 Subject: [PATCH 6/9] adding ability to control SEMAPHORE_AGENT_ASG_CAPACITY_REBALANCE --- lib/aws-semaphore-agent-stack.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/aws-semaphore-agent-stack.js b/lib/aws-semaphore-agent-stack.js index 670495d..c7b1556 100644 --- a/lib/aws-semaphore-agent-stack.js +++ b/lib/aws-semaphore-agent-stack.js @@ -545,11 +545,8 @@ class AwsSemaphoreAgentStack extends Stack { } ] } - - const capacityRebalance = this.argumentStore.getAsBool("SEMAPHORE_AGENT_ASG_CAPACITY_REBALANCE"); - if (capacityRebalance) { - autoScalingGroup.capacityRebalance = capacityRebalance ; - } + + autoScalingGroup.capacityRebalance = this.argumentStore.getAsBool("SEMAPHORE_AGENT_ASG_CAPACITY_REBALANCE"); if (!this.argumentStore.isEmpty("SEMAPHORE_AGENT_AZS")) { autoScalingGroup.availabilityZones = this.argumentStore.getAsList("SEMAPHORE_AGENT_AZS"); From 678851781dc9f71ed1ad5413c1dc618c2e2043fd Mon Sep 17 00:00:00 2001 From: yashdeep Date: Tue, 23 Dec 2025 13:01:21 +0530 Subject: [PATCH 7/9] semaphore: adding more collect paths in cludwatch logs SNE-51317 --- .../files/cloudwatch-agent-config.json | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/packer/linux/ansible/roles/cloudwatch_agent/files/cloudwatch-agent-config.json b/packer/linux/ansible/roles/cloudwatch_agent/files/cloudwatch-agent-config.json index 8ef61d7..04b16c1 100644 --- a/packer/linux/ansible/roles/cloudwatch_agent/files/cloudwatch-agent-config.json +++ b/packer/linux/ansible/roles/cloudwatch_agent/files/cloudwatch-agent-config.json @@ -47,6 +47,62 @@ "log_stream_name": "{instance_id}", "timestamp_format": "%b %d %H:%M:%S", "retention_in_days": 30 + }, + { + "file_path": "/var/log/syslog", + "log_group_name": "/semaphore/system/syslog", + "log_stream_name": "{instance_id}", + "timestamp_format": "%b %d %H:%M:%S", + "retention_in_days": 30 + }, + { + "file_path": "/var/log/auth.log", + "log_group_name": "/semaphore/auth", + "log_stream_name": "{instance_id}", + "timestamp_format": "%b %d %H:%M:%S", + "retention_in_days": 30 + }, + { + "file_path": "/var/log/kern.log", + "log_group_name": "/semaphore/kernel", + "log_stream_name": "{instance_id}", + "timestamp_format": "%b %d %H:%M:%S", + "retention_in_days": 30 + }, + { + "file_path": "/var/log/dmesg", + "log_group_name": "/semaphore/dmesg", + "log_stream_name": "{instance_id}", + "timestamp_format": "%b %d %H:%M:%S", + "retention_in_days": 30 + }, + { + "file_path": "/var/log/dmesg.0", + "log_group_name": "/semaphore/dmesg", + "log_stream_name": "{instance_id}-0", + "timestamp_format": "%b %d %H:%M:%S", + "retention_in_days": 30 + }, + { + "file_path": "/var/log/dpkg.log", + "log_group_name": "/semaphore/dpkg", + "log_stream_name": "{instance_id}", + "timestamp_format": "%Y-%m-%d %H:%M:%S", + "retention_in_days": 30 + }, + { + "file_path": "/var/log/alternatives.log", + "log_group_name": "/semaphore/alternatives", + "log_stream_name": "{instance_id}", + "timestamp_format": "%Y-%m-%d %H:%M:%S", + "retention_in_days": 30 + }, + { + "file_path": "/var/log/amazon/ssm/*.log", + "log_group_name": "/semaphore/amazon-ssm", + "log_stream_name": "{instance_id}", + "timestamp_format": "%Y-%m-%d %H:%M:%S", + "retention_in_days": 30 } ] } From 66d57bb99672684eb2d3c35325b05a6c34c9a983 Mon Sep 17 00:00:00 2001 From: yashdeep Date: Mon, 5 Jan 2026 22:00:40 +0530 Subject: [PATCH 8/9] semaphore: (revert) adding more collect paths in cloudwatch logs --- .../files/cloudwatch-agent-config.json | 56 ------------------- 1 file changed, 56 deletions(-) diff --git a/packer/linux/ansible/roles/cloudwatch_agent/files/cloudwatch-agent-config.json b/packer/linux/ansible/roles/cloudwatch_agent/files/cloudwatch-agent-config.json index 04b16c1..8ef61d7 100644 --- a/packer/linux/ansible/roles/cloudwatch_agent/files/cloudwatch-agent-config.json +++ b/packer/linux/ansible/roles/cloudwatch_agent/files/cloudwatch-agent-config.json @@ -47,62 +47,6 @@ "log_stream_name": "{instance_id}", "timestamp_format": "%b %d %H:%M:%S", "retention_in_days": 30 - }, - { - "file_path": "/var/log/syslog", - "log_group_name": "/semaphore/system/syslog", - "log_stream_name": "{instance_id}", - "timestamp_format": "%b %d %H:%M:%S", - "retention_in_days": 30 - }, - { - "file_path": "/var/log/auth.log", - "log_group_name": "/semaphore/auth", - "log_stream_name": "{instance_id}", - "timestamp_format": "%b %d %H:%M:%S", - "retention_in_days": 30 - }, - { - "file_path": "/var/log/kern.log", - "log_group_name": "/semaphore/kernel", - "log_stream_name": "{instance_id}", - "timestamp_format": "%b %d %H:%M:%S", - "retention_in_days": 30 - }, - { - "file_path": "/var/log/dmesg", - "log_group_name": "/semaphore/dmesg", - "log_stream_name": "{instance_id}", - "timestamp_format": "%b %d %H:%M:%S", - "retention_in_days": 30 - }, - { - "file_path": "/var/log/dmesg.0", - "log_group_name": "/semaphore/dmesg", - "log_stream_name": "{instance_id}-0", - "timestamp_format": "%b %d %H:%M:%S", - "retention_in_days": 30 - }, - { - "file_path": "/var/log/dpkg.log", - "log_group_name": "/semaphore/dpkg", - "log_stream_name": "{instance_id}", - "timestamp_format": "%Y-%m-%d %H:%M:%S", - "retention_in_days": 30 - }, - { - "file_path": "/var/log/alternatives.log", - "log_group_name": "/semaphore/alternatives", - "log_stream_name": "{instance_id}", - "timestamp_format": "%Y-%m-%d %H:%M:%S", - "retention_in_days": 30 - }, - { - "file_path": "/var/log/amazon/ssm/*.log", - "log_group_name": "/semaphore/amazon-ssm", - "log_stream_name": "{instance_id}", - "timestamp_format": "%Y-%m-%d %H:%M:%S", - "retention_in_days": 30 } ] } From 4ad3e436e7cb858f3579cd57344b9fe8ffa0d120 Mon Sep 17 00:00:00 2001 From: yashdeep Date: Mon, 5 Jan 2026 22:47:22 +0530 Subject: [PATCH 9/9] feat(asg): add new instances protected from scale-in config Add SEMAPHORE_AGENT_ASG_NEW_INSTANCES_PROTECTED_FROM_SCALE_IN parameter to control whether new instances in the Auto Scaling Group are protected from scale-in operations. Defaults to false. --- lib/argument-store.js | 3 ++- lib/aws-semaphore-agent-stack.js | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/argument-store.js b/lib/argument-store.js index 4b0cbd7..fbcd1db 100644 --- a/lib/argument-store.js +++ b/lib/argument-store.js @@ -48,7 +48,8 @@ class ArgumentStore { "SEMAPHORE_AGENT_ON_DEMAND_PERCENTAGE_ABOVE_BASE": "100", "SEMAPHORE_AGENT_ON_DEMAND_ALLOCATION_STRATEGY": "", "SEMAPHORE_AGENT_SPOT_ALLOCATION_STRATEGY": "", - "SEMAPHORE_AGENT_ASG_CAPACITY_REBALANCE": "false" + "SEMAPHORE_AGENT_ASG_CAPACITY_REBALANCE": "false", + "SEMAPHORE_AGENT_ASG_NEW_INSTANCES_PROTECTED_FROM_SCALE_IN": "false" } static validOverprovisionStrategies = ["none", "number", "percentage"] diff --git a/lib/aws-semaphore-agent-stack.js b/lib/aws-semaphore-agent-stack.js index c7b1556..e25dc32 100644 --- a/lib/aws-semaphore-agent-stack.js +++ b/lib/aws-semaphore-agent-stack.js @@ -547,6 +547,7 @@ class AwsSemaphoreAgentStack extends Stack { } autoScalingGroup.capacityRebalance = this.argumentStore.getAsBool("SEMAPHORE_AGENT_ASG_CAPACITY_REBALANCE"); + autoScalingGroup.newInstancesProtectedFromScaleIn = this.argumentStore.getAsBool("SEMAPHORE_AGENT_ASG_NEW_INSTANCES_PROTECTED_FROM_SCALE_IN"); if (!this.argumentStore.isEmpty("SEMAPHORE_AGENT_AZS")) { autoScalingGroup.availabilityZones = this.argumentStore.getAsList("SEMAPHORE_AGENT_AZS");