Skip to content

Commit

Permalink
tmp add object-storage
Browse files Browse the repository at this point in the history
  • Loading branch information
grongor committed Apr 23, 2024
1 parent 3a755a4 commit c016e16
Show file tree
Hide file tree
Showing 19 changed files with 1,166 additions and 153 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/cdn77/terraform-provider-cdn77
go 1.22

require (
github.com/cdn77/cdn77-client-go v0.0.0-20240417141351-700a85f8affc
github.com/cdn77/cdn77-client-go v0.0.0-20240423130134-1eda9cd8a9db
github.com/hashicorp/terraform-plugin-docs v0.19.0
github.com/hashicorp/terraform-plugin-framework v1.7.0
github.com/hashicorp/terraform-plugin-framework-validators v0.12.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwN
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
github.com/cdn77/cdn77-client-go v0.0.0-20240417141351-700a85f8affc h1:DAGwuXaybraJN1EIYbHRo898WiqExX3RtFnGJRaFWXA=
github.com/cdn77/cdn77-client-go v0.0.0-20240417141351-700a85f8affc/go.mod h1:j4vMPxoGnDqRBDMR/gdtXotIiKhEnWh3wJFsw3mTUQc=
github.com/cdn77/cdn77-client-go v0.0.0-20240423130134-1eda9cd8a9db h1:PLsdDBdFTFkbtnHjjtqqezrd+n7J4qQlL/fQkclPG4c=
github.com/cdn77/cdn77-client-go v0.0.0-20240423130134-1eda9cd8a9db/go.mod h1:j4vMPxoGnDqRBDMR/gdtXotIiKhEnWh3wJFsw3mTUQc=
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
Expand Down
2 changes: 2 additions & 0 deletions internal/acctest/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ func DeleteOrigin(client cdn77.ClientWithResponsesInterface, originType string,
switch originType {
case provider.OriginTypeAws:
response, err = client.OriginDeleteAwsWithResponse(context.Background(), id)
case provider.OriginTypeObjectStorage:
response, err = client.OriginDeleteObjectStorageWithResponse(context.Background(), id)
case provider.OriginTypeUrl:
response, err = client.OriginDeleteUrlWithResponse(context.Background(), id)
default:
Expand Down
2 changes: 1 addition & 1 deletion internal/provider/cdns_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type CdnSummaryModel struct {
Mp4PseudoStreamingEnabled types.Bool `tfsdk:"mp4_pseudo_streaming_enabled"`
}

var _ datasource.DataSourceWithConfigure = &OriginDataSource{}
var _ datasource.DataSourceWithConfigure = &CdnsDataSource{}

func NewCdnsDataSource() datasource.DataSource {
return &CdnsDataSource{}
Expand Down
115 changes: 115 additions & 0 deletions internal/provider/object_storages_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package provider

import (
"context"
"sort"

"github.com/cdn77/cdn77-client-go"
"github.com/cdn77/terraform-provider-cdn77/internal/util"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
)

type ObjectStoragesModel struct {
Clusters []ObjectStorageModel `tfsdk:"clusters"`
}

type ObjectStorageModel struct {
Id types.String `tfsdk:"id"`
Host types.String `tfsdk:"host"`
Label types.String `tfsdk:"label"`
Port types.Int64 `tfsdk:"port"`
Scheme types.String `tfsdk:"scheme"`
}

var _ datasource.DataSourceWithConfigure = &ObjectStoragesDataSource{}

func NewObjectStoragesDataSource() datasource.DataSource {
return &ObjectStoragesDataSource{}
}

type ObjectStoragesDataSource struct {
client cdn77.ClientWithResponsesInterface
}

func (*ObjectStoragesDataSource) Metadata(
_ context.Context,
req datasource.MetadataRequest,
resp *datasource.MetadataResponse,
) {
resp.TypeName = req.ProviderTypeName + "_object_storages"
}

func (*ObjectStoragesDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"clusters": schema.ListNestedAttribute{
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Description: "ID (UUID) of the Object Storage cluster",
Computed: true,
},
"host": schema.StringAttribute{
Computed: true,
},
"label": schema.StringAttribute{
Computed: true,
},
"port": schema.Int64Attribute{
Computed: true,
},
"scheme": schema.StringAttribute{
Computed: true,
},
},
},
Computed: true,
Description: "List of all Object Storage clusters",
},
},
Description: "Object Storages data source allows you to read all available Object Storage clusters",
}
}

func (d *ObjectStoragesDataSource) Configure(
_ context.Context,
req datasource.ConfigureRequest,
resp *datasource.ConfigureResponse,
) {
resp.Diagnostics.Append(util.MaybeSetClient(req.ProviderData, &d.client))
}

