-
Notifications
You must be signed in to change notification settings - Fork 161
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
feat: add scaleway provider with scaleway_function_namespace resource support #1648
base: main
Are you sure you want to change the base?
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,65 @@ | ||
package client | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/scaleway/scaleway-sdk-go/scw" | ||
"github.com/snyk/driftctl/pkg/version" | ||
) | ||
|
||
// Create - Creates a new Scaleway client object | ||
// Heavily inspired by the createClient method in Scaleway CLI: | ||
// https://github.com/scaleway/scaleway-cli/blob/v2.13.0/internal/core/client.go#L15-L83 | ||
func Create() (*scw.Client, error) { | ||
|
||
profile := scw.LoadEnvProfile() | ||
|
||
// Default path is based on the following priority order: | ||
// * $SCW_CONFIG_PATH | ||
// * $XDG_CONFIG_HOME/scw/config.yaml | ||
// * $HOME/.config/scw/config.yaml | ||
// * $USERPROFILE/.config/scw/config.yaml | ||
var errConfigFileNotFound *scw.ConfigFileNotFoundError | ||
config, err := scw.LoadConfigFromPath(scw.GetConfigPath()) | ||
|
||
switch { | ||
case errors.As(err, &errConfigFileNotFound): | ||
break | ||
case err != nil: | ||
return nil, err | ||
default: | ||
// If a config file is found and loaded, we merge with env | ||
activeProfile, err := config.GetActiveProfile() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Creates a client from the active profile | ||
// It will trigger a validation step on its configuration to catch errors if any | ||
opts := []scw.ClientOption{ | ||
scw.WithProfile(activeProfile), | ||
} | ||
|
||
_, err = scw.NewClient(opts...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
profile = scw.MergeProfiles(activeProfile, profile) | ||
} | ||
|
||
opts := []scw.ClientOption{ | ||
scw.WithDefaultRegion(scw.RegionFrPar), | ||
scw.WithDefaultZone(scw.ZoneFrPar1), | ||
scw.WithUserAgent(fmt.Sprintf("driftctl/%s", version.Current())), | ||
scw.WithProfile(profile), | ||
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. If the profile contains a region (e.g. |
||
} | ||
|
||
client, err := scw.NewClient(opts...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return client, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package scaleway | ||
|
||
import ( | ||
remoteerror "github.com/snyk/driftctl/enumeration/remote/error" | ||
"github.com/snyk/driftctl/enumeration/remote/scaleway/repository" | ||
"github.com/snyk/driftctl/enumeration/resource" | ||
"github.com/snyk/driftctl/pkg/resource/scaleway" | ||
) | ||
|
||
type FunctionNamespaceEnumerator struct { | ||
repository repository.FunctionRepository | ||
factory resource.ResourceFactory | ||
} | ||
|
||
func NewFunctionNamespaceEnumerator(repo repository.FunctionRepository, factory resource.ResourceFactory) *FunctionNamespaceEnumerator { | ||
return &FunctionNamespaceEnumerator{ | ||
repository: repo, | ||
factory: factory, | ||
} | ||
} | ||
|
||
func (e *FunctionNamespaceEnumerator) SupportedType() resource.ResourceType { | ||
return scaleway.ScalewayFunctionNamespaceResourceType | ||
} | ||
|
||
func (e *FunctionNamespaceEnumerator) Enumerate() ([]*resource.Resource, error) { | ||
namespaces, err := e.repository.ListAllNamespaces() | ||
if err != nil { | ||
return nil, remoteerror.NewResourceListingError(err, string(e.SupportedType())) | ||
} | ||
|
||
results := make([]*resource.Resource, 0, len(namespaces)) | ||
|
||
for _, namespace := range namespaces { | ||
results = append( | ||
results, | ||
e.factory.CreateAbstractResource( | ||
string(e.SupportedType()), | ||
getRegionalID(namespace.Region.String(), namespace.ID), | ||
map[string]interface{}{}, | ||
), | ||
) | ||
} | ||
|
||
return results, err | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package scaleway | ||
|
||
import ( | ||
"github.com/snyk/driftctl/enumeration" | ||
"github.com/snyk/driftctl/enumeration/alerter" | ||
"github.com/snyk/driftctl/enumeration/remote/cache" | ||
"github.com/snyk/driftctl/enumeration/remote/common" | ||
"github.com/snyk/driftctl/enumeration/remote/scaleway/client" | ||
"github.com/snyk/driftctl/enumeration/remote/scaleway/repository" | ||
"github.com/snyk/driftctl/enumeration/resource" | ||
"github.com/snyk/driftctl/enumeration/terraform" | ||
"github.com/snyk/driftctl/pkg/resource/scaleway" | ||
) | ||
|
||
func Init(version string, alerter alerter.AlerterInterface, providerLibrary *terraform.ProviderLibrary, remoteLibrary *common.RemoteLibrary, progress enumeration.ProgressCounter, factory resource.ResourceFactory, configDir string) error { | ||
|
||
if version == "" { | ||
version = "2.14.1" | ||
} | ||
|
||
provider, err := NewScalewayTerraformProvider(version, progress, configDir) | ||
if err != nil { | ||
return err | ||
} | ||
err = provider.Init() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
providerLibrary.AddProvider(terraform.SCALEWAY, provider) | ||
|
||
scwClient, err := client.Create() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
repositoryCache := cache.New(100) | ||
|
||
funcRepository := repository.NewFunctionRepository(scwClient, repositoryCache) | ||
|
||
deserializer := resource.NewDeserializer(factory) | ||
|
||
remoteLibrary.AddEnumerator(NewFunctionNamespaceEnumerator(funcRepository, factory)) | ||
remoteLibrary.AddDetailsFetcher(scaleway.ScalewayFunctionNamespaceResourceType, common.NewGenericDetailsFetcher(scaleway.ScalewayFunctionNamespaceResourceType, provider, deserializer)) | ||
|
||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package scaleway | ||
|
||
import ( | ||
"github.com/snyk/driftctl/enumeration" | ||
"github.com/snyk/driftctl/enumeration/remote/terraform" | ||
tf "github.com/snyk/driftctl/enumeration/terraform" | ||
) | ||
|
||
type ScalewayTerraformProvider struct { | ||
*terraform.TerraformProvider | ||
name string | ||
version string | ||
} | ||
|
||
func NewScalewayTerraformProvider(version string, progress enumeration.ProgressCounter, configDir string) (*ScalewayTerraformProvider, error) { | ||
|
||
provider := &ScalewayTerraformProvider{ | ||
version: version, | ||
name: "scaleway", | ||
} | ||
|
||
installer, err := tf.NewProviderInstaller(tf.ProviderConfig{ | ||
Key: provider.name, | ||
Version: version, | ||
ConfigDir: configDir, | ||
}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
tfProvider, err := terraform.NewTerraformProvider(installer, terraform.TerraformProviderConfig{ | ||
Name: provider.name, | ||
}, progress) | ||
if err != nil { | ||
return nil, err | ||
} | ||
provider.TerraformProvider = tfProvider | ||
return provider, err | ||
} | ||
|
||
func (p *ScalewayTerraformProvider) Name() string { | ||
return p.name | ||
} | ||
|
||
func (p *ScalewayTerraformProvider) Version() string { | ||
return p.version | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package repository | ||
|
||
import ( | ||
"github.com/scaleway/scaleway-sdk-go/api/function/v1beta1" | ||
"github.com/scaleway/scaleway-sdk-go/scw" | ||
"github.com/snyk/driftctl/enumeration/remote/cache" | ||
) | ||
|
||
type FunctionRepository interface { | ||
ListAllNamespaces() ([]*function.Namespace, error) | ||
} | ||
|
||
// We create an interface here (mainly for mocking purpose) because in scaleway-sdk-go, API is a struct and not an interface | ||
type functionAPI interface { | ||
ListNamespaces(req *function.ListNamespacesRequest, opts ...scw.RequestOption) (*function.ListNamespacesResponse, error) | ||
} | ||
|
||
type functionRepository struct { | ||
client functionAPI | ||
cache cache.Cache | ||
} | ||
|
||
func NewFunctionRepository(client *scw.Client, c cache.Cache) *functionRepository { | ||
|
||
api := function.NewAPI(client) | ||
return &functionRepository{ | ||
api, | ||
c, | ||
} | ||
} | ||
|
||
func (r *functionRepository) ListAllNamespaces() ([]*function.Namespace, error) { | ||
if v := r.cache.Get("functionListAllNamespaces"); v != nil { | ||
return v.([]*function.Namespace), nil | ||
} | ||
|
||
req := &function.ListNamespacesRequest{} | ||
res, err := r.client.ListNamespaces(req) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
namespaces := res.Namespaces | ||
|
||
r.cache.Put("functionListAllNamespaces", namespaces) | ||
|
||
return namespaces, err | ||
} |
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've added Scaleway in the list of providers here (but advertised it's still in alpha since only one resource is available). Tell me if we should wait before putting it in the README!