Skip to content

BL-255 | Add tofu command to cli #305

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

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions leverage/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,12 @@ def __init__(self, client, mounts: tuple = None, env_vars: dict = None):
self.project = self.paths.project

# Set image to use
self.image = self.env_conf.get("TERRAFORM_IMAGE", self.LEVERAGE_IMAGE)
self.image_tag = self.env_conf.get("TERRAFORM_IMAGE_TAG")
self.image = self.env_conf.get("TF_IMAGE", self.env_conf.get("TERRAFORM_IMAGE", self.LEVERAGE_IMAGE))
self.image_tag = self.env_conf.get("TF_IMAGE_TAG", self.env_conf.get("TERRAFORM_IMAGE_TAG"))
if not self.image_tag:
logger.error(
"No docker image tag defined.\n"
"Please set `TERRAFORM_IMAGE_TAG` variable in the project's [bold]build.env[/bold] file before running a Leverage command."
"Please set `TF_IMAGE_TAG` variable in the project's [bold]build.env[/bold] file before running a Leverage command."
)
raise Exit(1)

Expand Down Expand Up @@ -433,15 +433,16 @@ def system_exec(self, command):
return exit_code, output


class TerraformContainer(SSOContainer):
"""Leverage container specifically tailored to run Terraform commands.
class TFContainer(SSOContainer):
"""Leverage container specifically tailored to run Terraform/OpenTofu commands.
It handles authentication and some checks regarding where the command is being executed."""

TF_BINARY = "/bin/terraform"
TERRAFORM_BINARY = "/bin/terraform"
TOFU_BINARY = "/bin/tofu"

TF_MFA_ENTRYPOINT = "/home/leverage/scripts/aws-mfa/aws-mfa-entrypoint.sh"

def __init__(self, client, mounts=None, env_vars=None):
def __init__(self, client, terraform=False, mounts=None, env_vars=None):
super().__init__(client, mounts=mounts, env_vars=env_vars)

self.paths.assert_running_leverage_project()
Expand Down Expand Up @@ -474,7 +475,7 @@ def __init__(self, client, mounts=None, env_vars=None):
"SSH_AUTH_SOCK": "" if SSH_AUTH_SOCK is None else "/ssh-agent",
}
)
self.entrypoint = self.TF_BINARY
self.entrypoint = self.TERRAFORM_BINARY if terraform else self.TOFU_BINARY
extra_mounts = [
Mount(source=self.paths.root_dir.as_posix(), target=self.paths.guest_base_path, type="bind"),
Mount(
Expand Down Expand Up @@ -685,7 +686,7 @@ def backend_key(self, backend_key):
self._backend_key = backend_key


class TFautomvContainer(TerraformContainer):
class TFautomvContainer(TFContainer):
"""Leverage Container tailored to run general commands."""

TFAUTOMV_CLI_BINARY = "/usr/local/bin/tfautomv"
Expand Down
9 changes: 5 additions & 4 deletions leverage/containers/kubectl.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from leverage import logger
from leverage._utils import AwsCredsEntryPoint, ExitError, CustomEntryPoint
from leverage.container import TerraformContainer
from leverage.container import TFContainer


@dataclass
Expand All @@ -24,11 +24,11 @@ class MetadataTypes(Enum):
K8S_CLUSTER = "k8s-eks-cluster"


class KubeCtlContainer(TerraformContainer):
class KubeCtlContainer(TFContainer):
"""Container specifically tailored to run kubectl commands."""

KUBECTL_CLI_BINARY = "/usr/local/bin/kubectl"
KUBECTL_CONFIG_PATH = Path(f"/home/{TerraformContainer.CONTAINER_USER}/.kube")
KUBECTL_CONFIG_PATH = Path(f"/home/{TFContainer.CONTAINER_USER}/.kube")
KUBECTL_CONFIG_FILE = KUBECTL_CONFIG_PATH / Path("config")
METADATA_FILENAME = "metadata.yaml"

Expand Down Expand Up @@ -78,7 +78,8 @@ def configure(self, ci: ClusterInfo = None):
logger.info("Done.")

def _get_eks_kube_config(self) -> str:
exit_code, output = self._start_with_output(f"{self.TF_BINARY} output -no-color") # TODO: override on CM?
tf_binary = self.TOFU_BINARY if "tofu" in self.image_tag else self.TERRAFORM_BINARY
exit_code, output = self._start_with_output(f"{tf_binary} output -no-color") # TODO: override on CM?
if exit_code:
raise ExitError(exit_code, output)

Expand Down
16 changes: 12 additions & 4 deletions leverage/leverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from leverage._internals import pass_state
from leverage.modules.aws import aws
from leverage.modules.credentials import credentials
from leverage.modules import run, project, terraform, tfautomv, kubectl, shell
from leverage.modules import run, project, tofu, terraform, tfautomv, kubectl, shell
from leverage.path import NotARepositoryError


Expand All @@ -36,11 +36,18 @@ def leverage(context, state, verbose):
return

# check if the current versions are lower than the minimum required
if not (current_values := config.get("TERRAFORM_IMAGE_TAG")):
if not (image_tag := config.get("TF_IMAGE_TAG", config.get("TERRAFORM_IMAGE_TAG"))):
# at some points of the project (the init), the config file is not created yet
return

# validate both TOOLBOX and TF versions
for key, current in zip(MINIMUM_VERSIONS, current_values.split("-")):
image_versions = image_tag.split("-")
if "tofu" not in image_versions:
versions = zip(MINIMUM_VERSIONS, image_versions)
else:
versions = {"TOOLBOX": image_versions[-1]}.items()

for key, current in versions:
if Version(current) < Version(MINIMUM_VERSIONS[key]):
rich.print(
f"[red]WARNING[/red]\tYour current {key} version ({current}) is lower than the required minimum ({MINIMUM_VERSIONS[key]})."
Expand All @@ -50,8 +57,9 @@ def leverage(context, state, verbose):
# Add modules to leverage
leverage.add_command(run)
leverage.add_command(project)
leverage.add_command(tofu)
leverage.add_command(tofu, name="tf")
leverage.add_command(terraform)
leverage.add_command(terraform, name="tf")
leverage.add_command(credentials)
leverage.add_command(aws)
leverage.add_command(tfautomv)
Expand Down
2 changes: 1 addition & 1 deletion leverage/modules/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .run import run
from .project import project
from .terraform import terraform
from .tf import tofu, terraform
from .tfautomv import tfautomv
from .kubectl import kubectl
from .shell import shell
6 changes: 3 additions & 3 deletions leverage/modules/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ def credentials(state):
if common.tfvars
raise an exception

If we reached the only common.tfvars scenario, we have no project name nor TERRAFORM_IMAGE_TAG.
If we reached the only common.tfvars scenario, we have no project name nor TF_IMAGE_TAG.
So the best chance is to read the common.tfvars directly without a conatiner, e.g. with sed or grep
"""
project_config = _load_project_yaml()
Expand All @@ -266,7 +266,7 @@ def credentials(state):
logger.error("Invalid or missing project short name in project.yaml file.")
raise Exit(1)
if not build_env.exists():
build_env.write_text(f"PROJECT={short_name}\nTERRAFORM_IMAGE_TAG={__toolbox_version__}")
build_env.write_text(f"PROJECT={short_name}\nTF_IMAGE_TAG={__toolbox_version__}")
elif not build_env.exists():
# project_config is not empty
# and build.env does not exist
Expand All @@ -280,7 +280,7 @@ def credentials(state):
if g:
found = True
logger.info("Reading info from common.tfvars")
build_env.write_text(f"PROJECT={g[1]}\nTERRAFORM_IMAGE_TAG=1.1.9")
build_env.write_text(f"PROJECT={g[1]}\nTF_IMAGE_TAG=1.1.9")
break
if not found:
raise Exception("Config file not found")
Expand Down
4 changes: 2 additions & 2 deletions leverage/modules/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from leverage.path import NotARepositoryError
from leverage._utils import git, ExitError
from leverage.container import get_docker_client
from leverage.container import TerraformContainer
from leverage.container import TFContainer

