Skip to content

Commit 6ae123b

Browse files
authored
[feat] Adding new fields in LinodeObjectStorageBucket and decoupling ObjKey Functionality (#443)
* Adding fields and decoupling ObjBucket and ObjKey Functionality * Modifying e2e test case for minimal-linodeobjectstoragebucket * Adding cors in create opts and lint suggestions * lint suggestions * lint suggestions * key generation pointer changes
1 parent 8ab18ac commit 6ae123b

19 files changed

+132
-1399
lines changed

api/v1alpha1/conversion.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"strings"
2121

2222
"k8s.io/apimachinery/pkg/conversion"
23+
"k8s.io/utils/ptr"
2324

2425
infrastructurev1alpha2 "github.com/linode/cluster-api-provider-linode/api/v1alpha2"
2526
)
@@ -50,16 +51,26 @@ func Convert_v1alpha1_LinodeObjectStorageBucketSpec_To_v1alpha2_LinodeObjectStor
5051
// WARNING: in.Cluster requires manual conversion: does not exist in peer-type
5152
out.Region = in.Cluster
5253
out.CredentialsRef = in.CredentialsRef
53-
out.KeyGeneration = in.KeyGeneration
5454
out.SecretType = in.SecretType
5555
return nil
5656
}
57+
func Convert_v1alpha1_LinodeObjectStorageBucketStatus_To_v1alpha2_LinodeObjectStorageBucketStatus(in *LinodeObjectStorageBucketStatus, out *infrastructurev1alpha2.LinodeObjectStorageBucketStatus, s conversion.Scope) error {
58+
out.Ready = in.Ready
59+
out.FailureMessage = in.FailureMessage
60+
out.Conditions = in.Conditions
61+
out.Hostname = in.Hostname
62+
out.CreationTime = in.CreationTime
63+
// WARNING: in.LastKeyGeneration requires manual conversion: does not exist in peer-type
64+
// WARNING: in.KeySecretName requires manual conversion: does not exist in peer-type
65+
// WARNING: in.AccessKeyRefs requires manual conversion: does not exist in peer-type
66+
return nil
67+
}
5768

5869
func Convert_v1alpha2_LinodeObjectStorageBucketSpec_To_v1alpha1_LinodeObjectStorageBucketSpec(in *infrastructurev1alpha2.LinodeObjectStorageBucketSpec, out *LinodeObjectStorageBucketSpec, s conversion.Scope) error {
5970
// WARNING: in.Region requires manual conversion: does not exist in peer-type
6071
out.Cluster = in.Region
6172
out.CredentialsRef = in.CredentialsRef
62-
out.KeyGeneration = in.KeyGeneration
73+
out.KeyGeneration = ptr.To(0)
6374
out.SecretType = in.SecretType
6475
return nil
6576
}

