Skip to content
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

Feature: Dynamic Working Directory Configuration for Terraform/OpenTofu Tasks #2597

Open
pheus opened this issue Nov 28, 2024 · 3 comments
Open
Labels

Comments

@pheus
Copy link

pheus commented Nov 28, 2024

Related to

Web-Frontend (what users interact with), Web-Backend (APIs), Ansible (task execution)

Impact

major improvement to user experience

Missing Feature

Many Terraform/OpenTofu projects consist of a single Git repository containing multiple Terraform (TF) root modules organized into subdirectories. These subdirectories often represent different stages (e.g., production, development), partial configurations (e.g., per region, per device, or per type), or other organizational structures.

Currently, SemaphoreUI allows users to configure the working directory path for a TF root module in the Task Template. However, this setup necessitates creating a separate Task Template for each TF root module. This limitation complicates configurations, particularly when using SemaphoreUI integrations to trigger task executions through webhooks, as the process becomes unnecessarily complex and verbose.

Introducing a feature to dynamically set the working directory during Task Execution (and through the API) would streamline this workflow significantly. It would eliminate redundant Task Templates and simplify the process for projects with multiple TF root modules.

Implementation

  • Task Template UI:
    Add a checkbox labeled Allow switching working (sub)directory in Task. When enabled, this feature would permit dynamic selection of subdirectories during Task Execution. This checkbox allows project-specific use-case control.

  • Task Execution UI:
    Add a text field where users can specify a subdirectory path relative to the root directory defined in the Task Template. This field should only appear if the Allow switching working (sub)directory in Task option is enabled in the associated Task Template.

  • API Enhancements:
    Extend the API to accept a subdirectory path as part of the task execution payload.
    Example payload addition:

    {
      "template_id": "template-id",
      "sub_directory": "path/to/subdir"
    }
  • Environment Variable Support:
    Allow configuration of the subdirectory path via an environment variable. This would enable use of the Integrations ExtractValue mechanism to dynamically specify the relevant subdirectory during runtime.

Design

Terraform and OpenTofu allow changing the working directory before executing a subcommand by using the terraform -chdir=DIR <sub-command> parameter. Since this parameter is not part of the subcommand itself, it cannot be configured using the TF_CLI_ARGS environment variable (refer to Terraform Issue #28037).

This feature requires modifying every Terraform/OpenTofu command execution (e.g., init, plan, apply, destroy) to include the -chdir option dynamically, based on the subdirectory provided.

Implementation Considerations:

  1. UI Design:

    • The Allow switching working (sub)directory in Task checkbox in the Task Template UI should default to "off" to maintain backward compatibility.
    • The Task Execution text field should validate the subdirectory path to ensure it is relative and exists within the repository.
  2. API Design:

    • The API must validate the sub_directory field to ensure security and proper scoping (e.g., prevent attempts to access directories outside the repository).
  3. Environment Variable Integration:

    • The system should prioritize the environment variable setting if it is present, falling back to user-entered values in the Task Execution UI or API.
    • Ensure the environment variable mechanism aligns with other Terraform CLI argument settings.
  4. Edge Cases:

    • Invalid Directory Paths: Handle errors gracefully if the specified subdirectory is invalid or does not exist.
    • Security Concerns: Prevent directory traversal attacks (e.g., paths like ../../).
    • Empty Subdirectory Field: If no subdirectory is provided, default to the root directory specified in the Task Template.
    • Concurrency: Handle concurrent executions where different subdirectories are specified for the same Task Template.
@pheus pheus added the feature label Nov 28, 2024
@rismoney
Copy link

This is a really thought out idea. Kudos for opening it. We use this model heavily.

I figured I would add-on some thoughts based on a very comprehensive workflow I have been using.

Should subdirectory be an array of paths? In our current Jenkins pipeline we are inspecting changesets and/or using git diffs to detect changes in subdirectories. We then loop through all changes in a PR across directories and run TF inside each one. Orthogonal to this we lookup a json file that determines which agent(jenkins runner tag)/tf version to use based on the subdirectory. This allows us to stage upgrades of the terraform.exe before using it on every subdirectory.

Would this proposal accommodate none, some, all of this? I am definitely willing to lean into alternative worfklows for simplification.

@pheus
Copy link
Author

pheus commented Dec 18, 2024

Thank you for the feedback and for sharing your comprehensive workflow! Your use case introduces some advanced considerations that could enhance the proposed feature.

That said, I believe a single task execution should represent only one deployment—in this case, a single Terraform root module. Handling multiple deployments within a single task would be better suited for a workflow model, which is not currently supported by SemaphoreUI.

Of course, that’s just my perspective.

@rismoney
Copy link

Multiple TF roots is kind of inherent in a mono repo. I am not sure how you would approach git changes in multiple directories without looping through those dirs and running TF in either the same or separate task?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants