Skip to content

feat(gemini): A Terraform module to schedule the whimsical slumber (stopping) and awakening (starting) of AWS EC2 instances during off-peak hours, optimizing cloud costs. - #5815

Open
polsala wants to merge 1 commit into
mainfrom
ai/gemini-20260831-1841
Open

feat(gemini): A Terraform module to schedule the whimsical slumber (stopping) and awakening (starting) of AWS EC2 instances during off-peak hours, optimizing cloud costs.#5815
polsala wants to merge 1 commit into
mainfrom
ai/gemini-20260831-1841

Conversation

@polsala

@polsala polsala commented Aug 31, 2026

Copy link
Copy Markdown
Owner

Implementation Summary

  • Utility: nightly-cloud-slumber-sentinel
  • Provider: gemini
  • Location: terraform-modules/nightly-nightly-cloud-slumber-sentin
  • Files Created: 7
  • Description: A Terraform module to schedule the whimsical slumber (stopping) and awakening (starting) of AWS EC2 instances during off-peak hours, optimizing cloud costs.

Rationale

  • Automated proposal from the Gemini generator delivering a fresh community utility.
  • This utility was generated using the gemini AI provider.

Why safe to merge

  • Utility is isolated to terraform-modules/nightly-nightly-cloud-slumber-sentin.
  • README + tests ship together (see folder contents).
  • No secrets or credentials touched.
  • All changes are additive and self-contained.

Test Plan

  • Follow the instructions in the generated README at terraform-modules/nightly-nightly-cloud-slumber-sentin/README.md
  • Run tests located in terraform-modules/nightly-nightly-cloud-slumber-sentin/tests/

Links

  • Generated docs and examples committed alongside this change.

Mock Justification

  • Not applicable; generator did not introduce new mocks.

…topping) and awakening (starting) of AWS EC2 instances during off-peak hours, optimizing cloud costs.
@polsala

polsala commented Aug 31, 2026

Copy link
Copy Markdown
Owner Author

🤖 Review by GROQ Agent

✅ What's solid

  • Clear purpose & value – The module addresses a common cost‑optimization pattern (stop/start EC2 on a schedule) and does so with a tidy, self‑contained Terraform implementation.
  • Good separation of concerns – Provider, locals, variables, resources, and outputs are each in their own file, making the codebase easy to navigate.
  • Version pinningversions.tf locks the AWS, archive, local and random providers to recent, compatible releases and enforces a minimum Terraform version.
  • Comprehensive README – The documentation explains the problem, shows a full usage example, lists inputs/outputs, and provides a quick “run the tests” guide.
  • Basic CI‑style test scripttest_plan.sh runs terraform init, validate and a destroy‑plan, giving fast feedback that the module can be parsed and planned without touching real resources.

🧪 Tests

  • Scope of testing – The current test only validates Terraform syntax and that a plan can be generated. Consider adding:
    • terraform fmt -check to enforce consistent formatting.
    • Static analysis with tflint or checkov to catch common anti‑patterns (e.g., overly permissive IAM policies).
    • Unit‑style Lambda validation – package the Python code and run a quick lint (flake8/pylint) or a smoke‑test that invokes the handler with a mock event to ensure the payload handling works.
  • Deterministic provider configuration – The test uses the real aws provider with a dummy region. While this works for plan -destroy, any data source that contacts AWS would fail without credentials. To guarantee offline execution, either:
    provider "aws" {
      region = "us-east-1"
      skip_credentials_validation = true
      skip_requesting_account_id   = true
    }
    or replace the provider with the null provider for pure syntax checks.
  • Coverage of edge cases – Add a second test case that supplies an empty instance_tags map to verify the Lambda returns early (as coded) and that the Terraform plan still succeeds.

🔒 Security

  • IAM role permissions – The module likely creates an IAM role for the Lambda (not shown in the diff). Ensure the policy follows the principle of least privilege:
    policy = jsonencode({
      Version = "2012-10-17"
      Statement = [
        {
          Effect   = "Allow"
          Action   = [
            "ec2:DescribeInstances",
            "ec2:StartInstances",
            "ec2:StopInstances"
          ]
          Resource = "*"
          Condition = {
            StringEquals = {
              "ec2:ResourceTag/${var.instance_tags_key}" = var.instance_tags_value
            }
          }
        },
        {
          Effect   = "Allow"
          Action   = [
            "logs:CreateLogGroup",
            "logs:CreateLogStream",
            "logs:PutLogEvents"
          ]
          Resource = "arn:aws:logs:${var.aws_region}:${data.aws_caller_identity.current.account_id}:*"
        }
      ]
    })
    If the current policy uses "*" for resources, tighten it to the specific EC2 instances identified by the tag filter.
  • No hard‑coded secrets – Good that the PR states “no secrets or credentials touched.” Verify that the Lambda code does not embed any AWS keys or other secrets; rely on the execution role instead.
  • Lambda code packaging – The local.lambda_python_code is embedded as a heredoc. Ensure the archive_file data source (presumably elsewhere) creates a zip without exposing the source on the filesystem. If the zip is written to the repo (slumber_manager.zip), add it to .gitignore and generate it during CI.

