Skip to content

Commit

Permalink
feat: Add support for OpenTofu
Browse files Browse the repository at this point in the history
Add new configurations to specify product.
Use product to determine product passed to tfswitch and for executable used when calling terraform

Issue #520
  • Loading branch information
MatthewJohn committed Jun 7, 2024
1 parent 92d95db commit 03f20e9
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 8 deletions.
17 changes: 15 additions & 2 deletions docs/CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,17 @@ A common configuration may require a 'groups' scope to be added to the list of s
Default: `['openid', 'profile']`


### PRODUCT


Product to use when performing module extraction

Options: terraform, opentofu


Default: `terraform`


### PROVIDER_CATEGORIES


Expand Down Expand Up @@ -1057,10 +1068,12 @@ Default: ``
### TERRAFORM_ARCHIVE_MIRROR


Mirror for obtaining version list and downloading Terraform
Mirror for obtaining version list and downloading Terraform.

Defaults to default mirror used by tfswitch

Default: `https://releases.hashicorp.com/terraform`

Default: ``


### TERRAFORM_EXAMPLE_VERSION_TEMPLATE
Expand Down
21 changes: 19 additions & 2 deletions terrareg/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ class ModuleHostingMode(Enum):
ENFORCE = "enforce"


class Product(Enum):
"""Type of product"""
TERRAFORM = "terraform"
OPENTOFU = "opentofu"


class Config:

@property
Expand Down Expand Up @@ -861,12 +867,23 @@ def DEFAULT_TERRAFORM_VERSION(self):
"""
return os.environ.get("DEFAULT_TERRAFORM_VERSION", "1.3.6")

@property
def PRODUCT(self):
"""
Product to use when performing module extraction
Options: terraform, opentofu
"""
return Product(os.environ.get('PRODUCT', Product.TERRAFORM.value).lower())

@property
def TERRAFORM_ARCHIVE_MIRROR(self):
"""
Mirror for obtaining version list and downloading Terraform
Mirror for obtaining version list and downloading Terraform.
Defaults to default mirror used by tfswitch
"""
return os.environ.get("TERRAFORM_ARCHIVE_MIRROR", "https://releases.hashicorp.com/terraform")
return os.environ.get("TERRAFORM_ARCHIVE_MIRROR", "")

@property
def MANAGE_TERRAFORM_RC_FILE(self):
Expand Down
19 changes: 15 additions & 4 deletions terrareg/module_extractor.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
UnableToGetGlobalTerraformLockError,
TerraformVersionSwitchError
)
import terrareg.terraform_product
from terrareg.utils import PathDoesNotExistError, get_public_url_details, safe_iglob, safe_join_paths
from terrareg.config import Config
from terrareg.constants import EXTRACTION_VERSION
Expand All @@ -50,9 +51,10 @@ def __init__(self, module_version: 'terrareg.models.ModuleVersion'):
self._upload_directory = tempfile.TemporaryDirectory() # noqa: R1732

@staticmethod
def terraform_binary():
def terraform_binary() -> str:
"""Return path of terraform binary"""
return os.path.join(os.getcwd(), "bin", "terraform")
product = terrareg.terraform_product.ProductFactory.get_product()
return os.path.join(os.getcwd(), "bin", product.get_executable_name())

@property
def terraform_rc_file(self):
Expand Down Expand Up @@ -118,16 +120,25 @@ def _switch_terraform_versions(cls, module_path):
"Unable to obtain global Terraform lock in 60 seconds"
)
try:
default_terraform_version = Config().DEFAULT_TERRAFORM_VERSION
config = Config()

default_terraform_version = config.DEFAULT_TERRAFORM_VERSION
tfswitch_env = os.environ.copy()

if default_terraform_version:
tfswitch_env["TF_VERSION"] = default_terraform_version

product = terrareg.terraform_product.ProductFactory.get_product()
tfswitch_env["TF_PRODUCT"] = product.get_tfswitch_product_arg()

tfswitch_args = []
if config.TERRAFORM_ARCHIVE_MIRROR:
tfswitch_args += ["--mirror", config.TERRAFORM_ARCHIVE_MIRROR]

# Run tfswitch
try:
subprocess.check_output(
["tfswitch", "--mirror", Config().TERRAFORM_ARCHIVE_MIRROR, "--bin", cls.terraform_binary()],
["tfswitch", "--bin", cls.terraform_binary(), *tfswitch_args],
env=tfswitch_env,
cwd=module_path
)
Expand Down
52 changes: 52 additions & 0 deletions terrareg/terraform_product.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import abc

import terrareg.config


class BaseProduct(abc.ABC):

@abc.abstractmethod
def get_tfswitch_product_arg(self) -> str:
"""Return name of tfswitch product argument value"""
...

@abc.abstractmethod
def get_executable_name(self) -> str:
"""Return executable name for product"""
...

class Terraform(BaseProduct):
"""Terraform product"""

def get_tfswitch_product_arg(self) -> str:
"""Return name of tfswitch product argument value"""
return "terraform"

def get_executable_name(self) -> str:
"""Return executable name for product"""
return "terraform"


class OpenTofu(BaseProduct):
"""OpenTofu product"""

def get_tfswitch_product_arg(self) -> str:
"""Return name of tfswitch product argument value"""
return "opentofu"

def get_executable_name(self) -> str:
"""Return executable name for product"""
return "tofu"


class ProductFactory:

@staticmethod
def get_product():
"""Obtain current product"""
product_enum = terrareg.config.Config().PRODUCT
if product_enum is terrareg.config.Product.TERRAFORM:
return Terraform()
elif product_enum is terrareg.config.Product.OPENTOFU:
return OpenTofu()
raise Exception("Could not determine product class")

0 comments on commit 03f20e9

Please sign in to comment.