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

Add support for object storage services gen2 #649

Merged
merged 11 commits into from
Jan 15, 2025
31 changes: 20 additions & 11 deletions object_storage_bucket_certs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,44 @@ import (
"context"
)

// Deprecated: Please use ObjectStorageBucketCertV2 for all new implementations.
type ObjectStorageBucketCert struct {
SSL bool `json:"ssl"`
}

type ObjectStorageBucketCertV2 struct {
SSL *bool `json:"ssl"`
}

type ObjectStorageBucketCertUploadOptions struct {
Certificate string `json:"certificate"`
PrivateKey string `json:"private_key"`
}

// UploadObjectStorageBucketCert uploads a TLS/SSL Cert to be used with an Object Storage Bucket.
// Deprecated: Please use UploadObjectStorageBucketCertV2 for all new implementations.
func (c *Client) UploadObjectStorageBucketCert(ctx context.Context, clusterOrRegionID, bucket string, opts ObjectStorageBucketCertUploadOptions) (*ObjectStorageBucketCert, error) {
e := formatAPIPath("object-storage/buckets/%s/%s/ssl", clusterOrRegionID, bucket)
response, err := doPOSTRequest[ObjectStorageBucketCert](ctx, c, e, opts)
if err != nil {
return nil, err
}

return response, nil
return doPOSTRequest[ObjectStorageBucketCert](ctx, c, e, opts)
}

// GetObjectStorageBucketCert gets an ObjectStorageBucketCert
// Deprecated: Please use GetObjectStorageBucketCertV2 for all new implementations.
func (c *Client) GetObjectStorageBucketCert(ctx context.Context, clusterOrRegionID, bucket string) (*ObjectStorageBucketCert, error) {
e := formatAPIPath("object-storage/buckets/%s/%s/ssl", clusterOrRegionID, bucket)
response, err := doGETRequest[ObjectStorageBucketCert](ctx, c, e)
if err != nil {
return nil, err
}
return doGETRequest[ObjectStorageBucketCert](ctx, c, e)
}

return response, nil
// UploadObjectStorageBucketCert uploads a TLS/SSL Cert to be used with an Object Storage Bucket.
func (c *Client) UploadObjectStorageBucketCertV2(ctx context.Context, clusterOrRegionID, bucket string, opts ObjectStorageBucketCertUploadOptions) (*ObjectStorageBucketCertV2, error) {
e := formatAPIPath("object-storage/buckets/%s/%s/ssl", clusterOrRegionID, bucket)
return doPOSTRequest[ObjectStorageBucketCertV2](ctx, c, e, opts)
}

// GetObjectStorageBucketCertV2 gets an ObjectStorageBucketCert
func (c *Client) GetObjectStorageBucketCertV2(ctx context.Context, clusterOrRegionID, bucket string) (*ObjectStorageBucketCertV2, error) {
e := formatAPIPath("object-storage/buckets/%s/%s/ssl", clusterOrRegionID, bucket)
return doGETRequest[ObjectStorageBucketCertV2](ctx, c, e)
}

// DeleteObjectStorageBucketCert deletes an ObjectStorageBucketCert
Expand Down
66 changes: 29 additions & 37 deletions object_storage_buckets.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ type ObjectStorageBucket struct {
Cluster string `json:"cluster"`
Region string `json:"region"`

Created *time.Time `json:"-"`
Hostname string `json:"hostname"`
Objects int `json:"objects"`
Size int `json:"size"`
S3Endpoint string `json:"s3_endpoint"`
EndpointType ObjectStorageEndpointType `json:"endpoint_type"`
Created *time.Time `json:"-"`
Hostname string `json:"hostname"`
Objects int `json:"objects"`
Size int `json:"size"`
}

// ObjectStorageBucketAccess holds Object Storage access info
Expand All @@ -36,6 +38,13 @@ type ObjectStorageBucketAccess struct {
CorsEnabled bool `json:"cors_enabled"`
}

type ObjectStorageBucketAccessV2 struct {
ACL ObjectStorageACL `json:"acl"`
ACLXML string `json:"acl_xml"`
CorsEnabled *bool `json:"cors_enabled"`
CorsXML *string `json:"cors_xml"`
}

