From 1131e7a703ab783bc5f14972c39a301c502dff8d Mon Sep 17 00:00:00 2001 From: paladin-devops <83741749+paladin-devops@users.noreply.github.com> Date: Tue, 19 Mar 2024 10:49:19 -0400 Subject: [PATCH] [WAYP-2345] waypoint: Add create command for add-on definitions. --- internal/commands/waypoint/add-on/add_on.go | 17 ++ .../waypoint/add-on/add_on_definition.go | 42 +++++ .../add-on/add_on_definition_create.go | 152 ++++++++++++++++++ internal/commands/waypoint/waypoint.go | 2 + 4 files changed, 213 insertions(+) create mode 100644 internal/commands/waypoint/add-on/add_on.go create mode 100644 internal/commands/waypoint/add-on/add_on_definition.go create mode 100644 internal/commands/waypoint/add-on/add_on_definition_create.go diff --git a/internal/commands/waypoint/add-on/add_on.go b/internal/commands/waypoint/add-on/add_on.go new file mode 100644 index 00000000..71a4d842 --- /dev/null +++ b/internal/commands/waypoint/add-on/add_on.go @@ -0,0 +1,17 @@ +package addon + +import "github.com/hashicorp/hcp/internal/pkg/cmd" + +func NewCmdAddOn(ctx *cmd.Context) *cmd.Command { + cmd := &cmd.Command{ + Name: "add-ons", + ShortHelp: "Manage HCP Waypoint add-ons and add-on definitions.", + LongHelp: "Manage HCP Waypoint add-ons. Add-ons are units of infrastructure" + + " that can be deployed alongside applications. They can be used to deploy" + + " databases, caches, and other infrastructure alongside applications.", + } + + cmd.AddChild(NewCmdAddOnDefinition(ctx)) + + return cmd +} diff --git a/internal/commands/waypoint/add-on/add_on_definition.go b/internal/commands/waypoint/add-on/add_on_definition.go new file mode 100644 index 00000000..2f0b8daf --- /dev/null +++ b/internal/commands/waypoint/add-on/add_on_definition.go @@ -0,0 +1,42 @@ +package addon + +import ( + "github.com/hashicorp/hcp/internal/commands/waypoint/opts" + "github.com/hashicorp/hcp/internal/pkg/cmd" +) + +type AddOnDefinitionOpts struct { + opts.WaypointOpts + + Name string + Summary string + Description string + ReadmeMarkdownTemplateFile string + Labels []string + + TerraformNoCodeModuleSource string + TerraformNoCodeModuleVersion string + TerraformCloudProjectName string + TerraformCloudProjectID string + + // testFunc is used for testing, so that the command can be tested without + // using the real API. + testFunc func(c *cmd.Command, args []string) error +} + +func NewCmdAddOnDefinition(ctx *cmd.Context) *cmd.Command { + opts := &AddOnDefinitionOpts{ + WaypointOpts: opts.New(ctx), + } + + cmd := &cmd.Command{ + Name: "definitions", + ShortHelp: "Manage HCP Waypoint add-on definitions.", + LongHelp: "Manage HCP Waypoint add-on definitions. Add-on definitions " + + "are reusable configurations for creating add-ons.", + } + + cmd.AddChild(NewCmdAddOnDefinitionCreate(ctx, opts)) + + return cmd +} diff --git a/internal/commands/waypoint/add-on/add_on_definition_create.go b/internal/commands/waypoint/add-on/add_on_definition_create.go new file mode 100644 index 00000000..50906d6b --- /dev/null +++ b/internal/commands/waypoint/add-on/add_on_definition_create.go @@ -0,0 +1,152 @@ +package addon + +import ( + "fmt" + "os" + + "github.com/hashicorp/hcp-sdk-go/clients/cloud-waypoint-service/preview/2023-08-18/client/waypoint_service" + "github.com/hashicorp/hcp-sdk-go/clients/cloud-waypoint-service/preview/2023-08-18/models" + "github.com/hashicorp/hcp/internal/pkg/cmd" + "github.com/hashicorp/hcp/internal/pkg/flagvalue" + "github.com/hashicorp/hcp/internal/pkg/heredoc" + "github.com/pkg/errors" +) + +func NewCmdAddOnDefinitionCreate(ctx *cmd.Context, opts *AddOnDefinitionOpts) *cmd.Command { + cmd := &cmd.Command{ + Name: "create", + ShortHelp: "Create a new add-on definition.", + LongHelp: "Create a new add-on definition.", + Examples: []cmd.Example{ + // TODO: Add example + }, + RunF: func(c *cmd.Command, args []string) error { + if opts.testFunc != nil { + return opts.testFunc(c, args) + } + return addOnDefinitionCreate(opts) + }, + PersistentPreRun: func(c *cmd.Command, args []string) error { + return cmd.RequireOrgAndProject(ctx) + }, + Flags: cmd.Flags{ + Local: []*cmd.Flag{ + { + Name: "name", + Shorthand: "n", + DisplayValue: "NAME", + Description: "The name of the add-on definition.", + Value: flagvalue.Simple("", &opts.Name), + }, + { + Name: "summary", + Shorthand: "s", + DisplayValue: "SUMMARY", + Description: "The summary of the add-on definition.", + Value: flagvalue.Simple("", &opts.Summary), + }, + { + Name: "description", + Shorthand: "d", + DisplayValue: "DESCRIPTION", + Description: "The description of the add-on definition.", + Value: flagvalue.Simple("", &opts.Description), + }, + { + Name: "readme-markdown-template-file", + DisplayValue: "README_MARKDOWN_TEMPLATE_FILE_PATH", + Description: "The file containing the README markdown template.", + Value: flagvalue.Simple("", &opts.ReadmeMarkdownTemplateFile), + }, + { + Name: "label", + Shorthand: "l", + DisplayValue: "LABEL", + Description: "A label to apply to the template.", + Repeatable: true, + Value: flagvalue.SimpleSlice(nil, &opts.Labels), + }, + { + Name: "tfc-no-code-module-source", + DisplayValue: "TFC_NO_CODE_MODULE_SOURCE", + Description: heredoc.New(ctx.IO).Must(` + The source of the Terraform no-code module. + The expected format is "NAMESPACE/NAME/PROVIDER". An + optional "HOSTNAME/" can be added at the beginning for + a private registry. + `), + Value: flagvalue.Simple("", &opts.TerraformNoCodeModuleSource), + Required: true, + }, + { + Name: "tfc-no-code-module-version", + DisplayValue: "TFC_NO_CODE_MODULE_VERSION", + Description: "The version of the Terraform no-code module.", + Value: flagvalue.Simple("", &opts.TerraformNoCodeModuleVersion), + Required: true, + }, + { + Name: "tfc-project-name", + DisplayValue: "TFC_PROJECT_NAME", + Description: "The name of the Terraform Cloud project where" + + " applications using this add-on definition will be created.", + Value: flagvalue.Simple("", &opts.TerraformCloudProjectName), + Required: true, + }, + { + Name: "tfc-project-id", + DisplayValue: "TFC_PROJECT_ID", + Description: "The ID of the Terraform Cloud project where" + + " applications using this add-on definition will be created.", + Value: flagvalue.Simple("", &opts.TerraformCloudProjectID), + Required: true, + }, + }, + }, + } + + return cmd +} + +func addOnDefinitionCreate(opts *AddOnDefinitionOpts) error { + ns, err := opts.Namespace() + if err != nil { + return errors.Wrapf(err, "Unable to access HCP project") + } + + var readmeTpl []byte + if opts.ReadmeMarkdownTemplateFile != "" { + readmeTpl, err = os.ReadFile(opts.ReadmeMarkdownTemplateFile) + if err != nil { + return fmt.Errorf("failed to read README markdown template file: %w", err) + } + } + + _, err = opts.WS.WaypointServiceCreateAddOnDefinition( + &waypoint_service.WaypointServiceCreateAddOnDefinitionParams{ + NamespaceID: ns.ID, + Body: &models.HashicorpCloudWaypointWaypointServiceCreateAddOnDefinitionBody{ + Name: opts.Name, + Summary: opts.Summary, + Description: opts.Description, + ReadmeMarkdownTemplate: readmeTpl, + Labels: opts.Labels, + TerraformNocodeModule: &models.HashicorpCloudWaypointTerraformNocodeModule{ + Source: opts.TerraformNoCodeModuleSource, + Version: opts.TerraformNoCodeModuleVersion, + }, + TerraformCloudWorkspaceDetails: &models.HashicorpCloudWaypointTerraformCloudWorkspaceDetails{ + Name: opts.TerraformCloudProjectName, + ProjectID: opts.TerraformCloudProjectID, + }, + }, + Context: opts.Ctx, + }, nil) + if err != nil { + return fmt.Errorf("failed to create add-on definition %q: %w", opts.Name, err) + } + + fmt.Fprintf(opts.IO.Err(), "Add-on definition %q created.", opts.Name) + + return nil +} diff --git a/internal/commands/waypoint/waypoint.go b/internal/commands/waypoint/waypoint.go index 1ae9eb67..3c191c85 100644 --- a/internal/commands/waypoint/waypoint.go +++ b/internal/commands/waypoint/waypoint.go @@ -2,6 +2,7 @@ package waypoint import ( "github.com/hashicorp/hcp/internal/commands/waypoint/actionconfig" + addon "github.com/hashicorp/hcp/internal/commands/waypoint/add-on" "github.com/hashicorp/hcp/internal/commands/waypoint/agent" "github.com/hashicorp/hcp/internal/commands/waypoint/template" "github.com/hashicorp/hcp/internal/commands/waypoint/tfcconfig" @@ -24,6 +25,7 @@ func NewCmdWaypoint(ctx *cmd.Context) *cmd.Command { cmd.AddChild(actionconfig.NewCmdActionConfig(ctx)) cmd.AddChild(agent.NewCmdAgent(ctx)) cmd.AddChild(template.NewCmdTemplate(ctx)) + cmd.AddChild(addon.NewCmdAddOn(ctx)) return cmd }