func (d *ObjectStoragesDataSource) Read(ctx context.Context, _ datasource.ReadRequest, resp *datasource.ReadResponse) {
const errMessage = "Failed to fetch list of all Object Storages"

response, err := d.client.ObjectStorageClusterListWithResponse(ctx)
if err != nil {
resp.Diagnostics.AddError(errMessage, err.Error())

return
}

if !util.CheckResponse(&resp.Diagnostics, errMessage, response, response.JSONDefault) {
return
}

objectStorages := make([]ObjectStorageModel, 0, len(*response.JSON200))

for _, objectStorage := range *response.JSON200 {
objectStorages = append(objectStorages, ObjectStorageModel{
Id: types.StringValue(objectStorage.Id),
Host: types.StringValue(objectStorage.Host),
Label: types.StringValue(objectStorage.Label),
Port: util.IntPointerToInt64Value(objectStorage.Port),
Scheme: types.StringValue(objectStorage.Scheme),
})
}

sort.SliceStable(objectStorages, func(i, j int) bool {
return objectStorages[i].Id.ValueString() < objectStorages[j].Id.ValueString()
})

resp.Diagnostics.Append(resp.State.Set(ctx, &ObjectStoragesModel{Clusters: objectStorages})...)
}
46 changes: 46 additions & 0 deletions internal/provider/object_storages_data_source_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package provider_test

import (
"regexp"
"testing"

"github.com/cdn77/terraform-provider-cdn77/internal/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/knownvalue"
"github.com/hashicorp/terraform-plugin-testing/statecheck"
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
)

func TestAccObjectStoragesDataSource_All(t *testing.T) {
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: acctest.GetProviderFactories(),
Steps: []resource.TestStep{
{
Config: objectStoragesDataSourceConfig,
ConfigStateChecks: []statecheck.StateCheck{
statecheck.ExpectKnownValue("data.cdn77_object_storages.all",
tfjsonpath.New("clusters"),
knownvalue.SetPartial([]knownvalue.Check{
knownvalue.ObjectExact(map[string]knownvalue.Check{
"id": knownvalue.StringRegexp(regexp.MustCompile(
`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`,
)),
"host": knownvalue.StringRegexp(regexp.MustCompile(
`^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$`,
)),
"label": knownvalue.StringExact("EU"),
"port": knownvalue.Int64Exact(443),
"scheme": knownvalue.StringExact("https"),
}),
}),
),
},
},
},
})
}

const objectStoragesDataSourceConfig = `
data "cdn77_object_storages" "all" {
}
`
136 changes: 136 additions & 0 deletions internal/provider/origin_config_validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package provider

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-framework-validators/helpers/validatordiag"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
)

var (
_ datasource.ConfigValidator = &OriginConfigValidator{}
_ resource.ConfigValidator = &OriginConfigValidator{}
)

type OriginConfigValidator struct{}

func NewOriginTypeConfigValidator() *OriginConfigValidator {
return &OriginConfigValidator{}
}

func (v OriginConfigValidator) Description(ctx context.Context) string {
return v.MarkdownDescription(ctx)
}

func (OriginConfigValidator) MarkdownDescription(_ context.Context) string {
return "Checks Origin configuration for all required/conflicting attributes"
}

func (v OriginConfigValidator) ValidateDataSource(
ctx context.Context,
req datasource.ValidateConfigRequest,
resp *datasource.ValidateConfigResponse,
) {
resp.Diagnostics = v.Validate(ctx, req.Config)
}

func (v OriginConfigValidator) ValidateResource(
ctx context.Context,
req resource.ValidateConfigRequest,
resp *resource.ValidateConfigResponse,
) {
resp.Diagnostics = v.Validate(ctx, req.Config)
}

func (v OriginConfigValidator) Validate(ctx context.Context, config tfsdk.Config) diag.Diagnostics {
var data OriginModel
diags := config.Get(ctx, &data)

originType := data.Type.ValueString()
awsAttributes := []attrNameAndValue{
{name: "aws_access_key_id", value: data.AwsAccessKeyId},
{name: "aws_access_key_secret", value: data.AwsAccessKeySecret},
{name: "aws_region", value: data.AwsRegion},
}
objectStorageAttributes := []attrNameAndValue{
{name: "acl", value: data.Acl},
{name: "cluster_id", value: data.ClusterId},
//{name: "access_key_id", value: data.AccessKeyId},
//{name: "access_key_secret", value: data.AccessKeySecret},
{name: "bucket_name", value: data.BucketName},
}
schemeAndHostAttributes := []attrNameAndValue{
{name: "scheme", value: data.Scheme},
{name: "host", value: data.Host},
}
var conflictingAttributes, requiredAttributes []attrNameAndValue

switch originType {
case OriginTypeAws:
conflictingAttributes = append(conflictingAttributes, objectStorageAttributes...)
requiredAttributes = schemeAndHostAttributes
case OriginTypeObjectStorage:
conflictingAttributes = append(conflictingAttributes, awsAttributes...)
conflictingAttributes = append(conflictingAttributes, schemeAndHostAttributes...)
conflictingAttributes = append(conflictingAttributes, attrNameAndValue{name: "port", value: data.Port})
conflictingAttributes = append(conflictingAttributes, attrNameAndValue{name: "base_dir", value: data.BaseDir})
requiredAttributes = objectStorageAttributes
case OriginTypeUrl:
conflictingAttributes = append(conflictingAttributes, awsAttributes...)
conflictingAttributes = append(conflictingAttributes, objectStorageAttributes...)
requiredAttributes = schemeAndHostAttributes
default:
addUnknownOriginTypeError(&diags, data)

return diags
}

diags.Append(v.doValidate(originType, conflictingAttributes, requiredAttributes)...)

return diags
}