# Leverage related base definitions
LEVERAGE_DIR = Path.home() / ".leverage"
Expand Down Expand Up @@ -326,7 +326,7 @@ def create():
# Format the code correctly
logger.info("Reformatting terraform configuration to the standard style.")

terraform = TerraformContainer(get_docker_client())
terraform = TFContainer(get_docker_client())
terraform.ensure_image()
terraform.disable_authentication()
with console.status("Formatting..."):
Expand Down
6 changes: 3 additions & 3 deletions leverage/modules/shell.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import click

from leverage._utils import CustomEntryPoint
from leverage.container import get_docker_client, TerraformContainer
from leverage.container import get_docker_client, TFContainer
from leverage.modules.utils import env_var_option, mount_option, auth_sso, auth_mfa


Expand All @@ -28,9 +28,9 @@ def shell(mount, env_var, mfa, sso):
"""
if env_var:
env_var = dict(env_var)
# TODO: TerraformContainer is the only class supporting sso/mfa auth automagically
# TODO: TFContainer is the only class supporting sso/mfa auth automagically
# Move this capacity into a mixin later
container = TerraformContainer(get_docker_client(), mounts=mount, env_vars=env_var)
container = TFContainer(get_docker_client(), mounts=mount, env_vars=env_var)
container.ensure_image()

# auth
Expand Down
Loading
Loading