api/v1alpha1/linodeobjectstoragebucket_conversion_test.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,7 @@ func TestLinodeObjectStorageBucketConvertTo(t *testing.T) {
5959
Namespace: "default",
6060
Name: "cred-secret",
6161
},
62-
KeyGeneration: ptr.To(1),
63-
SecretType: "Opaque",
62+
SecretType: "Opaque",
6463
},
6564
Status: infrav1alpha2.LinodeObjectStorageBucketStatus{},
6665
}
@@ -96,16 +95,15 @@ func TestLinodeObjectStorageBucketFrom(t *testing.T) {
9695
Namespace: "default",
9796
Name: "cred-secret",
9897
},
99-
KeyGeneration: ptr.To(1),
100-
SecretType: "Opaque",
98+
SecretType: "Opaque",
10199
},
102100
Status: infrav1alpha2.LinodeObjectStorageBucketStatus{},
103101
}
104102
expectedDst := &LinodeObjectStorageBucket{
105103
ObjectMeta: metav1.ObjectMeta{
106104
Name: "test-bucket",
107105
Annotations: map[string]string{
108-
ConversionDataAnnotation: `{"spec":{"credentialsRef":{"name":"cred-secret","namespace":"default"},"keyGeneration":1,"region":"us-mia-1","secretType":"Opaque"},"status":{"ready":false}}`,
106+
ConversionDataAnnotation: `{"spec":{"credentialsRef":{"name":"cred-secret","namespace":"default"},"region":"us-mia-1","secretType":"Opaque"},"status":{"ready":false}}`,
109107
},
110108
},
111109
Spec: LinodeObjectStorageBucketSpec{
@@ -114,7 +112,7 @@ func TestLinodeObjectStorageBucketFrom(t *testing.T) {
114112
Namespace: "default",
115113
Name: "cred-secret",
116114
},
117-
KeyGeneration: ptr.To(1),
115+
KeyGeneration: ptr.To(0),
118116
SecretType: "Opaque",
119117
},
120118
Status: LinodeObjectStorageBucketStatus{},

api/v1alpha1/zz_generated.conversion.go

Lines changed: 11 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v1alpha2/linodeobjectstoragebucket_types.go

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,17 @@ import (
2222
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
2323
)
2424

25+
type ObjectStorageACL string
26+
27+
// ObjectStorageACL options represent the access control level of a bucket.
2528
const (
2629
// ObjectStorageBucketFinalizer allows ReconcileLinodeObjectStorageBucket to clean up Linode resources associated
2730
// with LinodeObjectStorageBucket before removing it from the apiserver.
28-
ObjectStorageBucketFinalizer = "linodeobjectstoragebucket.infrastructure.cluster.x-k8s.io"
31+
ObjectStorageBucketFinalizer = "linodeobjectstoragebucket.infrastructure.cluster.x-k8s.io"
32+
ACLPrivate ObjectStorageACL = "private"
33+
ACLPublicRead ObjectStorageACL = "public-read"
34+
ACLAuthenticatedRead ObjectStorageACL = "authenticated-read"
35+
ACLPublicReadWrite ObjectStorageACL = "public-read-write"
2936
)
3037

3138
// LinodeObjectStorageBucketSpec defines the desired state of LinodeObjectStorageBucket
@@ -37,16 +44,22 @@ type LinodeObjectStorageBucketSpec struct {
3744
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
3845
Region string `json:"region"`
3946

47+
// ACL sets The Access Control Level of the bucket using a canned ACL string
48+
// +optional
49+
// +kubebuilder:default=private
50+
// +kubebuilder:validation:Enum=private;public-read;authenticated-read;public-read-write
51+
ACL ObjectStorageACL `json:"acl,omitempty"`
52+
53+
// corsEnabled enables for all origins in the bucket .If set to false, CORS is disabled for all origins in the bucket
54+
// +optional
55+
// +kubebuilder:default=true
56+
CorsEnabled *bool `json:"corsEnabled,omitempty"`
57+
4058
// CredentialsRef is a reference to a Secret that contains the credentials to use for provisioning the bucket.
4159
// If not supplied then the credentials of the controller will be used.
4260
// +optional
4361
CredentialsRef *corev1.SecretReference `json:"credentialsRef"`
4462

45-
// KeyGeneration may be modified to trigger rotations of access keys created for the bucket.
46-
// +optional
47-
// +kubebuilder:default=0
48-
KeyGeneration *int `json:"keyGeneration,omitempty"`
49-
5063
// SecretType sets the type for the bucket-details secret that will be generated by the controller.
5164
// +optional
5265
// +kubebuilder:default=addons.cluster.x-k8s.io/resource-set
@@ -80,18 +93,6 @@ type LinodeObjectStorageBucketStatus struct {
8093
// CreationTime specifies the creation timestamp for the bucket.
8194
// +optional
8295
CreationTime *metav1.Time `json:"creationTime,omitempty"`
83-
84-
// LastKeyGeneration tracks the last known value of .spec.keyGeneration.
85-
// +optional
86-
LastKeyGeneration *int `json:"lastKeyGeneration,omitempty"`
87-
88-
// KeySecretName specifies the name of the Secret containing access keys for the bucket.
89-
// +optional
90-
KeySecretName *string `json:"keySecretName,omitempty"`
91-
92-
// AccessKeyRefs stores IDs for Object Storage keys provisioned along with the bucket.
93-
// +optional
94-
AccessKeyRefs []int `json:"accessKeyRefs,omitempty"`
9596
}
9697

9798
// +kubebuilder:object:root=true

api/v1alpha2/zz_generated.deepcopy.go

Lines changed: 5 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cloud/scope/object_storage_bucket.go

Lines changed: 1 addition & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,14 @@ import (
77
"time"
88

99
"github.com/go-logr/logr"
10-
"github.com/linode/linodego"
11-
corev1 "k8s.io/api/core/v1"
12-
apierrors "k8s.io/apimachinery/pkg/api/errors"
13-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1410
"sigs.k8s.io/cluster-api/util/patch"
15-
"sigs.k8s.io/controller-runtime/pkg/client"
1611
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
1712

1813
infrav1alpha2 "github.com/linode/cluster-api-provider-linode/api/v1alpha2"
1914

2015
. "github.com/linode/cluster-api-provider-linode/clients"
2116
)
2217

23-
const bucketDataSecret = `kind: Secret
24-
apiVersion: v1
25-
metadata:
26-
name: etcd-backup
27-
namespace: kube-system
28-
stringData:
29-
bucket_name: %s
30-
bucket_region: %s
31-
bucket_endpoint: %s
32-
access_key_rw: %s
33-
secret_key_rw: %s
34-
access_key_ro: %s
35-
secret_key_ro: %s`
36-
3718
type ObjectStorageBucketScopeParams struct {
3819
Client K8sClient
3920
Bucket *infrav1alpha2.LinodeObjectStorageBucket
@@ -49,9 +30,7 @@ type ObjectStorageBucketScope struct {
4930
}
5031

5132
const (
52-
AccessKeyNameTemplate = "%s-bucket-details"
53-
NumAccessKeys = 2
54-
clientTimeout = 20 * time.Second
33+
clientTimeout = 20 * time.Second
5534
)
5635

5736
func validateObjectStorageBucketScopeParams(params ObjectStorageBucketScopeParams) error {
@@ -119,78 +98,3 @@ func (s *ObjectStorageBucketScope) AddFinalizer(ctx context.Context) error {
11998

12099
return nil
121100
}
122-
123-
// GenerateKeySecret returns a secret suitable for submission to the Kubernetes API.
124-
// The secret is expected to contain keys for accessing the bucket, as well as owner and controller references.
125-
func (s *ObjectStorageBucketScope) GenerateKeySecret(ctx context.Context, keys [NumAccessKeys]*linodego.ObjectStorageKey, bucket *linodego.ObjectStorageBucket) (*corev1.Secret, error) {
126-
for _, key := range keys {
127-
if key == nil {
128-
return nil, errors.New("expected two non-nil object storage keys")
129-
}
130-
}
131-
var secretStringData map[string]string
132-
secretName := fmt.Sprintf(AccessKeyNameTemplate, s.Bucket.Name)
133-
// If the secret is of ClusterResourceSet type, encapsulate real data in the outer data
134-
if s.Bucket.Spec.SecretType == "addons.cluster.x-k8s.io/resource-set" {
135-
secretStringData = map[string]string{
136-
"bucket-details-secret.yaml": fmt.Sprintf(bucketDataSecret,
137-
bucket.Label,
138-
bucket.Region,
139-
bucket.Hostname,
140-
keys[0].AccessKey,
141-
keys[0].SecretKey,
142-
keys[1].AccessKey,
143-
keys[1].SecretKey,
144-
),
145-
}
146-
} else {
147-
secretStringData = map[string]string{
148-
"bucket_name": bucket.Label,
149-
"bucket_region": bucket.Region,
150-
"bucket_endpoint": bucket.Hostname,
151-
"access_key_rw": keys[0].AccessKey,
152-
"secret_key_rw": keys[0].SecretKey,
153-
"access_key_ro": keys[1].AccessKey,
154-
"secret_key_ro": keys[1].SecretKey,
155-
}
156-
}
157-
secret := &corev1.Secret{
158-
ObjectMeta: metav1.ObjectMeta{
159-
Name: secretName,
160-
Namespace: s.Bucket.Namespace,
161-
},
162-
Type: corev1.SecretType(s.Bucket.Spec.SecretType),
163-
StringData: secretStringData,
164-
}
165-
166-
scheme := s.Client.Scheme()
167-
if err := controllerutil.SetOwnerReference(s.Bucket, secret, scheme); err != nil {
168-
return nil, fmt.Errorf("could not set owner ref on access key secret %s: %w", secretName, err)
169-
}
170-
if err := controllerutil.SetControllerReference(s.Bucket, secret, scheme); err != nil {
171-
return nil, fmt.Errorf("could not set controller ref on access key secret %s: %w", secretName, err)
172-
}
173-
174-
return secret, nil
175-
}
176-
177-
func (s *ObjectStorageBucketScope) ShouldInitKeys() bool {
178-
return s.Bucket.Status.LastKeyGeneration == nil
179-
}
180-
181-
func (s *ObjectStorageBucketScope) ShouldRotateKeys() bool {
182-
return s.Bucket.Status.LastKeyGeneration != nil &&
183-
*s.Bucket.Spec.KeyGeneration != *s.Bucket.Status.LastKeyGeneration
184-
}
185-
186-
func (s *ObjectStorageBucketScope) ShouldRestoreKeySecret(ctx context.Context) (bool, error) {
187-
if s.Bucket.Status.KeySecretName == nil {
188-
return false, nil
189-
}
190-
191-
secret := &corev1.Secret{}
192-
key := client.ObjectKey{Namespace: s.Bucket.Namespace, Name: *s.Bucket.Status.KeySecretName}
193-
err := s.Client.Get(ctx, key, secret)
194-
195-
return apierrors.IsNotFound(err), client.IgnoreNotFound(err)
196-
}

0 commit comments

Comments
 (0)