func (OriginConfigValidator) doValidate(
originType string,
conflictingAttributes []attrNameAndValue,
requiredAttributes []attrNameAndValue,
) (diags diag.Diagnostics) {
for _, attribute := range conflictingAttributes {
if attribute.value.IsNull() {
continue
}

diags.Append(
validatordiag.InvalidAttributeCombinationDiagnostic(
path.Root(attribute.name),
fmt.Sprintf(`Attribute "%s" can't be used with Origin type "%s"'`, attribute.name, originType),
),
)
}

for _, attribute := range requiredAttributes {
if !attribute.value.IsNull() {
continue
}

diags.Append(
validatordiag.InvalidAttributeCombinationDiagnostic(
path.Root(attribute.name),
fmt.Sprintf(`Attribute "%s" is required for Origin type "%s"'`, attribute.name, originType),
),
)
}

return diags
}

type attrNameAndValue struct {
name string
value attr.Value
}
37 changes: 37 additions & 0 deletions internal/provider/origin_data_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ type OriginModel struct {
AwsAccessKeyId types.String `tfsdk:"aws_access_key_id"`
AwsAccessKeySecret types.String `tfsdk:"aws_access_key_secret"`
AwsRegion types.String `tfsdk:"aws_region"`
Acl types.String `tfsdk:"acl"`
ClusterId types.String `tfsdk:"cluster_id"`
AccessKeyId types.String `tfsdk:"access_key_id"`
AccessKeySecret types.String `tfsdk:"access_key_secret"`
BucketName types.String `tfsdk:"bucket_name"`
Scheme types.String `tfsdk:"scheme"`
Host types.String `tfsdk:"host"`
Port types.Int64 `tfsdk:"port"`
Expand Down Expand Up @@ -62,6 +67,8 @@ func (d *OriginDataReader) Read(provider StateProvider, diags *diag.Diagnostics,
switch data.Type.ValueString() {
case OriginTypeAws:
ok, statusCode = d.readAws(diags, errMessage, &data)
case OriginTypeObjectStorage:
ok, statusCode = d.readObjectStorage(diags, errMessage, &data)
case OriginTypeUrl:
ok, statusCode = d.readUrl(diags, errMessage, &data)
default:
Expand Down Expand Up @@ -110,6 +117,36 @@ func (d *OriginDataReader) readAws(diags *diag.Diagnostics, message string, data
return true, response.StatusCode()
}

func (d *OriginDataReader) readObjectStorage(diags *diag.Diagnostics, message string, data *OriginModel) (bool, int) {
response, err := d.client.OriginDetailObjectStorageWithResponse(d.ctx, data.Id.ValueString())
if err != nil {
diags.AddError(message, err.Error())

return false, 0
}

if !util.CheckResponse(diags, message, response, response.JSON404, response.JSONDefault) {
return false, response.StatusCode()
}

*data = OriginModel{
Id: data.Id,
Type: types.StringValue(OriginTypeObjectStorage),
Label: types.StringValue(response.JSON200.Label),
Note: util.NullableToStringValue(response.JSON200.Note),
Acl: data.Acl,
ClusterId: data.ClusterId,
AccessKeyId: data.AccessKeyId,
AccessKeySecret: data.AccessKeySecret,
BucketName: types.StringValue(response.JSON200.BucketName),
Scheme: types.StringValue(string(response.JSON200.Scheme)),
Host: types.StringValue(response.JSON200.Host),
Port: util.NullableIntToInt64Value(response.JSON200.Port),
}

return true, response.StatusCode()
}

func (d *OriginDataReader) readUrl(diags *diag.Diagnostics, message string, data *OriginModel) (bool, int) {
response, err := d.client.OriginDetailUrlWithResponse(d.ctx, data.Id.ValueString())
if err != nil {
Expand Down
Loading

0 comments on commit c016e16

Please sign in to comment.