Skip to content

Commit

Permalink
Enable setting credentials using profile default:(~/.osc/config.json)
Browse files Browse the repository at this point in the history
  • Loading branch information
outscale-toa committed Nov 6, 2024
1 parent 2b384d9 commit 077d48d
Show file tree
Hide file tree
Showing 6 changed files with 278 additions and 42 deletions.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (
github.com/nav-inc/datetime v0.1.3
github.com/outscale/osc-sdk-go/v2 v2.23.0
github.com/spf13/cast v1.6.0
github.com/tidwall/gjson v1.18.0
)

require (
Expand Down Expand Up @@ -51,6 +52,8 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
Expand Down
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,13 @@ github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
Expand Down
20 changes: 11 additions & 9 deletions outscale/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ import (

// Config ...
type Config struct {
AccessKeyID string
SecretKeyID string
Region string
TokenID string
Endpoints map[string]interface{}
X509cert string
X509key string
Insecure bool
AccessKeyID string
SecretKeyID string
Region string
TokenID string
Endpoints map[string]interface{}
X509CertPath string
X509KeyPath string
Insecure bool
ConfigFilePath string
Profile string
}

// OutscaleClient client
Expand All @@ -31,7 +33,7 @@ type OutscaleClient struct {
// Client ...
func (c *Config) Client() (*OutscaleClient, error) {
tlsconfig := &tls.Config{InsecureSkipVerify: c.Insecure}
cert, err := tls.LoadX509KeyPair(c.X509cert, c.X509key)
cert, err := tls.LoadX509KeyPair(c.X509CertPath, c.X509KeyPath)
if err == nil {
tlsconfig = &tls.Config{
InsecureSkipVerify: false,
Expand Down
99 changes: 96 additions & 3 deletions outscale/framework_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"context"
"crypto/tls"
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"

"github.com/hashicorp/terraform-plugin-framework/diag"
Expand All @@ -13,6 +15,7 @@ import (
oscgo "github.com/outscale/osc-sdk-go/v2"
"github.com/outscale/terraform-provider-outscale/utils"
"github.com/outscale/terraform-provider-outscale/version"
"github.com/tidwall/gjson"
)

// OutscaleClient client
Expand All @@ -22,8 +25,14 @@ type OutscaleClient_fw struct {

// Client ...
func (c *frameworkProvider) Client_fw(ctx context.Context, data *ProviderModel, diags *diag.Diagnostics) (*OutscaleClient_fw, error) {
ok, err := IsProfileSet(data)
if err != nil {
return nil, err
}
if !ok {
setDefaultEnv(data)
}

setDefaultEnv(data)
tlsconfig := &tls.Config{InsecureSkipVerify: c.insecure}
cert, err := tls.LoadX509KeyPair(data.X509CertPath.ValueString(), data.X509KeyPath.ValueString())
if err == nil {
Expand Down Expand Up @@ -66,6 +75,90 @@ func (c *frameworkProvider) Client_fw(ctx context.Context, data *ProviderModel,
return client, nil
}

func IsProfileSet(data *ProviderModel) (bool, error) {
isProfSet := false
if profileName, ok := os.LookupEnv("OSC_PROFILE"); ok || !data.Profile.IsNull() {
if data.Profile.ValueString() != "" {
profileName = data.Profile.ValueString()
}

var profilePath string
if envPath, ok := os.LookupEnv("OSC_CONFIG_FILE"); ok || !data.ConfigFilePath.IsNull() {
if data.ConfigFilePath.ValueString() != "" {
profilePath = data.ConfigFilePath.ValueString()
} else {
profilePath = envPath
}
if profilePath == "" {
homePath, err := os.UserHomeDir()
if err != nil {
return isProfSet, err
}
profilePath = homePath + "/.osc/config.json"
}
}
jsonFile, err := ioutil.ReadFile(profilePath)
if err != nil {
return isProfSet, err
}
profile := gjson.GetBytes(jsonFile, profileName)
if !gjson.Valid(profile.String()) {
return isProfSet, fmt.Errorf("Invalid json profile file")
}
if !profile.Get("access_key").Exists() ||
!profile.Get("secret_key").Exists() {
return isProfSet, fmt.Errorf("Profile 'access_key' or 'secret_key' are not defined!")
}
setProfile(data, profile)
isProfSet = true
}
return isProfSet, nil
}

func setProfile(data *ProviderModel, profile gjson.Result) {
if data.AccessKeyId.IsNull() {
if accessKeyId := profile.Get("access_key").String(); accessKeyId != "" {
data.AccessKeyId = types.StringValue(accessKeyId)
}
}
if data.SecretKeyId.IsNull() {
if secretKeyId := profile.Get("secret_key").String(); secretKeyId != "" {
data.SecretKeyId = types.StringValue(secretKeyId)
}
}
if data.Region.IsNull() {
if profile.Get("region").Exists() {
if region := profile.Get("region").String(); region != "" {
data.Region = types.StringValue(region)
}
}
}
if data.X509CertPath.IsNull() {
if profile.Get("x509_cert_path").Exists() {
if x509Cert := profile.Get("x509_cert_path").String(); x509Cert != "" {
data.X509CertPath = types.StringValue(x509Cert)
}
}
}
if data.X509KeyPath.IsNull() {
if profile.Get("x509_key_path").Exists() {
if x509Key := profile.Get("x509_key_path").String(); x509Key != "" {
data.X509KeyPath = types.StringValue(x509Key)
}
}
}
if len(data.Endpoints) == 0 {
if profile.Get("endpoints").Exists() {
endpoints := profile.Get("endpoints").Value().(map[string]interface{})
if endpoint := endpoints["api"].(string); endpoint != "" {
endp := make([]Endpoints, 1)
endp[0].API = types.StringValue(endpoint)
data.Endpoints = endp
}
}
}
}

func setDefaultEnv(data *ProviderModel) {
if data.AccessKeyId.IsNull() {
if accessKeyId := utils.GetEnvVariableValue([]string{"OSC_ACCESS_KEY", "OUTSCALE_ACCESSKEYID"}); accessKeyId != "" {
Expand Down Expand Up @@ -96,9 +189,9 @@ func setDefaultEnv(data *ProviderModel) {
}
}
if len(data.Endpoints) == 0 {
if endpoints := utils.GetEnvVariableValue([]string{"OSC_ENDPOINT_API", "OUTSCALE_OAPI_URL"}); endpoints != "" {
if endpoint := utils.GetEnvVariableValue([]string{"OSC_ENDPOINT_API", "OUTSCALE_OAPI_URL"}); endpoint != "" {
endp := make([]Endpoints, 1)
endp[0].API = types.StringValue(endpoints)
endp[0].API = types.StringValue(endpoint)
data.Endpoints = endp
}
}
Expand Down
58 changes: 43 additions & 15 deletions outscale/framework_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,28 @@ func New(version string) provider.Provider {
}

type frameworkProvider struct {
accessKeyId types.String
secretKeyId types.String
region types.String
endpoints []Endpoints
x509CertPath string
x509KeyPath string
insecure bool
version string
accessKeyId types.String
secretKeyId types.String
region types.String
endpoints []Endpoints
x509CertPath string
x509KeyPath string
configFilePath string
insecure bool
profile string
version string
}

type ProviderModel struct {
AccessKeyId types.String `tfsdk:"access_key_id"`
SecretKeyId types.String `tfsdk:"secret_key_id"`
Region types.String `tfsdk:"region"`
Endpoints []Endpoints `tfsdk:"endpoints"`
X509CertPath types.String `tfsdk:"x509_cert_path"`
X509KeyPath types.String `tfsdk:"x509_key_path"`
Insecure types.Bool `tfsdk:"insecure"`
AccessKeyId types.String `tfsdk:"access_key_id"`
SecretKeyId types.String `tfsdk:"secret_key_id"`
Region types.String `tfsdk:"region"`
Endpoints []Endpoints `tfsdk:"endpoints"`
X509CertPath types.String `tfsdk:"x509_cert_path"`
X509KeyPath types.String `tfsdk:"x509_key_path"`
ConfigFilePath types.String `tfsdk:"config_file_path"`
Profile types.String `tfsdk:"profile"`
Insecure types.Bool `tfsdk:"insecure"`
}

type Endpoints struct {
Expand Down Expand Up @@ -87,6 +91,14 @@ func (p *frameworkProvider) Schema(ctx context.Context, req provider.SchemaReque
Optional: true,
Description: "The path to your x509 key",
},
"config_file_path": schema.StringAttribute{
Optional: true,
Description: "The path to your configuration file in which you have defined your credentials.",
},
"profile": schema.StringAttribute{
Optional: true,
Description: "The name of your profile in which you define your credencial",
},
"insecure": schema.BoolAttribute{
Optional: true,
Description: "tls insecure connection",
Expand Down Expand Up @@ -149,6 +161,22 @@ func (p *frameworkProvider) Configure(ctx context.Context, req provider.Configur
"Either target apply the source of the value first, set the value statically in the configuration, or use the 'OSC_X509_CLIENT_KEY or OUTSCALE_X509KEY' environment variable.",
)
}
if config.ConfigFilePath.IsUnknown() {
resp.Diagnostics.AddAttributeError(
path.Root("config_file_path"),
"Unknown Outscale API ConfigFilePath",
"The provider cannot create the Outscale API client as there is an unknown configuration value for the Outscale API profile. "+
"Either target apply the source of the value first, set the value statically in the configuration, or use the 'OSC_CONFIG_FILE' environment variable.",
)
}
if config.Profile.IsUnknown() {
resp.Diagnostics.AddAttributeError(
path.Root("profile"),
"Unknown Outscale API profile",
"The provider cannot create the Outscale API client as there is an unknown configuration value for the Outscale API profile. "+
"Either target apply the source of the value first, set the value statically in the configuration, or use the 'OSC_PROFILE' environment variable.",
)
}

if resp.Diagnostics.HasError() {
return
Expand Down
Loading

0 comments on commit 077d48d

Please sign in to comment.