Skip to content
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] Support usage of separate Linode API for the domain client #436

Merged
merged 13 commits into from
Aug 5, 2024
Merged
6 changes: 3 additions & 3 deletions cloud/scope/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func validateClusterScopeParams(params ClusterScopeParams) error {

// NewClusterScope creates a new Scope from the supplied parameters.
// This is meant to be called for each reconcile iteration.
func NewClusterScope(ctx context.Context, apiKey string, params ClusterScopeParams) (*ClusterScope, error) {
func NewClusterScope(ctx context.Context, linodeClientConfig ClientConfig, params ClusterScopeParams) (*ClusterScope, error) {
if err := validateClusterScopeParams(params); err != nil {
return nil, err
}
Expand All @@ -62,9 +62,9 @@ func NewClusterScope(ctx context.Context, apiKey string, params ClusterScopePara
if err != nil {
return nil, fmt.Errorf("credentials from secret ref: %w", err)
}
apiKey = string(apiToken)
linodeClientConfig.Token = string(apiToken)
}
linodeClient, err := CreateLinodeClient(apiKey, defaultClientTimeout)
linodeClient, err := CreateLinodeClient(linodeClientConfig)
if err != nil {
return nil, fmt.Errorf("failed to create linode client: %w", err)
}
Expand Down
10 changes: 5 additions & 5 deletions cloud/scope/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ func TestClusterScopeMethods(t *testing.T) {

cScope, err := NewClusterScope(
context.Background(),
"test-key",
ClientConfig{Token: "test-key"},
ClusterScopeParams{
Cluster: testcase.fields.Cluster,
LinodeCluster: testcase.fields.LinodeCluster,
Expand Down Expand Up @@ -297,7 +297,7 @@ func TestNewClusterScope(t *testing.T) {
LinodeCluster: &infrav1alpha2.LinodeCluster{},
},
},
expectedError: fmt.Errorf("failed to create linode client: missing Linode API key"),
expectedError: fmt.Errorf("failed to create linode client: token cannot be empty"),
expects: func(mock *mock.MockK8sClient) {},
},
}
Expand All @@ -316,7 +316,7 @@ func TestNewClusterScope(t *testing.T) {

testcase.args.params.Client = mockK8sClient

got, err := NewClusterScope(context.Background(), testcase.args.apiKey, testcase.args.params)
got, err := NewClusterScope(context.Background(), ClientConfig{Token: testcase.args.apiKey}, testcase.args.params)

if testcase.expectedError != nil {
assert.ErrorContains(t, err, testcase.expectedError.Error())
Expand Down Expand Up @@ -411,7 +411,7 @@ func TestClusterAddCredentialsRefFinalizer(t *testing.T) {

cScope, err := NewClusterScope(
context.Background(),
"test-key",
ClientConfig{Token: "test-key"},
ClusterScopeParams{
Cluster: testcase.fields.Cluster,
LinodeCluster: testcase.fields.LinodeCluster,
Expand Down Expand Up @@ -512,7 +512,7 @@ func TestRemoveCredentialsRefFinalizer(t *testing.T) {

cScope, err := NewClusterScope(
context.Background(),
"test-key",
ClientConfig{Token: "test-key"},
ClusterScopeParams{
Cluster: testcase.fields.Cluster,
LinodeCluster: testcase.fields.LinodeCluster,
Expand Down
57 changes: 44 additions & 13 deletions cloud/scope/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"net/http"
Expand All @@ -13,7 +15,6 @@
"github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid"
"github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session"
"github.com/linode/linodego"
"golang.org/x/oauth2"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
Expand Down Expand Up @@ -44,29 +45,59 @@
}
}

func CreateLinodeClient(apiKey string, timeout time.Duration, opts ...Option) (LinodeClient, error) {
if apiKey == "" {
return nil, errors.New("missing Linode API key")
type ClientConfig struct {
Token string
BaseUrl string
RootCertificatePath string

Timeout time.Duration
}

func CreateLinodeClient(config ClientConfig, opts ...Option) (LinodeClient, error) {
if config.Token == "" {
return nil, errors.New("token cannot be empty")
}

tokenSource := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: apiKey})
timeout := defaultClientTimeout
if config.Timeout != 0 {
timeout = config.Timeout
}

oauth2Client := &http.Client{
Transport: &oauth2.Transport{
Source: tokenSource,
},
// Use system cert pool if root CA cert was not provided explicitly for this client.
// Works around linodego not using system certs if LINODE_CA is provided,
// which affects all clients spawned via linodego.NewClient
tlsConfig := &tls.Config{MinVersion: tls.VersionTLS12}
if config.RootCertificatePath == "" {
systemCertPool, err := x509.SystemCertPool()
if err != nil {
return nil, fmt.Errorf("failed to load system cert pool: %w", err)

Check warning on line 73 in cloud/scope/common.go

View check run for this annotation

Codecov / codecov/patch

cloud/scope/common.go#L73

Added line #L73 was not covered by tests
}
tlsConfig.RootCAs = systemCertPool
}

httpClient := &http.Client{
Timeout: timeout,
Transport: &http.Transport{
TLSClientConfig: tlsConfig,
},
}
linodeClient := linodego.NewClient(oauth2Client)

linodeClient.SetUserAgent(fmt.Sprintf("CAPL/%s", version.GetVersion()))
newClient := linodego.NewClient(httpClient)
newClient.SetToken(config.Token)
if config.RootCertificatePath != "" {
newClient.SetRootCertificate(config.RootCertificatePath)

Check warning on line 88 in cloud/scope/common.go

View check run for this annotation

Codecov / codecov/patch

cloud/scope/common.go#L88

Added line #L88 was not covered by tests
}
if config.BaseUrl != "" {
newClient.SetBaseURL(config.BaseUrl)

Check warning on line 91 in cloud/scope/common.go

View check run for this annotation

Codecov / codecov/patch

cloud/scope/common.go#L91

Added line #L91 was not covered by tests
}
newClient.SetUserAgent(fmt.Sprintf("CAPL/%s", version.GetVersion()))

for _, opt := range opts {
opt.set(&linodeClient)
opt.set(&newClient)
}

return linodeclient.NewLinodeClientWithTracing(
&linodeClient,
&newClient,
linodeclient.DefaultDecorator(),
), nil
}
Expand Down
32 changes: 23 additions & 9 deletions cloud/scope/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"testing"
"time"

"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
Expand All @@ -22,29 +23,42 @@ func TestCreateLinodeClient(t *testing.T) {
t.Parallel()

tests := []struct {
name string
apiKey string
expectedErr error
name string
token string
baseUrl string
rootCertificatePath string
timeout time.Duration
expectedErr error
}{
{
"Success - Valid API Key",
"Success - Valid API token",
"test-key",
"",
"",
0,
nil,
},
{
"Error - Empty API Key",
"Error - Empty API token",
"",
"",
"",
errors.New("missing Linode API key"),
0,
errors.New("token cannot be empty"),
},
}

for _, tt := range tests {
testCase := tt
t.Run(testCase.name, func(t *testing.T) {
t.Parallel()

got, err := CreateLinodeClient(testCase.apiKey, defaultClientTimeout)

clientConfig := ClientConfig{
Token: testCase.token,
Timeout: testCase.timeout,
BaseUrl: testCase.baseUrl,
RootCertificatePath: testCase.rootCertificatePath,
}
got, err := CreateLinodeClient(clientConfig)
if testCase.expectedErr != nil {
assert.EqualError(t, err, testCase.expectedErr.Error())
} else {
Expand Down
10 changes: 5 additions & 5 deletions cloud/scope/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func validateMachineScopeParams(params MachineScopeParams) error {
return nil
}

func NewMachineScope(ctx context.Context, apiKey, dnsKey string, params MachineScopeParams) (*MachineScope, error) {
func NewMachineScope(ctx context.Context, linodeClientConfig, dnsClientConfig ClientConfig, params MachineScopeParams) (*MachineScope, error) {
if err := validateMachineScopeParams(params); err != nil {
return nil, err
}
Expand Down Expand Up @@ -84,22 +84,22 @@ func NewMachineScope(ctx context.Context, apiKey, dnsKey string, params MachineS
if err != nil {
return nil, fmt.Errorf("credentials from secret ref: %w", err)
}
apiKey = string(apiToken)
linodeClientConfig.Token = string(apiToken)

dnsToken, err := getCredentialDataFromRef(ctx, params.Client, *credentialRef, defaultNamespace, "dnsToken")
if err != nil || len(dnsToken) == 0 {
dnsToken = apiToken
}
dnsKey = string(dnsToken)
dnsClientConfig.Token = string(dnsToken)
}

linodeClient, err := CreateLinodeClient(apiKey, defaultClientTimeout,
linodeClient, err := CreateLinodeClient(linodeClientConfig,
WithRetryCount(0),
)
if err != nil {
return nil, fmt.Errorf("failed to create linode client: %w", err)
}
linodeDomainsClient, err := CreateLinodeClient(dnsKey, defaultClientTimeout,
linodeDomainsClient, err := CreateLinodeClient(dnsClientConfig,
WithRetryCount(0),
)
if err != nil {
Expand Down
Loading
Loading