Skip to content

Commit 1590966

Browse files
authored
[feat] Support usage of separate Linode API for the domain client (#436)
* Use default http transport instead of oauth2.Transport * Improve client/import naming to avoid confusion * Pull and apply new custom dns client envs * Inform about fallback of dns token to general api token * Handle timeouts with compatible client * Don't count emitted log lines in tests * Update tests with new dns params * Impl. ClientConfig * Update getting started docs * object_storage_bucket: Rm unnecessary nolint:dupl * Populate system cert pool if root cert not provided * Rework doc additions into dns-loadbalancing.md
1 parent 1b4a2b9 commit 1590966

26 files changed

+257
-168
lines changed

cloud/scope/cluster.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func validateClusterScopeParams(params ClusterScopeParams) error {
5050

5151
// NewClusterScope creates a new Scope from the supplied parameters.
5252
// This is meant to be called for each reconcile iteration.
53-
func NewClusterScope(ctx context.Context, apiKey string, params ClusterScopeParams) (*ClusterScope, error) {
53+
func NewClusterScope(ctx context.Context, linodeClientConfig ClientConfig, params ClusterScopeParams) (*ClusterScope, error) {
5454
if err := validateClusterScopeParams(params); err != nil {
5555
return nil, err
5656
}
@@ -62,9 +62,9 @@ func NewClusterScope(ctx context.Context, apiKey string, params ClusterScopePara
6262
if err != nil {
6363
return nil, fmt.Errorf("credentials from secret ref: %w", err)
6464
}
65-
apiKey = string(apiToken)
65+
linodeClientConfig.Token = string(apiToken)
6666
}
67-
linodeClient, err := CreateLinodeClient(apiKey, defaultClientTimeout)
67+
linodeClient, err := CreateLinodeClient(linodeClientConfig)
6868
if err != nil {
6969
return nil, fmt.Errorf("failed to create linode client: %w", err)
7070
}

cloud/scope/cluster_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ func TestClusterScopeMethods(t *testing.T) {
157157

158158
cScope, err := NewClusterScope(
159159
context.Background(),
160-
"test-key",
160+
ClientConfig{Token: "test-key"},
161161
ClusterScopeParams{
162162
Cluster: testcase.fields.Cluster,
163163
LinodeCluster: testcase.fields.LinodeCluster,
@@ -297,7 +297,7 @@ func TestNewClusterScope(t *testing.T) {
297297
LinodeCluster: &infrav1alpha2.LinodeCluster{},
298298
},
299299
},
300-
expectedError: fmt.Errorf("failed to create linode client: missing Linode API key"),
300+
expectedError: fmt.Errorf("failed to create linode client: token cannot be empty"),
301301
expects: func(mock *mock.MockK8sClient) {},
302302
},
303303
}
@@ -316,7 +316,7 @@ func TestNewClusterScope(t *testing.T) {
316316

317317
testcase.args.params.Client = mockK8sClient
318318

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

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

412412
cScope, err := NewClusterScope(
413413
context.Background(),
414-
"test-key",
414+
ClientConfig{Token: "test-key"},
415415
ClusterScopeParams{
416416
Cluster: testcase.fields.Cluster,
417417
LinodeCluster: testcase.fields.LinodeCluster,
@@ -512,7 +512,7 @@ func TestRemoveCredentialsRefFinalizer(t *testing.T) {
512512

513513
cScope, err := NewClusterScope(
514514
context.Background(),
515-
"test-key",
515+
ClientConfig{Token: "test-key"},
516516
ClusterScopeParams{
517517
Cluster: testcase.fields.Cluster,
518518
LinodeCluster: testcase.fields.LinodeCluster,

cloud/scope/common.go

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package scope
22

33
import (
44
"context"
5+
"crypto/tls"
6+
"crypto/x509"
57
"errors"
68
"fmt"
79
"net/http"
@@ -13,7 +15,6 @@ import (
1315
"github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/edgegrid"
1416
"github.com/akamai/AkamaiOPEN-edgegrid-golang/v8/pkg/session"
1517
"github.com/linode/linodego"
16-
"golang.org/x/oauth2"
1718
corev1 "k8s.io/api/core/v1"
1819
"sigs.k8s.io/controller-runtime/pkg/client"
1920
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
@@ -44,29 +45,59 @@ func WithRetryCount(c int) Option {
4445
}
4546
}
4647

47-
func CreateLinodeClient(apiKey string, timeout time.Duration, opts ...Option) (LinodeClient, error) {
48-
if apiKey == "" {
49-
return nil, errors.New("missing Linode API key")
48+
type ClientConfig struct {
49+
Token string
50+
BaseUrl string
51+
RootCertificatePath string
52+
53+
Timeout time.Duration
54+
}
55+
56+
func CreateLinodeClient(config ClientConfig, opts ...Option) (LinodeClient, error) {
57+
if config.Token == "" {
58+
return nil, errors.New("token cannot be empty")
5059
}
5160

52-
tokenSource := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: apiKey})
61+
timeout := defaultClientTimeout
62+
if config.Timeout != 0 {
63+
timeout = config.Timeout
64+
}
5365

54-
oauth2Client := &http.Client{
55-
Transport: &oauth2.Transport{
56-
Source: tokenSource,
57-
},
66+
// Use system cert pool if root CA cert was not provided explicitly for this client.
67+
// Works around linodego not using system certs if LINODE_CA is provided,
68+
// which affects all clients spawned via linodego.NewClient
69+
tlsConfig := &tls.Config{MinVersion: tls.VersionTLS12}
70+
if config.RootCertificatePath == "" {
71+
systemCertPool, err := x509.SystemCertPool()
72+
if err != nil {
73+
return nil, fmt.Errorf("failed to load system cert pool: %w", err)
74+
}
75+
tlsConfig.RootCAs = systemCertPool
76+
}
77+
78+
httpClient := &http.Client{
5879
Timeout: timeout,
80+
Transport: &http.Transport{
81+
TLSClientConfig: tlsConfig,
82+
},
5983
}
60-
linodeClient := linodego.NewClient(oauth2Client)
6184

62-
linodeClient.SetUserAgent(fmt.Sprintf("CAPL/%s", version.GetVersion()))
85+
newClient := linodego.NewClient(httpClient)
86+
newClient.SetToken(config.Token)
87+
if config.RootCertificatePath != "" {
88+
newClient.SetRootCertificate(config.RootCertificatePath)
89+
}
90+
if config.BaseUrl != "" {
91+
newClient.SetBaseURL(config.BaseUrl)
92+
}
93+
newClient.SetUserAgent(fmt.Sprintf("CAPL/%s", version.GetVersion()))
6394

6495
for _, opt := range opts {
65-
opt.set(&linodeClient)
96+
opt.set(&newClient)
6697
}
6798

6899
return linodeclient.NewLinodeClientWithTracing(
69-
&linodeClient,
100+
&newClient,
70101
linodeclient.DefaultDecorator(),
71102
), nil
72103
}

cloud/scope/common_test.go

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"testing"
7+
"time"
78

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

2425
tests := []struct {
25-
name string
26-
apiKey string
27-
expectedErr error
26+
name string
27+
token string
28+
baseUrl string
29+
rootCertificatePath string
30+
timeout time.Duration
31+
expectedErr error
2832
}{
2933
{
30-
"Success - Valid API Key",
34+
"Success - Valid API token",
3135
"test-key",
36+
"",
37+
"",
38+
0,
3239
nil,
3340
},
3441
{
35-
"Error - Empty API Key",
42+
"Error - Empty API token",
43+
"",
44+
"",
3645
"",
37-
errors.New("missing Linode API key"),
46+
0,
47+
errors.New("token cannot be empty"),
3848
},
3949
}
4050

4151
for _, tt := range tests {
4252
testCase := tt
4353
t.Run(testCase.name, func(t *testing.T) {
4454
t.Parallel()
45-
46-
got, err := CreateLinodeClient(testCase.apiKey, defaultClientTimeout)
47-
55+
clientConfig := ClientConfig{
56+
Token: testCase.token,
57+
Timeout: testCase.timeout,
58+
BaseUrl: testCase.baseUrl,
59+
RootCertificatePath: testCase.rootCertificatePath,
60+
}
61+
got, err := CreateLinodeClient(clientConfig)
4862
if testCase.expectedErr != nil {
4963
assert.EqualError(t, err, testCase.expectedErr.Error())
5064
} else {

cloud/scope/machine.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func validateMachineScopeParams(params MachineScopeParams) error {
5353
return nil
5454
}
5555

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

8989
dnsToken, err := getCredentialDataFromRef(ctx, params.Client, *credentialRef, defaultNamespace, "dnsToken")
9090
if err != nil || len(dnsToken) == 0 {
9191
dnsToken = apiToken
9292
}
93-
dnsKey = string(dnsToken)
93+
dnsClientConfig.Token = string(dnsToken)
9494
}
9595

96-
linodeClient, err := CreateLinodeClient(apiKey, defaultClientTimeout,
96+
linodeClient, err := CreateLinodeClient(linodeClientConfig,
9797
WithRetryCount(0),
9898
)
9999
if err != nil {
100100
return nil, fmt.Errorf("failed to create linode client: %w", err)
101101
}
102-
linodeDomainsClient, err := CreateLinodeClient(dnsKey, defaultClientTimeout,
102+
linodeDomainsClient, err := CreateLinodeClient(dnsClientConfig,
103103
WithRetryCount(0),
104104
)
105105
if err != nil {

0 commit comments

Comments
 (0)