#Terraform

1 messages · Page 1 of 1 (latest)

heavy fiber
#

Yes, but rather than print to screen you need to think more about having the function return a string. When you call a function in the CLI that returns a string, it'll be printed to the screen.

#

As for error types, just need to raise any exception.

heavy fiber
#

Based on your code, a few tips for migration:

  • Instead of a single run_terraform, you can have several functions in a Terraform class:
    • run for general commands → cmd: list[str] as argument, replaces the force argument
    • a function for each key in command_mapping → just calls self.run() with the value of that mapping, replacing it completely
    • not necessary to validate if command is invalid since the function won't be available
  • ColorPrinted can be removed since we'll rely on dagger call TUI
  • For the repo, the functions can accept a dagger.Directory argument. In the CLI you can pass a local directory or a remote repo very easily, without having to change any code
  • ArgumentParser is replaced with normal function arguments
  • No need to manage connection, just from dagger import dag (dag == client)
  • There's two ways to run with the multiple versions:
    • Concurrency like you're doing
    • Have a function return a list of two instances of Terraform, each with the different version. In the CLI you can choose which function from these objects to run and it'll run in parallel, without you having to do concurrency yourself (example, dagger call all apply stdout)
#

Rather than returning the value of stdout it's more flexible to return the dagger.Container. In the CLI you can specify stdout or something else, and any error will be presented to the screen, so you don't need to capture if you're not adding information. For example, the error Error executing {command} on Terraform v{version} {e} isn't useful since that information is already readily available via the module, the function and the arguments that you're calling. Additionally, returning a container allows you to drop into a shell in that container easily, to make it easier to debug.

#

@subtle ginkgo, if you'd give a name to a function that runs what's on __main__, what would that be? Example: dagger call <name>. Easy to have the following:

  • dagger call --src=./terraform run --cmd=some,command stdout (replaces force argument)
  • dagger call --src=./terraform apply stdout (replaces apply command mapping)
  • dagger call --src=./terraform --version=1.4 apply (same as before but overrides the default version 1.5)

Putting the version in the constructor is easier because then you don't have to put it in every function, but then it doesn't make sense if you need multiple versions. Maybe you don't need that and can just have the default and override when needed? Otherwise, you can also create a different object to put the functions (class Instance:), and have the main class Terraform accept just the --src, and include two functions:

  • dagger call --src=./terraform default apply stdout (for the default version, allowing an override);
  • dagger call --src=./terraform all apply stdout (to return a list of two Instance objects, with 1.4 and 1.5 versions (or more), which makes this command run in parallel.

The main object's constructor is exposed as the entrypoint function for a module.

subtle ginkgo
subtle ginkgo
#

I like the version override tho, that makes the most sense to me

heavy fiber
#

Don't know what you intend to do with command fmt and exit_code == 3. Comment says it should be nonterminating but that branch ends there.

#

This is basically it:

from datetime import datetime
from typing import Final

import dagger
from dagger import dag, function, object_type


VERSIONS: Final = ["1.5", "1.4"]
DEFAULT_VERSION: Final = VERSIONS[0]


@object_type
class Terraform:
    src: dagger.Directory
    version: str = DEFAULT_VERSION
    platform: str = "linux/amd64"  # do you need this?

    @function
    def run(self, cmd: list[str]) -> dagger.Container:
        """Run any command in the Terraform container."""
        return (
            dag.container(platform=dagger.Platform(self.platform))
            .from_(f"hashicorp/terraform:{self.version}")
            .with_directory("/terraform", self.src)
            .with_workdir("/terraform")
            # TODO: this enforces a new image build each time - look into leveraging cache
            .with_env_variable("CACHEBUSTER", str(datetime.now()))
            .with_exec(["init", "-input=false", "-upgrade"])
            .with_exec(cmd)
        )

    @function
    def init(self) -> dagger.Container:
        return self.run(["init", "-input=false", "-upgrade"])

    @function
    def plan(self) -> dagger.Container:
        return self.run(["plan", "-input=false"])

    @function
    def apply(self) -> dagger.Container:
        return self.run(["apply", "-input=false", "-auto-approve"])

    @function
    def destroy(self) -> dagger.Container:
        return self.run(["destroy", "-input=false", "-auto-approve"])

    @function
    def validate(self) -> dagger.Container:
        return self.run(["validate", "-json"])

    @function
    def fmt(self) -> dagger.Container:
        return self.run(["fmt", "-recursive", "-check"])
subtle ginkgo
#

Um so basically if the person is running fmt and it returns files that are “at fault” not formatted, it should be more of a warning than an error basically. But that’s not critical

heavy fiber
#

Needs more docstrings:

$ dagger functions
Name       Description
apply      -
destroy    -
fmt        -
init       -
plan       -
run        Run any command in the Terraform container.
validate   -
subtle ginkgo
#

Ok so the thing with the terraform image is that I wasn’t able to figure out how to add in extra applications like terragrunt or vault. I did a revamp and used alpine, but if I can’t take lean docker images of the pure software and combine them that would be sweet

subtle ginkgo
#

Would you be open to a zoom call? Haha this is a HUGE help, but I just have a few questions on how to carry on and like make sure I understand it all

subtle ginkgo
heavy fiber
#

Now it's a bit late for me, are you available tomorrow until your 12pm?

subtle ginkgo
#

I can do 8-10am my time tomorrow!

heavy fiber