Skip to content

Commit

Permalink
feat: introduce json format for inline module (#165) (#283)
Browse files Browse the repository at this point in the history
Signed-off-by: Dennis Kniep <kniepdennis@gmail.com>
  • Loading branch information
denniskniep authored Aug 26, 2024
1 parent 8850b8a commit 9db20a3
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 15 deletions.
16 changes: 10 additions & 6 deletions apis/v1beta1/workspace_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ const (
VarFileSourceSecretKey VarFileSource = "SecretKey"
)

// A VarFileFormat specifies the format of a Terraform vars file.
// A FileFormat specifies the format of a Terraform file.
// +kubebuilder:validation:Enum=HCL;JSON
type VarFileFormat string
type FileFormat string

// Vars file formats.
var (
VarFileFormatHCL VarFileFormat = "HCL"
VarFileFormatJSON VarFileFormat = "JSON"
FileFormatHCL FileFormat = "HCL"
FileFormatJSON FileFormat = "JSON"
)

// A VarFile is a file containing many Terraform variables.
Expand All @@ -57,7 +57,7 @@ type VarFile struct {
// Format of this vars file.
// +kubebuilder:default=HCL
// +optional
Format *VarFileFormat `json:"format,omitempty"`
Format *FileFormat `json:"format,omitempty"`

// A ConfigMap key containing the vars file.
// +optional
Expand Down Expand Up @@ -108,9 +108,13 @@ type WorkspaceParameters struct {
// file. When the workspace's source is 'Remote' (the default) this can be
// any address supported by terraform init -from-module, for example a git
// repository or an S3 bucket. When the workspace's source is 'Inline' the
// content of a simple main.tf file may be written inline.
// content of a simple main.tf or main.tf.json file may be written inline.
Module string `json:"module"`

// Specifies the format of the inline Terraform content
// if Source is 'Inline'
InlineFormat FileFormat `json:"inlineFormat,omitempty"`

// Source of the root module of this workspace.
Source ModuleSource `json:"source"`

Expand Down
2 changes: 1 addition & 1 deletion apis/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 9 additions & 4 deletions internal/controller/workspace/workspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const (
errWriteCreds = "cannot write Terraform credentials"
errWriteGitCreds = "cannot write .git-credentials to /tmp dir"
errWriteConfig = "cannot write Terraform configuration " + tfConfig
errWriteMain = "cannot write Terraform configuration " + tfMain
errWriteMain = "cannot write Terraform configuration "
errWriteBackend = "cannot write Terraform configuration " + tfBackendFile
errInit = "cannot initialize Terraform configuration"
errWorkspace = "cannot select Terraform workspace"
Expand All @@ -87,6 +87,7 @@ const (
// TODO(negz): Make the Terraform binary path and work dir configurable.
tfPath = "terraform"
tfMain = "main.tf"
tfMainJSON = "main.tf.json"
tfConfig = "crossplane-provider-config.tf"
tfBackendFile = "crossplane.remote.tfbackend"
)
Expand Down Expand Up @@ -249,8 +250,12 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E
}

case v1beta1.ModuleSourceInline:
if err := c.fs.WriteFile(filepath.Join(dir, tfMain), []byte(cr.Spec.ForProvider.Module), 0600); err != nil {
return nil, errors.Wrap(err, errWriteMain)
fn := tfMain
if cr.Spec.ForProvider.InlineFormat == v1beta1.FileFormatJSON {
fn = tfMainJSON
}
if err := c.fs.WriteFile(filepath.Join(dir, fn), []byte(cr.Spec.ForProvider.Module), 0600); err != nil {
return nil, errors.Wrap(err, errWriteMain+fn)
}
}

Expand Down Expand Up @@ -481,7 +486,7 @@ func (c *external) options(ctx context.Context, p v1beta1.WorkspaceParameters) (

for _, vf := range p.VarFiles {
fmt := terraform.HCL
if vf.Format != nil && *vf.Format == v1beta1.VarFileFormatJSON {
if vf.Format != nil && *vf.Format == v1beta1.FileFormatJSON {
fmt = terraform.JSON
}

Expand Down
42 changes: 39 additions & 3 deletions internal/controller/workspace/workspace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,43 @@ func TestConnect(t *testing.T) {
},
},
},
want: errors.Wrap(errBoom, errWriteMain),
want: errors.Wrap(errBoom, errWriteMain+tfMain),
},
"WriteMainJsonError": {
reason: "We should return any error encountered while writing our main.tf file",
fields: fields{
kube: &test.MockClient{
MockGet: test.NewMockGetFn(nil),
},
usage: resource.TrackerFn(func(_ context.Context, _ resource.Managed) error { return nil }),
fs: afero.Afero{
Fs: &ErrFs{
Fs: afero.NewMemMapFs(),
errs: map[string]error{filepath.Join(tfDir, string(uid), tfMainJSON): errBoom},
},
},
terraform: func(_ string, _ bool, _ ...string) tfclient {

Check failure on line 537 in internal/controller/workspace/workspace_test.go

View workflow job for this annotation

GitHub Actions / ci / lint

cannot use func(_ string, _ bool, _ ...string) tfclient {…} (value of type func(_ string, _ bool, _ ...string) tfclient) as func(dir string, usePluginCache bool, enableTerraformCLILogging bool, logger logging.Logger, envs ...string) tfclient value in struct literal (typecheck)

Check failure on line 537 in internal/controller/workspace/workspace_test.go

View workflow job for this annotation

GitHub Actions / ci / unit-tests

cannot use func(_ string, _ bool, _ ...string) tfclient {…} (value of type func(_ string, _ bool, _ ...string) tfclient) as func(dir string, usePluginCache bool, enableTerraformCLILogging bool, logger logging.Logger, envs ...string) tfclient value in struct literal
return &MockTf{
MockInit: func(ctx context.Context, o ...terraform.InitOption) error { return nil },
}
},
},
args: args{
mg: &v1beta1.Workspace{
ObjectMeta: metav1.ObjectMeta{UID: uid},
Spec: v1beta1.WorkspaceSpec{
ResourceSpec: xpv1.ResourceSpec{
ProviderConfigReference: &xpv1.Reference{},
},
ForProvider: v1beta1.WorkspaceParameters{
Module: "I'm JSON!",
Source: v1beta1.ModuleSourceInline,
InlineFormat: v1beta1.FileFormatJSON,
},
},
},
},
want: errors.Wrap(errBoom, errWriteMain+tfMainJSON),
},
"TerraformInitError": {
reason: "We should return any error encountered while initializing Terraform",
Expand Down Expand Up @@ -1298,7 +1334,7 @@ func TestCreate(t *testing.T) {
{
Source: v1beta1.VarFileSourceSecretKey,
SecretKeyReference: &v1beta1.KeyReference{},
Format: &v1beta1.VarFileFormatJSON,
Format: &v1beta1.FileFormatJSON,
},
},
},
Expand Down Expand Up @@ -1483,7 +1519,7 @@ func TestDelete(t *testing.T) {
{
Source: v1beta1.VarFileSourceSecretKey,
SecretKeyReference: &v1beta1.KeyReference{},
Format: &v1beta1.VarFileFormatJSON,
Format: &v1beta1.FileFormatJSON,
},
},
},
Expand Down
10 changes: 9 additions & 1 deletion package/crds/tf.upbound.io_workspaces.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,21 @@ spec:
items:
type: string
type: array
inlineFormat:
description: |-
Specifies the format of the inline Terraform content
if Source is 'Inline'
enum:
- HCL
- JSON
type: string
module:
description: |-
The root module of this workspace; i.e. the module containing its main.tf
file. When the workspace's source is 'Remote' (the default) this can be
any address supported by terraform init -from-module, for example a git
repository or an S3 bucket. When the workspace's source is 'Inline' the
content of a simple main.tf file may be written inline.
content of a simple main.tf or main.tf.json file may be written inline.
type: string
planArgs:
description: Arguments to be included in the terraform plan CLI
Expand Down

0 comments on commit 9db20a3

Please sign in to comment.