Skip to content

Commit

Permalink
feat(terraform): fetch parents and children
Browse files Browse the repository at this point in the history
  • Loading branch information
quantumsheep committed Jun 14, 2023
1 parent 1e98790 commit 2cb0d09
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 45 deletions.
8 changes: 4 additions & 4 deletions internal/core/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func Bootstrap(config *BootstrapConfig) (exitCode int, result interface{}, err e
isClientFromBootstrapConfig = false
client, err = createAnonymousClient(httpClient, config.BuildInfo)
if err != nil {
printErr := printer.Print(err, nil)
printErr := printer.Print(client, err, nil)
if printErr != nil {
_, _ = fmt.Fprintln(config.Stderr, printErr)
}
Expand Down Expand Up @@ -201,7 +201,7 @@ func Bootstrap(config *BootstrapConfig) (exitCode int, result interface{}, err e
// Load CLI config
cliCfg, err := cliConfig.LoadConfig(ExtractCliConfigPath(ctx))
if err != nil {
printErr := printer.Print(err, nil)
printErr := printer.Print(meta.Client, err, nil)
if printErr != nil {
_, _ = fmt.Fprintln(config.Stderr, printErr)
}
Expand Down Expand Up @@ -270,15 +270,15 @@ func Bootstrap(config *BootstrapConfig) (exitCode int, result interface{}, err e
if cliErr, ok := err.(*CliError); ok && cliErr.Code != 0 {
errorCode = cliErr.Code
}
printErr := printer.Print(err, nil)
printErr := printer.Print(meta.Client, err, nil)
if printErr != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
}
return errorCode, nil, err
}

if meta.command != nil {
printErr := printer.Print(meta.result, meta.command.getHumanMarshalerOpt())
printErr := printer.Print(meta.Client, meta.result, meta.command.getHumanMarshalerOpt())
if printErr != nil {
_, _ = fmt.Fprintln(config.Stderr, printErr)
}
Expand Down
39 changes: 28 additions & 11 deletions internal/core/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/scaleway/scaleway-cli/v2/internal/gofields"
"github.com/scaleway/scaleway-cli/v2/internal/human"
"github.com/scaleway/scaleway-cli/v2/internal/terraform"
"github.com/scaleway/scaleway-sdk-go/scw"
)

// Type defines an formatter format.
Expand Down Expand Up @@ -44,8 +45,12 @@ const (
// Option to enable pretty output on json printer.
PrinterOptJSONPretty = "pretty"

// Option to enable pretty output on json printer.
PrinterOptTerraformWithChildren = "with-children"
// Option to disable parents output on terraform printer.
PrinterOptTerraformSkipParents = "skip-parents"
// Option to disable children output on terraform printer.
PrinterOptTerraformSkipChildren = "skip-children"
// Option to disable parents and children output on terraform printer.
PrinterOptTerraformSkipParentsAndChildren = "skip-parents-and-children"
)

type PrinterConfig struct {
Expand Down Expand Up @@ -115,11 +120,16 @@ func setupJSONPrinter(printer *Printer, opts string) error {
func setupTerraformPrinter(printer *Printer, opts string) error {
printer.printerType = PrinterTypeTerraform
switch opts {
case PrinterOptTerraformWithChildren:
printer.terraformWithChildren = true
case PrinterOptTerraformSkipParents:
printer.terraformSkipParents = true
case PrinterOptTerraformSkipChildren:
printer.terraformSkipChildren = true
case PrinterOptTerraformSkipParentsAndChildren:
printer.terraformSkipParents = true
printer.terraformSkipChildren = true
case "":
default:
return fmt.Errorf("invalid option %s for terraform outout. Valid options are: %s", opts, PrinterOptTerraformWithChildren)
return fmt.Errorf("invalid option %s for terraform outout. Valid options are: %s and %s", opts, PrinterOptTerraformSkipParents, PrinterOptTerraformSkipChildren)
}

terraformVersion, err := terraform.GetLocalClientVersion()
Expand Down Expand Up @@ -173,8 +183,10 @@ type Printer struct {
// Enable pretty print on json output
jsonPretty bool

// Enable children fetching on terraform output
terraformWithChildren bool
// Disable children fetching on terraform output
terraformSkipParents bool
// Disable children fetching on terraform output
terraformSkipChildren bool

// go template to use on template output
template *template.Template
Expand All @@ -183,7 +195,7 @@ type Printer struct {
humanFields []string
}

func (p *Printer) Print(data interface{}, opt *human.MarshalOpt) error {
func (p *Printer) Print(client *scw.Client, data interface{}, opt *human.MarshalOpt) error {
// No matter the printer type if data is a RawResult we should print it as is.
if rawResult, isRawResult := data.(RawResult); isRawResult {
_, err := p.stdout.Write(rawResult)
Expand All @@ -201,7 +213,7 @@ func (p *Printer) Print(data interface{}, opt *human.MarshalOpt) error {
case PrinterTypeYAML:
err = p.printYAML(data)
case PrinterTypeTerraform:
err = p.printTerraform(data)
err = p.printTerraform(client, data)
case PrinterTypeTemplate:
err = p.printTemplate(data)
default:
Expand Down Expand Up @@ -322,13 +334,18 @@ func (p *Printer) printYAML(data interface{}) error {
return encoder.Encode(data)
}

func (p *Printer) printTerraform(data interface{}) error {
func (p *Printer) printTerraform(client *scw.Client, data interface{}) error {
writer := p.stdout
if _, isError := data.(error); isError {
return p.printHuman(data, nil)
}

hcl, err := terraform.GetHCL(data)
hcl, err := terraform.GetHCL(&terraform.GetHCLConfig{
Client: client,
Data: data,
SkipParents: p.terraformSkipParents,
SkipChildren: p.terraformSkipChildren,
})
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions internal/core/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ func shellExecutor(rootCmd *cobra.Command, printer *Printer, meta *meta) func(s
return
}

printErr := printer.Print(err, nil)
printErr := printer.Print(meta.Client, err, nil)
if printErr != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
}
Expand All @@ -283,7 +283,7 @@ func shellExecutor(rootCmd *cobra.Command, printer *Printer, meta *meta) func(s

autoCompleteCache.Update(meta.command.Namespace)

printErr := printer.Print(meta.result, meta.command.getHumanMarshalerOpt())
printErr := printer.Print(meta.Client, meta.result, meta.command.getHumanMarshalerOpt())
if printErr != nil {
_, _ = fmt.Fprintln(os.Stderr, printErr)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/core/shell_disabled.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

func RunShell(ctx context.Context, printer *Printer, meta *meta, rootCmd *cobra.Command, args []string) {
err := printer.Print(fmt.Errorf("shell is currently disabled on freebsd"), nil)
err := printer.Print(meta.Client, fmt.Errorf("shell is currently disabled on freebsd"), nil)
if err != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
}
Expand Down
4 changes: 2 additions & 2 deletions internal/core/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -717,11 +717,11 @@ func marshalGolden(t *testing.T, ctx *CheckFuncCtx) string {
require.NoError(t, err)

if ctx.Err != nil {
err = jsonPrinter.Print(ctx.Err, nil)
err = jsonPrinter.Print(nil, ctx.Err, nil)
require.NoError(t, err)
}
if ctx.Result != nil {
err = jsonPrinter.Print(ctx.Result, nil)
err = jsonPrinter.Print(nil, ctx.Result, nil)
require.NoError(t, err)
}

Expand Down
97 changes: 83 additions & 14 deletions internal/terraform/association.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,32 @@ package terraform
import (
"reflect"

"github.com/scaleway/scaleway-sdk-go/api/account/v2"
"github.com/scaleway/scaleway-sdk-go/api/baremetal/v1"
container "github.com/scaleway/scaleway-sdk-go/api/container/v1beta1"
"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
"github.com/scaleway/scaleway-sdk-go/scw"
)

type associationSubResource struct {
TerraformAttributeName string
Command string
AsDataSource bool
type associationParent struct {
Fetcher func(client *scw.Client, data interface{}) (interface{}, error)
AsDataSource bool
}

type associationChild struct {
// {
// [<child attribute>]: <parent attribute>
// }
ParentFieldMap map[string]string

Fetcher func(client *scw.Client, data interface{}) (interface{}, error)
}

type association struct {
ResourceName string
ImportFormat string
SubResources map[string]*associationSubResource
Parents map[string]*associationParent
Children []*associationChild
}

// const importFormatID = "{{ .Region }}/{{ .ID }}"
Expand All @@ -36,21 +47,79 @@ var associations = map[interface{}]*association{
&container.Container{}: {
ResourceName: "scaleway_container",
ImportFormat: importFormatRegionID,
SubResources: map[string]*associationSubResource{
"NamespaceID": {
TerraformAttributeName: "namespace_id",
Command: "container namespace get {{ .NamespaceID }}",
Parents: map[string]*associationParent{
"namespace_id": {
Fetcher: func(client *scw.Client, raw interface{}) (interface{}, error) {
api := container.NewAPI(client)
data := raw.(*container.Container)

return api.GetNamespace(&container.GetNamespaceRequest{
NamespaceID: data.NamespaceID,
Region: data.Region,
})
},
},
},
},
&container.Namespace{}: {
ResourceName: "scaleway_container_namespace",
ImportFormat: importFormatRegionID,
SubResources: map[string]*associationSubResource{
"ProjectID": {
TerraformAttributeName: "project_id",
Command: "container project get project-id={{ .ProjectID }}",
AsDataSource: true,
Parents: map[string]*associationParent{
"project_id": {
AsDataSource: true,
Fetcher: func(client *scw.Client, raw interface{}) (interface{}, error) {
api := account.NewAPI(client)
data := raw.(*container.Namespace)

return api.GetProject(&account.GetProjectRequest{
ProjectID: data.ProjectID,
})
},
},
},
Children: []*associationChild{
{
ParentFieldMap: map[string]string{
"namespace_id": "id",
},
Fetcher: func(client *scw.Client, raw interface{}) (interface{}, error) {
api := container.NewAPI(client)
data := raw.(*container.Namespace)

res, err := api.ListContainers(&container.ListContainersRequest{
NamespaceID: data.ID,
Region: data.Region,
})
if err != nil {
return nil, err
}

return res.Containers, nil
},
},
},
},
&account.Project{}: {
ResourceName: "scaleway_account_project",
ImportFormat: "{{ .ID }}",
Children: []*associationChild{
{
ParentFieldMap: map[string]string{
"project_id": "id",
},
Fetcher: func(client *scw.Client, raw interface{}) (interface{}, error) {
api := container.NewAPI(client)
data := raw.(*account.Project)

res, err := api.ListNamespaces(&container.ListNamespacesRequest{
ProjectID: &data.ID,
})
if err != nil {
return nil, err
}

return res.Namespaces, nil
},
},
},
},
Expand Down
Loading

0 comments on commit 2cb0d09

Please sign in to comment.