// ObjectStorageBucketContent holds the content of an ObjectStorageBucket
type ObjectStorageBucketContent struct {
Data []ObjectStorageBucketContentData `json:"data"`
Expand Down Expand Up @@ -82,7 +91,9 @@ type ObjectStorageBucketCreateOptions struct {
Cluster string `json:"cluster,omitempty"`
Region string `json:"region,omitempty"`

Label string `json:"label"`
Label string `json:"label"`
S3Endpoint string `json:"s3_endpoint,omitempty"`
EndpointType ObjectStorageEndpointType `json:"endpoint_type,omitempty"`

ACL ObjectStorageACL `json:"acl,omitempty"`
CorsEnabled *bool `json:"cors_enabled,omitempty"`
Expand Down Expand Up @@ -115,55 +126,31 @@ const (

// ListObjectStorageBuckets lists ObjectStorageBuckets
func (c *Client) ListObjectStorageBuckets(ctx context.Context, opts *ListOptions) ([]ObjectStorageBucket, error) {
response, err := getPaginatedResults[ObjectStorageBucket](ctx, c, "object-storage/buckets", opts)
if err != nil {
return nil, err
}

return response, nil
return getPaginatedResults[ObjectStorageBucket](ctx, c, "object-storage/buckets", opts)
}

// ListObjectStorageBucketsInCluster lists all ObjectStorageBuckets of a cluster
func (c *Client) ListObjectStorageBucketsInCluster(ctx context.Context, opts *ListOptions, clusterOrRegionID string) ([]ObjectStorageBucket, error) {
response, err := getPaginatedResults[ObjectStorageBucket](ctx, c, formatAPIPath("object-storage/buckets/%s", clusterOrRegionID), opts)
if err != nil {
return nil, err
}

return response, nil
return getPaginatedResults[ObjectStorageBucket](ctx, c, formatAPIPath("object-storage/buckets/%s", clusterOrRegionID), opts)
}

// GetObjectStorageBucket gets the ObjectStorageBucket with the provided label
func (c *Client) GetObjectStorageBucket(ctx context.Context, clusterOrRegionID, label string) (*ObjectStorageBucket, error) {
e := formatAPIPath("object-storage/buckets/%s/%s", clusterOrRegionID, label)
response, err := doGETRequest[ObjectStorageBucket](ctx, c, e)
if err != nil {
return nil, err
}

return response, nil
return doGETRequest[ObjectStorageBucket](ctx, c, e)
}

// CreateObjectStorageBucket creates an ObjectStorageBucket
func (c *Client) CreateObjectStorageBucket(ctx context.Context, opts ObjectStorageBucketCreateOptions) (*ObjectStorageBucket, error) {
e := "object-storage/buckets"
response, err := doPOSTRequest[ObjectStorageBucket](ctx, c, e, opts)
if err != nil {
return nil, err
}

return response, nil
return doPOSTRequest[ObjectStorageBucket](ctx, c, e, opts)
}

// GetObjectStorageBucketAccess gets the current access config for a bucket
// Deprecated: use GetObjectStorageBucketAccessV2 for new implementations
func (c *Client) GetObjectStorageBucketAccess(ctx context.Context, clusterOrRegionID, label string) (*ObjectStorageBucketAccess, error) {
e := formatAPIPath("object-storage/buckets/%s/%s/access", clusterOrRegionID, label)
response, err := doGETRequest[ObjectStorageBucketAccess](ctx, c, e)
if err != nil {
return nil, err
}

return response, nil
return doGETRequest[ObjectStorageBucketAccess](ctx, c, e)
}

// UpdateObjectStorageBucketAccess updates the access configuration for an ObjectStorageBucket
Expand All @@ -174,11 +161,16 @@ func (c *Client) UpdateObjectStorageBucketAccess(ctx context.Context, clusterOrR
return err
}

// GetObjectStorageBucketAccess gets the current access config for a bucket
func (c *Client) GetObjectStorageBucketAccessV2(ctx context.Context, clusterOrRegionID, label string) (*ObjectStorageBucketAccessV2, error) {
e := formatAPIPath("object-storage/buckets/%s/%s/access", clusterOrRegionID, label)
return doGETRequest[ObjectStorageBucketAccessV2](ctx, c, e)
}

// DeleteObjectStorageBucket deletes the ObjectStorageBucket with the specified label
func (c *Client) DeleteObjectStorageBucket(ctx context.Context, clusterOrRegionID, label string) error {
e := formatAPIPath("object-storage/buckets/%s/%s", clusterOrRegionID, label)
err := doDELETERequest(ctx, c, e)
return err
return doDELETERequest(ctx, c, e)
}

// Lists the contents of the specified ObjectStorageBucket
Expand Down
26 changes: 26 additions & 0 deletions object_storage_endpoints.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package linodego

import "context"

// NotificationType constants start with Notification and include all known Linode API Notification Types.
type ObjectStorageEndpointType string

// NotificationType constants represent the actions that cause a Notification. New types may be added in the future.
const (
ObjectStorageEndpointE0 ObjectStorageEndpointType = "E0"
ObjectStorageEndpointE1 ObjectStorageEndpointType = "E1"
ObjectStorageEndpointE2 ObjectStorageEndpointType = "E2"
ObjectStorageEndpointE3 ObjectStorageEndpointType = "E3"
)

// ObjectStorageEndpoint represents a linode object storage endpoint object
type ObjectStorageEndpoint struct {
Region string `json:"region"`
S3Endpoint *string `json:"s3_endpoint"`
EndpointType ObjectStorageEndpointType `json:"endpoint_type"`
}

// ListObjectStorageEndpoints lists all endpoints in all regions
func (c *Client) ListObjectStorageEndpoints(ctx context.Context, opts *ListOptions) ([]ObjectStorageEndpoint, error) {
return getPaginatedResults[ObjectStorageEndpoint](ctx, c, "object-storage/endpoints", opts)
}
5 changes: 3 additions & 2 deletions object_storage_keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import (
)

type ObjectStorageKeyRegion struct {
ID string `json:"id"`
S3Endpoint string `json:"s3_endpoint"`
ID string `json:"id"`
S3Endpoint string `json:"s3_endpoint"`
EndpointType ObjectStorageEndpointType `json:"endpoint_type"`
}

// ObjectStorageKey represents a linode object storage key object
Expand Down
27 changes: 21 additions & 6 deletions object_storage_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,45 @@ type ObjectStorageObjectURL struct {
Exists bool `json:"exists"`
}

// Deprecated: Please use ObjectStorageObjectACLConfigV2 for all new implementations.
type ObjectStorageObjectACLConfig struct {
ACL string `json:"acl"`
ACLXML string `json:"acl_xml"`
}

type ObjectStorageObjectACLConfigV2 struct {
ACL *string `json:"acl"`
ACLXML *string `json:"acl_xml"`
}

type ObjectStorageObjectACLConfigUpdateOptions struct {
Name string `json:"name"`
ACL string `json:"acl"`
}

func (c *Client) CreateObjectStorageObjectURL(ctx context.Context, objectID, label string, opts ObjectStorageObjectURLCreateOptions) (*ObjectStorageObjectURL, error) {
e := formatAPIPath("object-storage/buckets/%s/%s/object-url", objectID, label)
response, err := doPOSTRequest[ObjectStorageObjectURL](ctx, c, e, opts)
return response, err
return doPOSTRequest[ObjectStorageObjectURL](ctx, c, e, opts)
}

// Deprecated: use GetObjectStorageObjectACLConfigV2 for new implementations
func (c *Client) GetObjectStorageObjectACLConfig(ctx context.Context, objectID, label, object string) (*ObjectStorageObjectACLConfig, error) {
e := formatAPIPath("object-storage/buckets/%s/%s/object-acl?name=%s", objectID, label, object)
response, err := doGETRequest[ObjectStorageObjectACLConfig](ctx, c, e)
return response, err
return doGETRequest[ObjectStorageObjectACLConfig](ctx, c, e)
}

// Deprecated: use UpdateObjectStorageObjectACLConfigV2 for new implementations
func (c *Client) UpdateObjectStorageObjectACLConfig(ctx context.Context, objectID, label string, opts ObjectStorageObjectACLConfigUpdateOptions) (*ObjectStorageObjectACLConfig, error) {
e := formatAPIPath("object-storage/buckets/%s/%s/object-acl", objectID, label)
response, err := doPUTRequest[ObjectStorageObjectACLConfig](ctx, c, e, opts)
return response, err
return doPUTRequest[ObjectStorageObjectACLConfig](ctx, c, e, opts)
}

func (c *Client) GetObjectStorageObjectACLConfigV2(ctx context.Context, objectID, label, object string) (*ObjectStorageObjectACLConfigV2, error) {
e := formatAPIPath("object-storage/buckets/%s/%s/object-acl?name=%s", objectID, label, object)
return doGETRequest[ObjectStorageObjectACLConfigV2](ctx, c, e)
}

func (c *Client) UpdateObjectStorageObjectACLConfigV2(ctx context.Context, objectID, label string, opts ObjectStorageObjectACLConfigUpdateOptions) (*ObjectStorageObjectACLConfigV2, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it's worth introducing a ObjectStorageObjectACLConfigUpdateOptionsV2 struct for consistency and future-proofing, although it might be a bit redundant 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the API schema will stay the same for this set of options? Gen2 doesn't currently support the object-level ACL.

e := formatAPIPath("object-storage/buckets/%s/%s/object-acl", objectID, label)
return doPUTRequest[ObjectStorageObjectACLConfigV2](ctx, c, e, opts)
}
61 changes: 33 additions & 28 deletions regions.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,39 @@ import (
// Defined as strings rather than a custom type to avoid breaking change.
// Can be changed in the potential v2 version.
const (
CapabilityLinodes string = "Linodes"
CapabilityNodeBalancers string = "NodeBalancers"
CapabilityBlockStorage string = "Block Storage"
CapabilityObjectStorage string = "Object Storage"
CapabilityObjectStorageRegions string = "Object Storage Access Key Regions"
CapabilityLKE string = "Kubernetes"
CapabilityLkeHaControlPlanes string = "LKE HA Control Planes"
CapabilityCloudFirewall string = "Cloud Firewall"
CapabilityGPU string = "GPU Linodes"
CapabilityVlans string = "Vlans"
CapabilityVPCs string = "VPCs"
CapabilityVPCsExtra string = "VPCs Extra"
CapabilityQuadraT1UVPU string = "NETINT Quadra T1U"
CapabilityMachineImages string = "Machine Images"
CapabilityBareMetal string = "Bare Metal"
CapabilityDBAAS string = "Managed Databases"
CapabilityBlockStorageMigrations string = "Block Storage Migrations"
CapabilityMetadata string = "Metadata"
CapabilityPremiumPlans string = "Premium Plans"
CapabilityEdgePlans string = "Edge Plans"
CapabilityLKEControlPlaneACL string = "LKE Network Access Control List (IP ACL)"
CapabilityACLB string = "Akamai Cloud Load Balancer"
CapabilitySupportTicketSeverity string = "Support Ticket Severity"
CapabilityBackups string = "Backups"
CapabilityPlacementGroup string = "Placement Group"
CapabilityDiskEncryption string = "Disk Encryption"
CapabilityBlockStorageEncryption string = "Block Storage Encryption"
CapabilityKubernetesEnterprise string = "Kubernetes Enterprise"
CapabilityACLB string = "Akamai Cloud Load Balancer"
CapabilityBackups string = "Backups"
CapabilityBareMetal string = "Bare Metal"
CapabilityBlockStorage string = "Block Storage"
CapabilityBlockStorageEncryption string = "Block Storage Encryption"
CapabilityBlockStorageMigrations string = "Block Storage Migrations"
CapabilityCloudFirewall string = "Cloud Firewall"
CapabilityDBAAS string = "Managed Databases"
CapabilityDiskEncryption string = "Disk Encryption"
CapabilityEdgePlans string = "Edge Plans"
CapabilityGPU string = "GPU Linodes"
CapabilityKubernetesEnterprise string = "Kubernetes Enterprise"
CapabilityLKE string = "Kubernetes"
CapabilityLKEControlPlaneACL string = "LKE Network Access Control List (IP ACL)"
CapabilityLinodes string = "Linodes"
CapabilityLkeHaControlPlanes string = "LKE HA Control Planes"
CapabilityMachineImages string = "Machine Images"
CapabilityMetadata string = "Metadata"
CapabilityNodeBalancers string = "NodeBalancers"
CapabilityObjectStorage string = "Object Storage"
CapabilityObjectStorageAccessKeyRegions string = "Object Storage Access Key Regions"
CapabilityObjectStorageEndpointTypes string = "Object Storage Endpoint Types"
CapabilityPlacementGroup string = "Placement Group"
CapabilityPremiumPlans string = "Premium Plans"
CapabilityQuadraT1UVPU string = "NETINT Quadra T1U"
CapabilitySupportTicketSeverity string = "Support Ticket Severity"
CapabilityVPCs string = "VPCs"
CapabilityVPCsExtra string = "VPCs Extra"
CapabilityVlans string = "Vlans"

// Deprecated: CapabilityObjectStorageRegions constant has been
// renamed to `CapabilityObjectStorageAccessKeyRegions`.
CapabilityObjectStorageRegions string = CapabilityObjectStorageAccessKeyRegions
)

// Region-related endpoints have a custom expiry time as the
Expand Down
Loading
Loading