-
Notifications
You must be signed in to change notification settings - Fork 55
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
DXCDT-498: Add terraform generate command skeleton #792
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
--- | ||
layout: default | ||
has_toc: false | ||
has_children: true | ||
--- | ||
# auth0 terraform | ||
|
||
This command facilitates the integration of Auth0 with [Terraform](https://www.terraform.io/), an Infrastructure as Code tool. | ||
|
||
## Commands | ||
|
||
- [auth0 terraform generate](auth0_terraform_generate.md) - Generate terraform configuration for your Auth0 Tenant | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
--- | ||
layout: default | ||
parent: auth0 terraform | ||
has_toc: false | ||
--- | ||
# auth0 terraform generate | ||
|
||
This command is designed to streamline the process of generating Terraform configuration files for your Auth0 resources, serving as a bridge between the two. | ||
|
||
It automatically scans your Auth0 Tenant and compiles a set of Terraform configuration files based on the existing resources and configurations. | ||
|
||
The generated Terraform files are written in HashiCorp Configuration Language (HCL). | ||
|
||
## Usage | ||
``` | ||
auth0 terraform generate [flags] | ||
``` | ||
|
||
## Examples | ||
|
||
``` | ||
|
||
``` | ||
|
||
|
||
## Flags | ||
|
||
``` | ||
-o, --output-dir string Output directory for the generated Terraform config files. If not provided, the files will be saved in the current working directory. (default "./") | ||
``` | ||
|
||
|
||
## Inherited Flags | ||
|
||
``` | ||
--debug Enable debug mode. | ||
--no-color Disable colors. | ||
--no-input Disable interactivity. | ||
--tenant string Specific tenant to use. | ||
``` | ||
|
||
|
||
## Related Commands | ||
|
||
- [auth0 terraform generate](auth0_terraform_generate.md) - Generate terraform configuration for your Auth0 Tenant | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package cli | ||
|
||
import ( | ||
"os" | ||
"path" | ||
|
||
"github.com/spf13/cobra" | ||
) | ||
|
||
var tfFlags = terraformFlags{ | ||
OutputDIR: Flag{ | ||
Name: "Output Dir", | ||
LongForm: "output-dir", | ||
ShortForm: "o", | ||
Help: "Output directory for the generated Terraform config files. If not provided, the files will be " + | ||
"saved in the current working directory.", | ||
}, | ||
} | ||
|
||
type ( | ||
terraformFlags struct { | ||
OutputDIR Flag | ||
} | ||
|
||
terraformInputs struct { | ||
OutputDIR string | ||
} | ||
) | ||
|
||
func terraformCmd(cli *cli) *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "terraform", | ||
Aliases: []string{"tf"}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the |
||
Short: "Manage terraform configuration for your Auth0 Tenant", | ||
Long: "This command facilitates the integration of Auth0 with [Terraform](https://www.terraform.io/), an " + | ||
"Infrastructure as Code tool.", | ||
} | ||
|
||
cmd.SetUsageTemplate(resourceUsageTemplate()) | ||
cmd.AddCommand(generateTerraformCmd(cli)) | ||
|
||
return cmd | ||
} | ||
|
||
func generateTerraformCmd(cli *cli) *cobra.Command { | ||
var inputs terraformInputs | ||
|
||
cmd := &cobra.Command{ | ||
Use: "generate", | ||
Aliases: []string{"gen", "export"}, // Reconsider aliases and command name before releasing. | ||
Short: "Generate terraform configuration for your Auth0 Tenant", | ||
Long: "This command is designed to streamline the process of generating Terraform configuration files for " + | ||
"your Auth0 resources, serving as a bridge between the two.\n\nIt automatically scans your Auth0 Tenant " + | ||
"and compiles a set of Terraform configuration files based on the existing resources and configurations." + | ||
"\n\nThe generated Terraform files are written in HashiCorp Configuration Language (HCL).", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reminder for us to include instructions and/or link to a guide once one is available. |
||
RunE: generateTerraformCmdRun(cli, &inputs), | ||
} | ||
|
||
tfFlags.OutputDIR.RegisterString(cmd, &inputs.OutputDIR, "./") | ||
|
||
return cmd | ||
} | ||
|
||
func generateTerraformCmdRun(cli *cli, inputs *terraformInputs) func(cmd *cobra.Command, args []string) error { | ||
return func(cmd *cobra.Command, args []string) error { | ||
if err := generateTerraformConfigFiles(inputs); err != nil { | ||
return err | ||
} | ||
|
||
cli.renderer.Infof("Terraform config files generated successfully.") | ||
cli.renderer.Infof( | ||
"Follow this " + | ||
"[quickstart](https://registry.terraform.io/providers/auth0/auth0/latest/docs/guides/quickstart) " + | ||
"to go through setting up an Auth0 application for the provider to authenticate against and manage " + | ||
"resources.", | ||
) | ||
|
||
return nil | ||
} | ||
} | ||
|
||
func generateTerraformConfigFiles(inputs *terraformInputs) error { | ||
const readWritePermission = 0755 | ||
if err := os.MkdirAll(inputs.OutputDIR, readWritePermission); err != nil { | ||
if !os.IsExist(err) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does there need to be some nuance here? There's no certainty that an existing Some ideas on how to manage:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good callout, however considering we will have the same issue with the import.tf file and the generated files, let's focus on this as a separate PR after those are added as well. Currently, if the file exists it gets truncated and overwritten. |
||
return err | ||
} | ||
} | ||
|
||
mainTerraformConfigFile, err := os.Create(path.Join(inputs.OutputDIR, "main.tf")) | ||
if err != nil { | ||
return err | ||
} | ||
defer mainTerraformConfigFile.Close() | ||
|
||
mainTerraformConfigFileContent := `terraform { | ||
required_version = "~> 1.5.0" | ||
required_providers { | ||
auth0 = { | ||
source = "auth0/auth0" | ||
version = "1.0.0-beta.1" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a way to set this value programmatically? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't think of any. Any suggestions? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Once v1 GA goes live, we can consider omitting the version, so it always fetches the latest stable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Once we eventually release v2 (e.g. in a couple of years), would this mean it will automatically fetch the new major (along with its breaking changes)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could also use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All good things to consider, but at the moment we don't have any stable v1 so we can use |
||
} | ||
} | ||
} | ||
|
||
provider "auth0" { | ||
debug = true | ||
} | ||
` | ||
|
||
_, err = mainTerraformConfigFile.WriteString(mainTerraformConfigFileContent) | ||
return err | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package cli | ||
|
||
import ( | ||
"os" | ||
"path" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestGenerateTerraformConfigFiles(t *testing.T) { | ||
testInputs := terraformInputs{ | ||
OutputDIR: "./terraform/dev", | ||
} | ||
defer os.RemoveAll("./terraform") | ||
|
||
t.Run("it can correctly generate the terraform main config file", func(t *testing.T) { | ||
assertTerraformConfigFilesWereGeneratedWithCorrectContent(t, &testInputs) | ||
}) | ||
|
||
t.Run("it can correctly generate the terraform main config file even if the dir exists", func(t *testing.T) { | ||
err := os.MkdirAll(testInputs.OutputDIR, 0755) | ||
require.NoError(t, err) | ||
|
||
assertTerraformConfigFilesWereGeneratedWithCorrectContent(t, &testInputs) | ||
}) | ||
|
||
t.Run("it fails to create the directory if path is empty", func(t *testing.T) { | ||
testInputs := terraformInputs{ | ||
OutputDIR: "", | ||
} | ||
|
||
err := generateTerraformConfigFiles(&testInputs) | ||
assert.EqualError(t, err, "mkdir : no such file or directory") | ||
}) | ||
|
||
t.Run("it fails to create the main.tf file if file is already created and read only", func(t *testing.T) { | ||
err := os.MkdirAll(testInputs.OutputDIR, 0755) | ||
require.NoError(t, err) | ||
|
||
mainFilePath := path.Join(testInputs.OutputDIR, "main.tf") | ||
_, err = os.Create(mainFilePath) | ||
require.NoError(t, err) | ||
|
||
err = os.Chmod(mainFilePath, 0444) | ||
require.NoError(t, err) | ||
|
||
err = generateTerraformConfigFiles(&testInputs) | ||
assert.EqualError(t, err, "open terraform/dev/main.tf: permission denied") | ||
}) | ||
} | ||
|
||
func assertTerraformConfigFilesWereGeneratedWithCorrectContent(t *testing.T, testInputs *terraformInputs) { | ||
err := generateTerraformConfigFiles(testInputs) | ||
require.NoError(t, err) | ||
|
||
// Assert that the directory was created. | ||
_, err = os.Stat(testInputs.OutputDIR) | ||
assert.NoError(t, err) | ||
|
||
// Assert that the main.tf file was created with the correct content. | ||
mainTerraformConfigFilePath := path.Join(testInputs.OutputDIR, "main.tf") | ||
_, err = os.Stat(mainTerraformConfigFilePath) | ||
assert.NoError(t, err) | ||
|
||
expectedContent := `terraform { | ||
required_version = "~> 1.5.0" | ||
required_providers { | ||
auth0 = { | ||
source = "auth0/auth0" | ||
version = "1.0.0-beta.1" | ||
} | ||
} | ||
} | ||
|
||
provider "auth0" { | ||
debug = true | ||
} | ||
` | ||
// Read the file content and check if it matches the expected content | ||
content, err := os.ReadFile(mainTerraformConfigFilePath) | ||
assert.NoError(t, err) | ||
assert.Equal(t, expectedContent, string(content)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considered naming this just
--dir
, however the extra verbosity adds clarity in the full form for this flag and considering there's also the short form option of-o
, I deemed unnecessary to have the flag shorter.