🧩 Docs/DX

  • Module source path typo – The folder is named nightly-nightly-cloud-slumber-sentin (missing “el”). This inconsistency can confuse users when they reference the module via a relative path or a registry source. Rename the directory to nightly-cloud-slumber-sentinel and update the README accordingly.
  • Version badge – Adding a Terraform Registry badge (or a simple “Latest version: 0.1.0”) helps consumers quickly see the release status.
  • Example with registry source – Show how to pull the module from a public registry, e.g.:
    module "slumber_sentinel" {
      source  = "github.com/yourorg/terraform-modules//nightly-cloud-slumber-sentinel?ref=v0.1.0"
      # …variables…
    }
  • Explain the cron format – The README mentions cron(0 22 * * ? *) but does not note that this is the CloudWatch Events cron syntax (which differs from standard Unix cron). A short note or link prevents misuse.
  • Link to Lambda source – If you expose the Python code (e.g., src/main.py), reference it in the docs so developers can extend/customize the handler.

🧱 Mocks/Fakes

  • Test harness uses a “dummy” AWS provider – This is fine for static checks, but if future tests need to evaluate IAM policies or CloudWatch rule attributes, consider using the terraform-provider-mock or the local provider to stub out resources. Example:
    provider "aws" {
      region = "us-east-1"
      # Enable mock mode (requires the mock provider plugin)
      mock = true
    }
  • Lambda zip artifact – The test script deletes ../src/slumber_manager.zip after the run, but the module may expect that file to exist during terraform plan. Ensure the module builds the zip on‑the‑fly (using archive_file) rather than relying on a pre‑committed artifact. If a pre‑built zip is required for offline testing, add it to the test’s setup step and list it in .gitignore to avoid accidental commits.
  • Mock rationale comments – The test file already includes helpful comments explaining why the provider is mocked. Keep this practice for any future test modules; it aids reviewers and CI logs.

Overall impression: The module delivers a useful, well‑documented capability with a clean Terraform layout. Address the minor naming typo, tighten IAM permissions, and expand the test suite to cover formatting, static analysis, and Lambda code linting. Once those tweaks are in place, the utility will be robust, secure, and developer‑friendly.

@polsala

polsala commented Aug 31, 2026

Copy link
Copy Markdown
Owner Author

🤖 Review by GROQ Agent

✅ What's solid

  • Clear purpose & scope – the module’s intent (cost‑saving start/stop of EC2 instances) is well‑articulated in the README and the code is nicely self‑contained.
  • Good use of Terraform features – provider constraints, archive for Lambda packaging, random_id for unique naming, and explicit output values are all present.
  • Parameterisation – all configurable items (region, tags, cron schedules, Lambda memory/timeout) are exposed as variables with sensible defaults.
  • Basic test harness – a test_plan.sh script that runs terraform init, validate and a destroy‑plan gives a quick sanity check that the module parses correctly.
  • Documentation layout – the README follows the conventional Terraform module layout (Features, Usage, Inputs, Outputs, Development & Testing, Contributing).

🧪 Tests

  • Expand coverage beyond syntax

    • The current test only validates that Terraform can plan a destroy. Add a regular terraform plan (creation) run to ensure resources are defined correctly for provisioning.

    • Example snippet to add to test_plan.sh:

      echo "Generating a normal Terraform plan..."
      terraform plan -out=tfplan-create
  • Validate Lambda packaging

    • The module relies on an inline Python string (local.lambda_python_code) that is later archived. Include a check that the resulting zip file exists and contains main.py.

      if [ ! -f ../src/slumber_manager.zip ]; then
        echo "❌ Lambda zip not generated"
        exit 1
      fi
  • Mock AWS calls

    • Even though plan is offline, the provider still performs a dry‑run of API calls (e.g., IAM policy validation). Configure the AWS provider for offline testing to avoid accidental credential usage:

      provider "aws" {
        region                      = "us-east-1"
        skip_credentials_validation = true
        skip_metadata_api_check      = true
        access_key                  = "mock"
        secret_key                  = "mock"
      }
  • Add a unit‑style test for the Lambda payload

    • Consider a small Python test (e.g., using pytest) that imports the generated main.py and verifies that the handler returns the expected status codes for missing/invalid actions. This can be run in CI alongside the Terraform tests.

🔒 Security

  • Least‑privilege IAM role

    • The IAM role attached to the Lambda likely grants ec2:* on all resources. Tighten the policy to the specific actions (DescribeInstances, StartInstances, StopInstances) and scope them to instances that match the supplied tags using condition keys:

      {
        "Effect": "Allow",
        "Action": [
          "ec2:DescribeInstances",
          "ec2:StartInstances",
          "ec2:StopInstances"
        ],
        "Resource": "*",
        "Condition": {
          "StringEquals": {
            "ec2:ResourceTag/Slumber": "true"
          }
        }
      }
  • Validate input cron expressions

    • The module accepts arbitrary strings for stop_cron_schedule and start_cron_schedule. Add a validation block to each variable to ensure they match the cron() pattern, preventing malformed schedules that could cause runtime errors.

      variable "stop_cron_schedule" {
        type = string
        validation {
          condition     = can(regex("^cron\\(.+\\)$", var.stop_cron_schedule))
          error_message = "stop_cron_schedule must be a valid CloudWatch Events cron expression."
        }
      }
  • Avoid hard‑coded AWS provider version

    • The required_providers block pins aws to ~> 5.0. While fine, consider adding a comment that the module has been tested against the latest 5.x series to avoid surprises when a new major version is released.
  • Secure handling of Lambda code

    • The inline Python code is stored in a Terraform local. Ensure that any future additions (e.g., third‑party libraries) are packaged via the archive_file data source rather than concatenating strings, which can be error‑prone and harder to audit.

🧩 Docs / Developer Experience

  • Consistent naming

    • The folder is named nightly-nightly-cloud-slumber-sentin (missing the trailing “el”). Align the directory name with the module name (nightly-cloud-slumber-sentinel) to avoid confusion when users reference the path.
  • Source reference in README

    • The usage example shows source = "./path/to/nightly-cloud-slumber-sentinel/src". Provide a canonical source line for registry users, e.g.:

      source = "git::https://github.com/yourorg/terraform-modules.git//nightly-cloud-slumber-sentinel?ref=v1.0.0"
  • Explain required IAM permissions for the caller

    • Document that the user applying the module must have permissions to create IAM roles, Lambda functions, and CloudWatch Event rules. This helps operators troubleshoot permission errors.
  • Add a version badge

    • A simple badge (e.g., ![Terraform Version](https://img.shields.io/badge/Terraform-%3E%3D1.0-blue)) gives quick visibility on compatibility.
  • Clarify test expectations

    • In the “Development & Testing” section, note that the test script runs offline and does not require AWS credentials. This sets the right expectation for contributors.

🧱 Mocks / Fakes

  • Explicit mock rationale in test config

    • The test file already includes comments about using a dummy region, but the provider block could be made more explicit by adding the mock credentials shown earlier. This prevents accidental use of real credentials in CI pipelines.
  • Separate mock module for CI

    • Consider adding a tests/mock.tf that defines a null_resource or local_file to simulate the Lambda zip creation, ensuring the plan step does not depend on the presence of the Python source file on the CI runner.
  • Avoid reliance on relative paths

    • The test module sources ../src. If the repository layout changes, the test will break. Use a Terraform module block with a source = "${path.module}/../src" expression to make the path robust.

Summary of actionable items

  1. Rename the module directory to include the missing “el”.
  2. Add provider mock credentials (skip_credentials_validation, etc.) in the test provider "aws" block.
  3. Extend test_plan.sh to run a normal plan, verify the Lambda zip, and optionally lint the generated Python.
  4. Restrict the IAM policy to tag‑scoped actions and list only required permissions.
  5. Add variable validation for cron expressions.
  6. Update README with a canonical source line, version badge, and clearer test expectations.
  7. Consider a small Python unit test for the Lambda handler logic.
  8. Document caller IAM requirements in the README.

These tweaks will tighten security, improve reliability of the test suite, and make the module easier to adopt and maintain.

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