diff --git a/.gitignore b/.gitignore index b1e167f..da3b897 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ dist/ *.env .DS_Store -.python-version \ No newline at end of file +.python-version diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 78fe76f..1240ce4 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -40,7 +40,7 @@ builds: binary: '{{ .ProjectName }}_v{{ .Version }}' archives: - - format: zip + - formats: zip name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}' checksum: diff --git a/build/generator-config.yml b/build/generator-config.yml index 8b37b78..5793437 100644 --- a/build/generator-config.yml +++ b/build/generator-config.yml @@ -164,7 +164,7 @@ resources: core_virtual_machine: read: - path: /core/virtual-machines/{id} + path: /core/virtual-machines/{vm_id} method: GET create: path: /core/virtual-machines diff --git a/internal/genprovider/datasource_core_clusters/core_clusters_data_source_gen.go b/internal/genprovider/datasource_core_clusters/core_clusters_data_source_gen.go index 87638a8..d6b9a56 100644 --- a/internal/genprovider/datasource_core_clusters/core_clusters_data_source_gen.go +++ b/internal/genprovider/datasource_core_clusters/core_clusters_data_source_gen.go @@ -59,6 +59,15 @@ func CoreClustersDataSourceSchema(ctx context.Context) schema.Schema { "ephemeral": schema.Int64Attribute{ Computed: true, }, + "features": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{}, + CustomType: FeaturesType{ + ObjectType: types.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + }, + Computed: true, + }, "gpu": schema.StringAttribute{ Computed: true, }, @@ -68,6 +77,24 @@ func CoreClustersDataSourceSchema(ctx context.Context) schema.Schema { "id": schema.Int64Attribute{ Computed: true, }, + "labels": schema.ListNestedAttribute{ + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "id": schema.Int64Attribute{ + Computed: true, + }, + "label": schema.StringAttribute{ + Computed: true, + }, + }, + CustomType: LabelsType{ + ObjectType: types.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + }, + Computed: true, + }, "name": schema.StringAttribute{ Computed: true, }, @@ -1140,6 +1167,24 @@ func (t NodeFlavorType) ValueFromObject(ctx context.Context, in basetypes.Object fmt.Sprintf(`ephemeral expected to be basetypes.Int64Value, was: %T`, ephemeralAttribute)) } + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return nil, diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + gpuAttribute, ok := attributes["gpu"] if !ok { @@ -1194,6 +1239,24 @@ func (t NodeFlavorType) ValueFromObject(ctx context.Context, in basetypes.Object fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) } + labelsAttribute, ok := attributes["labels"] + + if !ok { + diags.AddError( + "Attribute Missing", + `labels is missing from object`) + + return nil, diags + } + + labelsVal, ok := labelsAttribute.(basetypes.ListValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`labels expected to be basetypes.ListValue, was: %T`, labelsAttribute)) + } + nameAttribute, ok := attributes["name"] if !ok { @@ -1238,9 +1301,11 @@ func (t NodeFlavorType) ValueFromObject(ctx context.Context, in basetypes.Object Cpu: cpuVal, Disk: diskVal, Ephemeral: ephemeralVal, + Features: featuresVal, Gpu: gpuVal, GpuCount: gpuCountVal, Id: idVal, + Labels: labelsVal, Name: nameVal, Ram: ramVal, state: attr.ValueStateKnown, @@ -1364,6 +1429,24 @@ func NewNodeFlavorValue(attributeTypes map[string]attr.Type, attributes map[stri fmt.Sprintf(`ephemeral expected to be basetypes.Int64Value, was: %T`, ephemeralAttribute)) } + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return NewNodeFlavorValueUnknown(), diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + gpuAttribute, ok := attributes["gpu"] if !ok { @@ -1418,6 +1501,24 @@ func NewNodeFlavorValue(attributeTypes map[string]attr.Type, attributes map[stri fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) } + labelsAttribute, ok := attributes["labels"] + + if !ok { + diags.AddError( + "Attribute Missing", + `labels is missing from object`) + + return NewNodeFlavorValueUnknown(), diags + } + + labelsVal, ok := labelsAttribute.(basetypes.ListValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`labels expected to be basetypes.ListValue, was: %T`, labelsAttribute)) + } + nameAttribute, ok := attributes["name"] if !ok { @@ -1462,9 +1563,11 @@ func NewNodeFlavorValue(attributeTypes map[string]attr.Type, attributes map[stri Cpu: cpuVal, Disk: diskVal, Ephemeral: ephemeralVal, + Features: featuresVal, Gpu: gpuVal, GpuCount: gpuCountVal, Id: idVal, + Labels: labelsVal, Name: nameVal, Ram: ramVal, state: attr.ValueStateKnown, @@ -1542,16 +1645,18 @@ type NodeFlavorValue struct { Cpu basetypes.Int64Value `tfsdk:"cpu"` Disk basetypes.Int64Value `tfsdk:"disk"` Ephemeral basetypes.Int64Value `tfsdk:"ephemeral"` + Features basetypes.ObjectValue `tfsdk:"features"` Gpu basetypes.StringValue `tfsdk:"gpu"` GpuCount basetypes.Int64Value `tfsdk:"gpu_count"` Id basetypes.Int64Value `tfsdk:"id"` + Labels basetypes.ListValue `tfsdk:"labels"` Name basetypes.StringValue `tfsdk:"name"` Ram basetypes.NumberValue `tfsdk:"ram"` state attr.ValueState } func (v NodeFlavorValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { - attrTypes := make(map[string]tftypes.Type, 8) + attrTypes := make(map[string]tftypes.Type, 10) var val tftypes.Value var err error @@ -1559,9 +1664,15 @@ func (v NodeFlavorValue) ToTerraformValue(ctx context.Context) (tftypes.Value, e attrTypes["cpu"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["disk"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["ephemeral"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["features"] = basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }.TerraformType(ctx) attrTypes["gpu"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["gpu_count"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["labels"] = basetypes.ListType{ + ElemType: LabelsValue{}.Type(ctx), + }.TerraformType(ctx) attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["ram"] = basetypes.NumberType{}.TerraformType(ctx) @@ -1569,7 +1680,7 @@ func (v NodeFlavorValue) ToTerraformValue(ctx context.Context) (tftypes.Value, e switch v.state { case attr.ValueStateKnown: - vals := make(map[string]tftypes.Value, 8) + vals := make(map[string]tftypes.Value, 10) val, err = v.Cpu.ToTerraformValue(ctx) @@ -1595,6 +1706,14 @@ func (v NodeFlavorValue) ToTerraformValue(ctx context.Context) (tftypes.Value, e vals["ephemeral"] = val + val, err = v.Features.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["features"] = val + val, err = v.Gpu.ToTerraformValue(ctx) if err != nil { @@ -1619,6 +1738,14 @@ func (v NodeFlavorValue) ToTerraformValue(ctx context.Context) (tftypes.Value, e vals["id"] = val + val, err = v.Labels.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["labels"] = val + val, err = v.Name.ToTerraformValue(ctx) if err != nil { @@ -1664,15 +1791,71 @@ func (v NodeFlavorValue) String() string { func (v NodeFlavorValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { var diags diag.Diagnostics + var features basetypes.ObjectValue + + if v.Features.IsNull() { + features = types.ObjectNull( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if v.Features.IsUnknown() { + features = types.ObjectUnknown( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if !v.Features.IsNull() && !v.Features.IsUnknown() { + features = types.ObjectValueMust( + FeaturesValue{}.AttributeTypes(ctx), + v.Features.Attributes(), + ) + } + + labels := types.ListValueMust( + LabelsType{ + basetypes.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + v.Labels.Elements(), + ) + + if v.Labels.IsNull() { + labels = types.ListNull( + LabelsType{ + basetypes.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + ) + } + + if v.Labels.IsUnknown() { + labels = types.ListUnknown( + LabelsType{ + basetypes.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + ) + } + attributeTypes := map[string]attr.Type{ "cpu": basetypes.Int64Type{}, "disk": basetypes.Int64Type{}, "ephemeral": basetypes.Int64Type{}, + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, "gpu": basetypes.StringType{}, "gpu_count": basetypes.Int64Type{}, "id": basetypes.Int64Type{}, - "name": basetypes.StringType{}, - "ram": basetypes.NumberType{}, + "labels": basetypes.ListType{ + ElemType: LabelsValue{}.Type(ctx), + }, + "name": basetypes.StringType{}, + "ram": basetypes.NumberType{}, } if v.IsNull() { @@ -1689,9 +1872,11 @@ func (v NodeFlavorValue) ToObjectValue(ctx context.Context) (basetypes.ObjectVal "cpu": v.Cpu, "disk": v.Disk, "ephemeral": v.Ephemeral, + "features": features, "gpu": v.Gpu, "gpu_count": v.GpuCount, "id": v.Id, + "labels": labels, "name": v.Name, "ram": v.Ram, }) @@ -1726,6 +1911,10 @@ func (v NodeFlavorValue) Equal(o attr.Value) bool { return false } + if !v.Features.Equal(other.Features) { + return false + } + if !v.Gpu.Equal(other.Gpu) { return false } @@ -1738,6 +1927,10 @@ func (v NodeFlavorValue) Equal(o attr.Value) bool { return false } + if !v.Labels.Equal(other.Labels) { + return false + } + if !v.Name.Equal(other.Name) { return false } @@ -1762,10 +1955,655 @@ func (v NodeFlavorValue) AttributeTypes(ctx context.Context) map[string]attr.Typ "cpu": basetypes.Int64Type{}, "disk": basetypes.Int64Type{}, "ephemeral": basetypes.Int64Type{}, + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, "gpu": basetypes.StringType{}, "gpu_count": basetypes.Int64Type{}, "id": basetypes.Int64Type{}, - "name": basetypes.StringType{}, - "ram": basetypes.NumberType{}, + "labels": basetypes.ListType{ + ElemType: LabelsValue{}.Type(ctx), + }, + "name": basetypes.StringType{}, + "ram": basetypes.NumberType{}, + } +} + +var _ basetypes.ObjectTypable = FeaturesType{} + +type FeaturesType struct { + basetypes.ObjectType +} + +func (t FeaturesType) Equal(o attr.Type) bool { + other, ok := o.(FeaturesType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t FeaturesType) String() string { + return "FeaturesType" +} + +func (t FeaturesType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + if diags.HasError() { + return nil, diags + } + + return FeaturesValue{ + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueNull() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateNull, + } +} + +func NewFeaturesValueUnknown() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateUnknown, + } +} + +func NewFeaturesValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (FeaturesValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing FeaturesValue Attribute Value", + "While creating a FeaturesValue value, a missing attribute value was detected. "+ + "A FeaturesValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid FeaturesValue Attribute Type", + "While creating a FeaturesValue value, an invalid attribute value was detected. "+ + "A FeaturesValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra FeaturesValue Attribute Value", + "While creating a FeaturesValue value, an extra attribute value was detected. "+ + "A FeaturesValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra FeaturesValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + return FeaturesValue{ + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) FeaturesValue { + object, diags := NewFeaturesValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewFeaturesValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t FeaturesType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewFeaturesValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewFeaturesValueUnknown(), nil + } + + if in.IsNull() { + return NewFeaturesValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewFeaturesValueMust(FeaturesValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t FeaturesType) ValueType(ctx context.Context) attr.Value { + return FeaturesValue{} +} + +var _ basetypes.ObjectValuable = FeaturesValue{} + +type FeaturesValue struct { + state attr.ValueState +} + +func (v FeaturesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 0) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 0) + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v FeaturesValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v FeaturesValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v FeaturesValue) String() string { + return "FeaturesValue" +} + +func (v FeaturesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + attributeTypes := map[string]attr.Type{} + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{}) + + return objVal, diags +} + +func (v FeaturesValue) Equal(o attr.Value) bool { + other, ok := o.(FeaturesValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + return true +} + +func (v FeaturesValue) Type(ctx context.Context) attr.Type { + return FeaturesType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v FeaturesValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{} +} + +var _ basetypes.ObjectTypable = LabelsType{} + +type LabelsType struct { + basetypes.ObjectType +} + +func (t LabelsType) Equal(o attr.Type) bool { + other, ok := o.(LabelsType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t LabelsType) String() string { + return "LabelsType" +} + +func (t LabelsType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + attributes := in.Attributes() + + idAttribute, ok := attributes["id"] + + if !ok { + diags.AddError( + "Attribute Missing", + `id is missing from object`) + + return nil, diags + } + + idVal, ok := idAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) + } + + labelAttribute, ok := attributes["label"] + + if !ok { + diags.AddError( + "Attribute Missing", + `label is missing from object`) + + return nil, diags + } + + labelVal, ok := labelAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`label expected to be basetypes.StringValue, was: %T`, labelAttribute)) + } + + if diags.HasError() { + return nil, diags + } + + return LabelsValue{ + Id: idVal, + Label: labelVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewLabelsValueNull() LabelsValue { + return LabelsValue{ + state: attr.ValueStateNull, + } +} + +func NewLabelsValueUnknown() LabelsValue { + return LabelsValue{ + state: attr.ValueStateUnknown, + } +} + +func NewLabelsValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (LabelsValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing LabelsValue Attribute Value", + "While creating a LabelsValue value, a missing attribute value was detected. "+ + "A LabelsValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("LabelsValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid LabelsValue Attribute Type", + "While creating a LabelsValue value, an invalid attribute value was detected. "+ + "A LabelsValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("LabelsValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("LabelsValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra LabelsValue Attribute Value", + "While creating a LabelsValue value, an extra attribute value was detected. "+ + "A LabelsValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra LabelsValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewLabelsValueUnknown(), diags + } + + idAttribute, ok := attributes["id"] + + if !ok { + diags.AddError( + "Attribute Missing", + `id is missing from object`) + + return NewLabelsValueUnknown(), diags + } + + idVal, ok := idAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) + } + + labelAttribute, ok := attributes["label"] + + if !ok { + diags.AddError( + "Attribute Missing", + `label is missing from object`) + + return NewLabelsValueUnknown(), diags + } + + labelVal, ok := labelAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`label expected to be basetypes.StringValue, was: %T`, labelAttribute)) + } + + if diags.HasError() { + return NewLabelsValueUnknown(), diags + } + + return LabelsValue{ + Id: idVal, + Label: labelVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewLabelsValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) LabelsValue { + object, diags := NewLabelsValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewLabelsValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t LabelsType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewLabelsValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewLabelsValueUnknown(), nil + } + + if in.IsNull() { + return NewLabelsValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewLabelsValueMust(LabelsValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t LabelsType) ValueType(ctx context.Context) attr.Value { + return LabelsValue{} +} + +var _ basetypes.ObjectValuable = LabelsValue{} + +type LabelsValue struct { + Id basetypes.Int64Value `tfsdk:"id"` + Label basetypes.StringValue `tfsdk:"label"` + state attr.ValueState +} + +func (v LabelsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 2) + + var val tftypes.Value + var err error + + attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["label"] = basetypes.StringType{}.TerraformType(ctx) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 2) + + val, err = v.Id.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["id"] = val + + val, err = v.Label.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["label"] = val + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v LabelsValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v LabelsValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v LabelsValue) String() string { + return "LabelsValue" +} + +func (v LabelsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + attributeTypes := map[string]attr.Type{ + "id": basetypes.Int64Type{}, + "label": basetypes.StringType{}, + } + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{ + "id": v.Id, + "label": v.Label, + }) + + return objVal, diags +} + +func (v LabelsValue) Equal(o attr.Value) bool { + other, ok := o.(LabelsValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + if !v.Id.Equal(other.Id) { + return false + } + + if !v.Label.Equal(other.Label) { + return false + } + + return true +} + +func (v LabelsValue) Type(ctx context.Context) attr.Type { + return LabelsType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v LabelsValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{ + "id": basetypes.Int64Type{}, + "label": basetypes.StringType{}, } } diff --git a/internal/genprovider/datasource_core_environment/core_environment_data_source_gen.go b/internal/genprovider/datasource_core_environment/core_environment_data_source_gen.go index fad0b89..9c3f14b 100644 --- a/internal/genprovider/datasource_core_environment/core_environment_data_source_gen.go +++ b/internal/genprovider/datasource_core_environment/core_environment_data_source_gen.go @@ -4,7 +4,13 @@ package datasource_core_environment import ( "context" + "fmt" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "strings" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" ) @@ -15,6 +21,22 @@ func CoreEnvironmentDataSourceSchema(ctx context.Context) schema.Schema { "created_at": schema.StringAttribute{ Computed: true, }, + "features": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "green_status": schema.StringAttribute{ + Computed: true, + }, + "network_optimised": schema.BoolAttribute{ + Computed: true, + }, + }, + CustomType: FeaturesType{ + ObjectType: types.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + }, + Computed: true, + }, "id": schema.Int64Attribute{ Required: true, }, @@ -29,8 +51,388 @@ func CoreEnvironmentDataSourceSchema(ctx context.Context) schema.Schema { } type CoreEnvironmentModel struct { - CreatedAt types.String `tfsdk:"created_at"` - Id types.Int64 `tfsdk:"id"` - Name types.String `tfsdk:"name"` - Region types.String `tfsdk:"region"` + CreatedAt types.String `tfsdk:"created_at"` + Features FeaturesValue `tfsdk:"features"` + Id types.Int64 `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Region types.String `tfsdk:"region"` +} + +var _ basetypes.ObjectTypable = FeaturesType{} + +type FeaturesType struct { + basetypes.ObjectType +} + +func (t FeaturesType) Equal(o attr.Type) bool { + other, ok := o.(FeaturesType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t FeaturesType) String() string { + return "FeaturesType" +} + +func (t FeaturesType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + attributes := in.Attributes() + + greenStatusAttribute, ok := attributes["green_status"] + + if !ok { + diags.AddError( + "Attribute Missing", + `green_status is missing from object`) + + return nil, diags + } + + greenStatusVal, ok := greenStatusAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`green_status expected to be basetypes.StringValue, was: %T`, greenStatusAttribute)) + } + + networkOptimisedAttribute, ok := attributes["network_optimised"] + + if !ok { + diags.AddError( + "Attribute Missing", + `network_optimised is missing from object`) + + return nil, diags + } + + networkOptimisedVal, ok := networkOptimisedAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`network_optimised expected to be basetypes.BoolValue, was: %T`, networkOptimisedAttribute)) + } + + if diags.HasError() { + return nil, diags + } + + return FeaturesValue{ + GreenStatus: greenStatusVal, + NetworkOptimised: networkOptimisedVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueNull() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateNull, + } +} + +func NewFeaturesValueUnknown() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateUnknown, + } +} + +func NewFeaturesValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (FeaturesValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing FeaturesValue Attribute Value", + "While creating a FeaturesValue value, a missing attribute value was detected. "+ + "A FeaturesValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid FeaturesValue Attribute Type", + "While creating a FeaturesValue value, an invalid attribute value was detected. "+ + "A FeaturesValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra FeaturesValue Attribute Value", + "While creating a FeaturesValue value, an extra attribute value was detected. "+ + "A FeaturesValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra FeaturesValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + greenStatusAttribute, ok := attributes["green_status"] + + if !ok { + diags.AddError( + "Attribute Missing", + `green_status is missing from object`) + + return NewFeaturesValueUnknown(), diags + } + + greenStatusVal, ok := greenStatusAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`green_status expected to be basetypes.StringValue, was: %T`, greenStatusAttribute)) + } + + networkOptimisedAttribute, ok := attributes["network_optimised"] + + if !ok { + diags.AddError( + "Attribute Missing", + `network_optimised is missing from object`) + + return NewFeaturesValueUnknown(), diags + } + + networkOptimisedVal, ok := networkOptimisedAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`network_optimised expected to be basetypes.BoolValue, was: %T`, networkOptimisedAttribute)) + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + return FeaturesValue{ + GreenStatus: greenStatusVal, + NetworkOptimised: networkOptimisedVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) FeaturesValue { + object, diags := NewFeaturesValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewFeaturesValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t FeaturesType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewFeaturesValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewFeaturesValueUnknown(), nil + } + + if in.IsNull() { + return NewFeaturesValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewFeaturesValueMust(FeaturesValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t FeaturesType) ValueType(ctx context.Context) attr.Value { + return FeaturesValue{} +} + +var _ basetypes.ObjectValuable = FeaturesValue{} + +type FeaturesValue struct { + GreenStatus basetypes.StringValue `tfsdk:"green_status"` + NetworkOptimised basetypes.BoolValue `tfsdk:"network_optimised"` + state attr.ValueState +} + +func (v FeaturesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 2) + + var val tftypes.Value + var err error + + attrTypes["green_status"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["network_optimised"] = basetypes.BoolType{}.TerraformType(ctx) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 2) + + val, err = v.GreenStatus.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["green_status"] = val + + val, err = v.NetworkOptimised.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["network_optimised"] = val + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v FeaturesValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v FeaturesValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v FeaturesValue) String() string { + return "FeaturesValue" +} + +func (v FeaturesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + attributeTypes := map[string]attr.Type{ + "green_status": basetypes.StringType{}, + "network_optimised": basetypes.BoolType{}, + } + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{ + "green_status": v.GreenStatus, + "network_optimised": v.NetworkOptimised, + }) + + return objVal, diags +} + +func (v FeaturesValue) Equal(o attr.Value) bool { + other, ok := o.(FeaturesValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + if !v.GreenStatus.Equal(other.GreenStatus) { + return false + } + + if !v.NetworkOptimised.Equal(other.NetworkOptimised) { + return false + } + + return true +} + +func (v FeaturesValue) Type(ctx context.Context) attr.Type { + return FeaturesType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v FeaturesValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{ + "green_status": basetypes.StringType{}, + "network_optimised": basetypes.BoolType{}, + } } diff --git a/internal/genprovider/datasource_core_environments/core_environments_data_source_gen.go b/internal/genprovider/datasource_core_environments/core_environments_data_source_gen.go index 7498afa..e16367c 100644 --- a/internal/genprovider/datasource_core_environments/core_environments_data_source_gen.go +++ b/internal/genprovider/datasource_core_environments/core_environments_data_source_gen.go @@ -24,6 +24,22 @@ func CoreEnvironmentsDataSourceSchema(ctx context.Context) schema.Schema { "created_at": schema.StringAttribute{ Computed: true, }, + "features": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "green_status": schema.StringAttribute{ + Computed: true, + }, + "network_optimised": schema.BoolAttribute{ + Computed: true, + }, + }, + CustomType: FeaturesType{ + ObjectType: types.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + }, + Computed: true, + }, "id": schema.Int64Attribute{ Computed: true, }, @@ -114,6 +130,24 @@ func (t CoreEnvironmentsType) ValueFromObject(ctx context.Context, in basetypes. fmt.Sprintf(`created_at expected to be basetypes.StringValue, was: %T`, createdAtAttribute)) } + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return nil, diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + idAttribute, ok := attributes["id"] if !ok { @@ -174,6 +208,7 @@ func (t CoreEnvironmentsType) ValueFromObject(ctx context.Context, in basetypes. return CoreEnvironmentsValue{ CreatedAt: createdAtVal, + Features: featuresVal, Id: idVal, Name: nameVal, Region: regionVal, @@ -262,6 +297,24 @@ func NewCoreEnvironmentsValue(attributeTypes map[string]attr.Type, attributes ma fmt.Sprintf(`created_at expected to be basetypes.StringValue, was: %T`, createdAtAttribute)) } + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return NewCoreEnvironmentsValueUnknown(), diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + idAttribute, ok := attributes["id"] if !ok { @@ -322,6 +375,7 @@ func NewCoreEnvironmentsValue(attributeTypes map[string]attr.Type, attributes ma return CoreEnvironmentsValue{ CreatedAt: createdAtVal, + Features: featuresVal, Id: idVal, Name: nameVal, Region: regionVal, @@ -398,6 +452,7 @@ var _ basetypes.ObjectValuable = CoreEnvironmentsValue{} type CoreEnvironmentsValue struct { CreatedAt basetypes.StringValue `tfsdk:"created_at"` + Features basetypes.ObjectValue `tfsdk:"features"` Id basetypes.Int64Value `tfsdk:"id"` Name basetypes.StringValue `tfsdk:"name"` Region basetypes.StringValue `tfsdk:"region"` @@ -405,12 +460,15 @@ type CoreEnvironmentsValue struct { } func (v CoreEnvironmentsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { - attrTypes := make(map[string]tftypes.Type, 4) + attrTypes := make(map[string]tftypes.Type, 5) var val tftypes.Value var err error attrTypes["created_at"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["features"] = basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }.TerraformType(ctx) attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["region"] = basetypes.StringType{}.TerraformType(ctx) @@ -419,7 +477,7 @@ func (v CoreEnvironmentsValue) ToTerraformValue(ctx context.Context) (tftypes.Va switch v.state { case attr.ValueStateKnown: - vals := make(map[string]tftypes.Value, 4) + vals := make(map[string]tftypes.Value, 5) val, err = v.CreatedAt.ToTerraformValue(ctx) @@ -429,6 +487,14 @@ func (v CoreEnvironmentsValue) ToTerraformValue(ctx context.Context) (tftypes.Va vals["created_at"] = val + val, err = v.Features.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["features"] = val + val, err = v.Id.ToTerraformValue(ctx) if err != nil { @@ -482,11 +548,35 @@ func (v CoreEnvironmentsValue) String() string { func (v CoreEnvironmentsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { var diags diag.Diagnostics + var features basetypes.ObjectValue + + if v.Features.IsNull() { + features = types.ObjectNull( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if v.Features.IsUnknown() { + features = types.ObjectUnknown( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if !v.Features.IsNull() && !v.Features.IsUnknown() { + features = types.ObjectValueMust( + FeaturesValue{}.AttributeTypes(ctx), + v.Features.Attributes(), + ) + } + attributeTypes := map[string]attr.Type{ "created_at": basetypes.StringType{}, - "id": basetypes.Int64Type{}, - "name": basetypes.StringType{}, - "region": basetypes.StringType{}, + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + "id": basetypes.Int64Type{}, + "name": basetypes.StringType{}, + "region": basetypes.StringType{}, } if v.IsNull() { @@ -501,6 +591,7 @@ func (v CoreEnvironmentsValue) ToObjectValue(ctx context.Context) (basetypes.Obj attributeTypes, map[string]attr.Value{ "created_at": v.CreatedAt, + "features": features, "id": v.Id, "name": v.Name, "region": v.Region, @@ -528,6 +619,10 @@ func (v CoreEnvironmentsValue) Equal(o attr.Value) bool { return false } + if !v.Features.Equal(other.Features) { + return false + } + if !v.Id.Equal(other.Id) { return false } @@ -554,8 +649,390 @@ func (v CoreEnvironmentsValue) Type(ctx context.Context) attr.Type { func (v CoreEnvironmentsValue) AttributeTypes(ctx context.Context) map[string]attr.Type { return map[string]attr.Type{ "created_at": basetypes.StringType{}, - "id": basetypes.Int64Type{}, - "name": basetypes.StringType{}, - "region": basetypes.StringType{}, + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + "id": basetypes.Int64Type{}, + "name": basetypes.StringType{}, + "region": basetypes.StringType{}, + } +} + +var _ basetypes.ObjectTypable = FeaturesType{} + +type FeaturesType struct { + basetypes.ObjectType +} + +func (t FeaturesType) Equal(o attr.Type) bool { + other, ok := o.(FeaturesType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t FeaturesType) String() string { + return "FeaturesType" +} + +func (t FeaturesType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + attributes := in.Attributes() + + greenStatusAttribute, ok := attributes["green_status"] + + if !ok { + diags.AddError( + "Attribute Missing", + `green_status is missing from object`) + + return nil, diags + } + + greenStatusVal, ok := greenStatusAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`green_status expected to be basetypes.StringValue, was: %T`, greenStatusAttribute)) + } + + networkOptimisedAttribute, ok := attributes["network_optimised"] + + if !ok { + diags.AddError( + "Attribute Missing", + `network_optimised is missing from object`) + + return nil, diags + } + + networkOptimisedVal, ok := networkOptimisedAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`network_optimised expected to be basetypes.BoolValue, was: %T`, networkOptimisedAttribute)) + } + + if diags.HasError() { + return nil, diags + } + + return FeaturesValue{ + GreenStatus: greenStatusVal, + NetworkOptimised: networkOptimisedVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueNull() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateNull, + } +} + +func NewFeaturesValueUnknown() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateUnknown, + } +} + +func NewFeaturesValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (FeaturesValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing FeaturesValue Attribute Value", + "While creating a FeaturesValue value, a missing attribute value was detected. "+ + "A FeaturesValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid FeaturesValue Attribute Type", + "While creating a FeaturesValue value, an invalid attribute value was detected. "+ + "A FeaturesValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra FeaturesValue Attribute Value", + "While creating a FeaturesValue value, an extra attribute value was detected. "+ + "A FeaturesValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra FeaturesValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + greenStatusAttribute, ok := attributes["green_status"] + + if !ok { + diags.AddError( + "Attribute Missing", + `green_status is missing from object`) + + return NewFeaturesValueUnknown(), diags + } + + greenStatusVal, ok := greenStatusAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`green_status expected to be basetypes.StringValue, was: %T`, greenStatusAttribute)) + } + + networkOptimisedAttribute, ok := attributes["network_optimised"] + + if !ok { + diags.AddError( + "Attribute Missing", + `network_optimised is missing from object`) + + return NewFeaturesValueUnknown(), diags + } + + networkOptimisedVal, ok := networkOptimisedAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`network_optimised expected to be basetypes.BoolValue, was: %T`, networkOptimisedAttribute)) + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + return FeaturesValue{ + GreenStatus: greenStatusVal, + NetworkOptimised: networkOptimisedVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) FeaturesValue { + object, diags := NewFeaturesValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewFeaturesValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t FeaturesType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewFeaturesValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewFeaturesValueUnknown(), nil + } + + if in.IsNull() { + return NewFeaturesValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewFeaturesValueMust(FeaturesValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t FeaturesType) ValueType(ctx context.Context) attr.Value { + return FeaturesValue{} +} + +var _ basetypes.ObjectValuable = FeaturesValue{} + +type FeaturesValue struct { + GreenStatus basetypes.StringValue `tfsdk:"green_status"` + NetworkOptimised basetypes.BoolValue `tfsdk:"network_optimised"` + state attr.ValueState +} + +func (v FeaturesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 2) + + var val tftypes.Value + var err error + + attrTypes["green_status"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["network_optimised"] = basetypes.BoolType{}.TerraformType(ctx) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 2) + + val, err = v.GreenStatus.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["green_status"] = val + + val, err = v.NetworkOptimised.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["network_optimised"] = val + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v FeaturesValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v FeaturesValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v FeaturesValue) String() string { + return "FeaturesValue" +} + +func (v FeaturesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + attributeTypes := map[string]attr.Type{ + "green_status": basetypes.StringType{}, + "network_optimised": basetypes.BoolType{}, + } + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{ + "green_status": v.GreenStatus, + "network_optimised": v.NetworkOptimised, + }) + + return objVal, diags +} + +func (v FeaturesValue) Equal(o attr.Value) bool { + other, ok := o.(FeaturesValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + if !v.GreenStatus.Equal(other.GreenStatus) { + return false + } + + if !v.NetworkOptimised.Equal(other.NetworkOptimised) { + return false + } + + return true +} + +func (v FeaturesValue) Type(ctx context.Context) attr.Type { + return FeaturesType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v FeaturesValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{ + "green_status": basetypes.StringType{}, + "network_optimised": basetypes.BoolType{}, } } diff --git a/internal/genprovider/datasource_core_flavors/core_flavors_data_source_gen.go b/internal/genprovider/datasource_core_flavors/core_flavors_data_source_gen.go index 5af3836..cd1885f 100644 --- a/internal/genprovider/datasource_core_flavors/core_flavors_data_source_gen.go +++ b/internal/genprovider/datasource_core_flavors/core_flavors_data_source_gen.go @@ -48,6 +48,24 @@ func CoreFlavorsDataSourceSchema(ctx context.Context) schema.Schema { "id": schema.Int64Attribute{ Computed: true, }, + "labels": schema.ListNestedAttribute{ + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "id": schema.Int64Attribute{ + Computed: true, + }, + "label": schema.StringAttribute{ + Computed: true, + }, + }, + CustomType: LabelsType{ + ObjectType: types.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + }, + Computed: true, + }, "name": schema.StringAttribute{ Computed: true, }, @@ -737,6 +755,24 @@ func (t FlavorsType) ValueFromObject(ctx context.Context, in basetypes.ObjectVal fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) } + labelsAttribute, ok := attributes["labels"] + + if !ok { + diags.AddError( + "Attribute Missing", + `labels is missing from object`) + + return nil, diags + } + + labelsVal, ok := labelsAttribute.(basetypes.ListValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`labels expected to be basetypes.ListValue, was: %T`, labelsAttribute)) + } + nameAttribute, ok := attributes["name"] if !ok { @@ -822,6 +858,7 @@ func (t FlavorsType) ValueFromObject(ctx context.Context, in basetypes.ObjectVal Gpu: gpuVal, GpuCount: gpuCountVal, Id: idVal, + Labels: labelsVal, Name: nameVal, Ram: ramVal, RegionName: regionNameVal, @@ -1037,6 +1074,24 @@ func NewFlavorsValue(attributeTypes map[string]attr.Type, attributes map[string] fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) } + labelsAttribute, ok := attributes["labels"] + + if !ok { + diags.AddError( + "Attribute Missing", + `labels is missing from object`) + + return NewFlavorsValueUnknown(), diags + } + + labelsVal, ok := labelsAttribute.(basetypes.ListValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`labels expected to be basetypes.ListValue, was: %T`, labelsAttribute)) + } + nameAttribute, ok := attributes["name"] if !ok { @@ -1122,6 +1177,7 @@ func NewFlavorsValue(attributeTypes map[string]attr.Type, attributes map[string] Gpu: gpuVal, GpuCount: gpuCountVal, Id: idVal, + Labels: labelsVal, Name: nameVal, Ram: ramVal, RegionName: regionNameVal, @@ -1206,6 +1262,7 @@ type FlavorsValue struct { Gpu basetypes.StringValue `tfsdk:"gpu"` GpuCount basetypes.Int64Value `tfsdk:"gpu_count"` Id basetypes.Int64Value `tfsdk:"id"` + Labels basetypes.ListValue `tfsdk:"labels"` Name basetypes.StringValue `tfsdk:"name"` Ram basetypes.NumberValue `tfsdk:"ram"` RegionName basetypes.StringValue `tfsdk:"region_name"` @@ -1214,7 +1271,7 @@ type FlavorsValue struct { } func (v FlavorsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { - attrTypes := make(map[string]tftypes.Type, 12) + attrTypes := make(map[string]tftypes.Type, 13) var val tftypes.Value var err error @@ -1227,6 +1284,9 @@ func (v FlavorsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, erro attrTypes["gpu"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["gpu_count"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["labels"] = basetypes.ListType{ + ElemType: LabelsValue{}.Type(ctx), + }.TerraformType(ctx) attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["ram"] = basetypes.NumberType{}.TerraformType(ctx) attrTypes["region_name"] = basetypes.StringType{}.TerraformType(ctx) @@ -1236,7 +1296,7 @@ func (v FlavorsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, erro switch v.state { case attr.ValueStateKnown: - vals := make(map[string]tftypes.Value, 12) + vals := make(map[string]tftypes.Value, 13) val, err = v.Cpu.ToTerraformValue(ctx) @@ -1302,6 +1362,14 @@ func (v FlavorsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, erro vals["id"] = val + val, err = v.Labels.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["labels"] = val + val, err = v.Name.ToTerraformValue(ctx) if err != nil { @@ -1363,15 +1431,47 @@ func (v FlavorsValue) String() string { func (v FlavorsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { var diags diag.Diagnostics + labels := types.ListValueMust( + LabelsType{ + basetypes.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + v.Labels.Elements(), + ) + + if v.Labels.IsNull() { + labels = types.ListNull( + LabelsType{ + basetypes.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + ) + } + + if v.Labels.IsUnknown() { + labels = types.ListUnknown( + LabelsType{ + basetypes.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + ) + } + attributeTypes := map[string]attr.Type{ - "cpu": basetypes.Int64Type{}, - "created_at": basetypes.StringType{}, - "disk": basetypes.Int64Type{}, - "display_name": basetypes.StringType{}, - "ephemeral": basetypes.Int64Type{}, - "gpu": basetypes.StringType{}, - "gpu_count": basetypes.Int64Type{}, - "id": basetypes.Int64Type{}, + "cpu": basetypes.Int64Type{}, + "created_at": basetypes.StringType{}, + "disk": basetypes.Int64Type{}, + "display_name": basetypes.StringType{}, + "ephemeral": basetypes.Int64Type{}, + "gpu": basetypes.StringType{}, + "gpu_count": basetypes.Int64Type{}, + "id": basetypes.Int64Type{}, + "labels": basetypes.ListType{ + ElemType: LabelsValue{}.Type(ctx), + }, "name": basetypes.StringType{}, "ram": basetypes.NumberType{}, "region_name": basetypes.StringType{}, @@ -1397,6 +1497,7 @@ func (v FlavorsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, "gpu": v.Gpu, "gpu_count": v.GpuCount, "id": v.Id, + "labels": labels, "name": v.Name, "ram": v.Ram, "region_name": v.RegionName, @@ -1453,6 +1554,10 @@ func (v FlavorsValue) Equal(o attr.Value) bool { return false } + if !v.Labels.Equal(other.Labels) { + return false + } + if !v.Name.Equal(other.Name) { return false } @@ -1482,17 +1587,399 @@ func (v FlavorsValue) Type(ctx context.Context) attr.Type { func (v FlavorsValue) AttributeTypes(ctx context.Context) map[string]attr.Type { return map[string]attr.Type{ - "cpu": basetypes.Int64Type{}, - "created_at": basetypes.StringType{}, - "disk": basetypes.Int64Type{}, - "display_name": basetypes.StringType{}, - "ephemeral": basetypes.Int64Type{}, - "gpu": basetypes.StringType{}, - "gpu_count": basetypes.Int64Type{}, - "id": basetypes.Int64Type{}, + "cpu": basetypes.Int64Type{}, + "created_at": basetypes.StringType{}, + "disk": basetypes.Int64Type{}, + "display_name": basetypes.StringType{}, + "ephemeral": basetypes.Int64Type{}, + "gpu": basetypes.StringType{}, + "gpu_count": basetypes.Int64Type{}, + "id": basetypes.Int64Type{}, + "labels": basetypes.ListType{ + ElemType: LabelsValue{}.Type(ctx), + }, "name": basetypes.StringType{}, "ram": basetypes.NumberType{}, "region_name": basetypes.StringType{}, "stock_available": basetypes.BoolType{}, } } + +var _ basetypes.ObjectTypable = LabelsType{} + +type LabelsType struct { + basetypes.ObjectType +} + +func (t LabelsType) Equal(o attr.Type) bool { + other, ok := o.(LabelsType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t LabelsType) String() string { + return "LabelsType" +} + +func (t LabelsType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + attributes := in.Attributes() + + idAttribute, ok := attributes["id"] + + if !ok { + diags.AddError( + "Attribute Missing", + `id is missing from object`) + + return nil, diags + } + + idVal, ok := idAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) + } + + labelAttribute, ok := attributes["label"] + + if !ok { + diags.AddError( + "Attribute Missing", + `label is missing from object`) + + return nil, diags + } + + labelVal, ok := labelAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`label expected to be basetypes.StringValue, was: %T`, labelAttribute)) + } + + if diags.HasError() { + return nil, diags + } + + return LabelsValue{ + Id: idVal, + Label: labelVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewLabelsValueNull() LabelsValue { + return LabelsValue{ + state: attr.ValueStateNull, + } +} + +func NewLabelsValueUnknown() LabelsValue { + return LabelsValue{ + state: attr.ValueStateUnknown, + } +} + +func NewLabelsValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (LabelsValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing LabelsValue Attribute Value", + "While creating a LabelsValue value, a missing attribute value was detected. "+ + "A LabelsValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("LabelsValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid LabelsValue Attribute Type", + "While creating a LabelsValue value, an invalid attribute value was detected. "+ + "A LabelsValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("LabelsValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("LabelsValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra LabelsValue Attribute Value", + "While creating a LabelsValue value, an extra attribute value was detected. "+ + "A LabelsValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra LabelsValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewLabelsValueUnknown(), diags + } + + idAttribute, ok := attributes["id"] + + if !ok { + diags.AddError( + "Attribute Missing", + `id is missing from object`) + + return NewLabelsValueUnknown(), diags + } + + idVal, ok := idAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) + } + + labelAttribute, ok := attributes["label"] + + if !ok { + diags.AddError( + "Attribute Missing", + `label is missing from object`) + + return NewLabelsValueUnknown(), diags + } + + labelVal, ok := labelAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`label expected to be basetypes.StringValue, was: %T`, labelAttribute)) + } + + if diags.HasError() { + return NewLabelsValueUnknown(), diags + } + + return LabelsValue{ + Id: idVal, + Label: labelVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewLabelsValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) LabelsValue { + object, diags := NewLabelsValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewLabelsValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t LabelsType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewLabelsValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewLabelsValueUnknown(), nil + } + + if in.IsNull() { + return NewLabelsValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewLabelsValueMust(LabelsValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t LabelsType) ValueType(ctx context.Context) attr.Value { + return LabelsValue{} +} + +var _ basetypes.ObjectValuable = LabelsValue{} + +type LabelsValue struct { + Id basetypes.Int64Value `tfsdk:"id"` + Label basetypes.StringValue `tfsdk:"label"` + state attr.ValueState +} + +func (v LabelsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 2) + + var val tftypes.Value + var err error + + attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["label"] = basetypes.StringType{}.TerraformType(ctx) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 2) + + val, err = v.Id.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["id"] = val + + val, err = v.Label.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["label"] = val + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v LabelsValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v LabelsValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v LabelsValue) String() string { + return "LabelsValue" +} + +func (v LabelsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + attributeTypes := map[string]attr.Type{ + "id": basetypes.Int64Type{}, + "label": basetypes.StringType{}, + } + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{ + "id": v.Id, + "label": v.Label, + }) + + return objVal, diags +} + +func (v LabelsValue) Equal(o attr.Value) bool { + other, ok := o.(LabelsValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + if !v.Id.Equal(other.Id) { + return false + } + + if !v.Label.Equal(other.Label) { + return false + } + + return true +} + +func (v LabelsValue) Type(ctx context.Context) attr.Type { + return LabelsType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v LabelsValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{ + "id": basetypes.Int64Type{}, + "label": basetypes.StringType{}, + } +} diff --git a/internal/genprovider/datasource_core_images/core_images_data_source_gen.go b/internal/genprovider/datasource_core_images/core_images_data_source_gen.go index bd628c7..8209c0d 100644 --- a/internal/genprovider/datasource_core_images/core_images_data_source_gen.go +++ b/internal/genprovider/datasource_core_images/core_images_data_source_gen.go @@ -96,19 +96,47 @@ func CoreImagesDataSourceSchema(ctx context.Context) schema.Schema { }, Computed: true, }, + "include_public": schema.BoolAttribute{ + Optional: true, + Computed: true, + Description: "Flag to include public images in the response (true/false). Default is true.", + MarkdownDescription: "Flag to include public images in the response (true/false). Default is true.", + }, + "page": schema.Int64Attribute{ + Optional: true, + Computed: true, + Description: "Page number for pagination", + MarkdownDescription: "Page number for pagination", + }, + "per_page": schema.Int64Attribute{ + Optional: true, + Computed: true, + Description: "Number of Images per page", + MarkdownDescription: "Number of Images per page", + }, "region": schema.StringAttribute{ Optional: true, Computed: true, Description: "Region Name", MarkdownDescription: "Region Name", }, + "search": schema.StringAttribute{ + Optional: true, + Computed: true, + Description: "Search query to filter images by name", + MarkdownDescription: "Search query to filter images by name", + }, }, } } type CoreImagesModel struct { - CoreImages types.Set `tfsdk:"core_images"` - Region types.String `tfsdk:"region"` + CoreImages types.Set `tfsdk:"core_images"` + IncludePublic types.Bool `tfsdk:"include_public"` + Page types.Int64 `tfsdk:"page"` + PerPage types.Int64 `tfsdk:"per_page"` + Region types.String `tfsdk:"region"` + Search types.String `tfsdk:"search"` } var _ basetypes.ObjectTypable = CoreImagesType{} diff --git a/internal/genprovider/datasource_core_keypair/core_keypair_data_source_gen.go b/internal/genprovider/datasource_core_keypair/core_keypair_data_source_gen.go index 7a33d03..eb240a4 100644 --- a/internal/genprovider/datasource_core_keypair/core_keypair_data_source_gen.go +++ b/internal/genprovider/datasource_core_keypair/core_keypair_data_source_gen.go @@ -4,7 +4,13 @@ package datasource_core_keypair import ( "context" + "fmt" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "strings" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" ) @@ -15,7 +21,42 @@ func CoreKeypairDataSourceSchema(ctx context.Context) schema.Schema { "created_at": schema.StringAttribute{ Computed: true, }, - "environment": schema.StringAttribute{ + "environment": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "created_at": schema.StringAttribute{ + Computed: true, + }, + "features": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "green_status": schema.StringAttribute{ + Computed: true, + }, + "network_optimised": schema.BoolAttribute{ + Computed: true, + }, + }, + CustomType: FeaturesType{ + ObjectType: types.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + }, + Computed: true, + }, + "id": schema.Int64Attribute{ + Computed: true, + }, + "name": schema.StringAttribute{ + Computed: true, + }, + "region": schema.StringAttribute{ + Computed: true, + }, + }, + CustomType: EnvironmentType{ + ObjectType: types.ObjectType{ + AttrTypes: EnvironmentValue{}.AttributeTypes(ctx), + }, + }, Computed: true, }, "fingerprint": schema.StringAttribute{ @@ -35,10 +76,960 @@ func CoreKeypairDataSourceSchema(ctx context.Context) schema.Schema { } type CoreKeypairModel struct { - CreatedAt types.String `tfsdk:"created_at"` - Environment types.String `tfsdk:"environment"` - Fingerprint types.String `tfsdk:"fingerprint"` - Id types.Int64 `tfsdk:"id"` - Name types.String `tfsdk:"name"` - PublicKey types.String `tfsdk:"public_key"` + CreatedAt types.String `tfsdk:"created_at"` + Environment EnvironmentValue `tfsdk:"environment"` + Fingerprint types.String `tfsdk:"fingerprint"` + Id types.Int64 `tfsdk:"id"` + Name types.String `tfsdk:"name"` + PublicKey types.String `tfsdk:"public_key"` +} + +var _ basetypes.ObjectTypable = EnvironmentType{} + +type EnvironmentType struct { + basetypes.ObjectType +} + +func (t EnvironmentType) Equal(o attr.Type) bool { + other, ok := o.(EnvironmentType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t EnvironmentType) String() string { + return "EnvironmentType" +} + +func (t EnvironmentType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + attributes := in.Attributes() + + createdAtAttribute, ok := attributes["created_at"] + + if !ok { + diags.AddError( + "Attribute Missing", + `created_at is missing from object`) + + return nil, diags + } + + createdAtVal, ok := createdAtAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`created_at expected to be basetypes.StringValue, was: %T`, createdAtAttribute)) + } + + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return nil, diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + + idAttribute, ok := attributes["id"] + + if !ok { + diags.AddError( + "Attribute Missing", + `id is missing from object`) + + return nil, diags + } + + idVal, ok := idAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) + } + + nameAttribute, ok := attributes["name"] + + if !ok { + diags.AddError( + "Attribute Missing", + `name is missing from object`) + + return nil, diags + } + + nameVal, ok := nameAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`name expected to be basetypes.StringValue, was: %T`, nameAttribute)) + } + + regionAttribute, ok := attributes["region"] + + if !ok { + diags.AddError( + "Attribute Missing", + `region is missing from object`) + + return nil, diags + } + + regionVal, ok := regionAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`region expected to be basetypes.StringValue, was: %T`, regionAttribute)) + } + + if diags.HasError() { + return nil, diags + } + + return EnvironmentValue{ + CreatedAt: createdAtVal, + Features: featuresVal, + Id: idVal, + Name: nameVal, + Region: regionVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewEnvironmentValueNull() EnvironmentValue { + return EnvironmentValue{ + state: attr.ValueStateNull, + } +} + +func NewEnvironmentValueUnknown() EnvironmentValue { + return EnvironmentValue{ + state: attr.ValueStateUnknown, + } +} + +func NewEnvironmentValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (EnvironmentValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing EnvironmentValue Attribute Value", + "While creating a EnvironmentValue value, a missing attribute value was detected. "+ + "A EnvironmentValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("EnvironmentValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid EnvironmentValue Attribute Type", + "While creating a EnvironmentValue value, an invalid attribute value was detected. "+ + "A EnvironmentValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("EnvironmentValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("EnvironmentValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra EnvironmentValue Attribute Value", + "While creating a EnvironmentValue value, an extra attribute value was detected. "+ + "A EnvironmentValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra EnvironmentValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewEnvironmentValueUnknown(), diags + } + + createdAtAttribute, ok := attributes["created_at"] + + if !ok { + diags.AddError( + "Attribute Missing", + `created_at is missing from object`) + + return NewEnvironmentValueUnknown(), diags + } + + createdAtVal, ok := createdAtAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`created_at expected to be basetypes.StringValue, was: %T`, createdAtAttribute)) + } + + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return NewEnvironmentValueUnknown(), diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + + idAttribute, ok := attributes["id"] + + if !ok { + diags.AddError( + "Attribute Missing", + `id is missing from object`) + + return NewEnvironmentValueUnknown(), diags + } + + idVal, ok := idAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) + } + + nameAttribute, ok := attributes["name"] + + if !ok { + diags.AddError( + "Attribute Missing", + `name is missing from object`) + + return NewEnvironmentValueUnknown(), diags + } + + nameVal, ok := nameAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`name expected to be basetypes.StringValue, was: %T`, nameAttribute)) + } + + regionAttribute, ok := attributes["region"] + + if !ok { + diags.AddError( + "Attribute Missing", + `region is missing from object`) + + return NewEnvironmentValueUnknown(), diags + } + + regionVal, ok := regionAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`region expected to be basetypes.StringValue, was: %T`, regionAttribute)) + } + + if diags.HasError() { + return NewEnvironmentValueUnknown(), diags + } + + return EnvironmentValue{ + CreatedAt: createdAtVal, + Features: featuresVal, + Id: idVal, + Name: nameVal, + Region: regionVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewEnvironmentValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) EnvironmentValue { + object, diags := NewEnvironmentValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewEnvironmentValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t EnvironmentType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewEnvironmentValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewEnvironmentValueUnknown(), nil + } + + if in.IsNull() { + return NewEnvironmentValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewEnvironmentValueMust(EnvironmentValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t EnvironmentType) ValueType(ctx context.Context) attr.Value { + return EnvironmentValue{} +} + +var _ basetypes.ObjectValuable = EnvironmentValue{} + +type EnvironmentValue struct { + CreatedAt basetypes.StringValue `tfsdk:"created_at"` + Features basetypes.ObjectValue `tfsdk:"features"` + Id basetypes.Int64Value `tfsdk:"id"` + Name basetypes.StringValue `tfsdk:"name"` + Region basetypes.StringValue `tfsdk:"region"` + state attr.ValueState +} + +func (v EnvironmentValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 5) + + var val tftypes.Value + var err error + + attrTypes["created_at"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["features"] = basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }.TerraformType(ctx) + attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["region"] = basetypes.StringType{}.TerraformType(ctx) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 5) + + val, err = v.CreatedAt.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["created_at"] = val + + val, err = v.Features.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["features"] = val + + val, err = v.Id.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["id"] = val + + val, err = v.Name.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["name"] = val + + val, err = v.Region.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["region"] = val + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v EnvironmentValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v EnvironmentValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v EnvironmentValue) String() string { + return "EnvironmentValue" +} + +func (v EnvironmentValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + var features basetypes.ObjectValue + + if v.Features.IsNull() { + features = types.ObjectNull( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if v.Features.IsUnknown() { + features = types.ObjectUnknown( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if !v.Features.IsNull() && !v.Features.IsUnknown() { + features = types.ObjectValueMust( + FeaturesValue{}.AttributeTypes(ctx), + v.Features.Attributes(), + ) + } + + attributeTypes := map[string]attr.Type{ + "created_at": basetypes.StringType{}, + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + "id": basetypes.Int64Type{}, + "name": basetypes.StringType{}, + "region": basetypes.StringType{}, + } + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{ + "created_at": v.CreatedAt, + "features": features, + "id": v.Id, + "name": v.Name, + "region": v.Region, + }) + + return objVal, diags +} + +func (v EnvironmentValue) Equal(o attr.Value) bool { + other, ok := o.(EnvironmentValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + if !v.CreatedAt.Equal(other.CreatedAt) { + return false + } + + if !v.Features.Equal(other.Features) { + return false + } + + if !v.Id.Equal(other.Id) { + return false + } + + if !v.Name.Equal(other.Name) { + return false + } + + if !v.Region.Equal(other.Region) { + return false + } + + return true +} + +func (v EnvironmentValue) Type(ctx context.Context) attr.Type { + return EnvironmentType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v EnvironmentValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{ + "created_at": basetypes.StringType{}, + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + "id": basetypes.Int64Type{}, + "name": basetypes.StringType{}, + "region": basetypes.StringType{}, + } +} + +var _ basetypes.ObjectTypable = FeaturesType{} + +type FeaturesType struct { + basetypes.ObjectType +} + +func (t FeaturesType) Equal(o attr.Type) bool { + other, ok := o.(FeaturesType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t FeaturesType) String() string { + return "FeaturesType" +} + +func (t FeaturesType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + attributes := in.Attributes() + + greenStatusAttribute, ok := attributes["green_status"] + + if !ok { + diags.AddError( + "Attribute Missing", + `green_status is missing from object`) + + return nil, diags + } + + greenStatusVal, ok := greenStatusAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`green_status expected to be basetypes.StringValue, was: %T`, greenStatusAttribute)) + } + + networkOptimisedAttribute, ok := attributes["network_optimised"] + + if !ok { + diags.AddError( + "Attribute Missing", + `network_optimised is missing from object`) + + return nil, diags + } + + networkOptimisedVal, ok := networkOptimisedAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`network_optimised expected to be basetypes.BoolValue, was: %T`, networkOptimisedAttribute)) + } + + if diags.HasError() { + return nil, diags + } + + return FeaturesValue{ + GreenStatus: greenStatusVal, + NetworkOptimised: networkOptimisedVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueNull() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateNull, + } +} + +func NewFeaturesValueUnknown() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateUnknown, + } +} + +func NewFeaturesValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (FeaturesValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing FeaturesValue Attribute Value", + "While creating a FeaturesValue value, a missing attribute value was detected. "+ + "A FeaturesValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid FeaturesValue Attribute Type", + "While creating a FeaturesValue value, an invalid attribute value was detected. "+ + "A FeaturesValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra FeaturesValue Attribute Value", + "While creating a FeaturesValue value, an extra attribute value was detected. "+ + "A FeaturesValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra FeaturesValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + greenStatusAttribute, ok := attributes["green_status"] + + if !ok { + diags.AddError( + "Attribute Missing", + `green_status is missing from object`) + + return NewFeaturesValueUnknown(), diags + } + + greenStatusVal, ok := greenStatusAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`green_status expected to be basetypes.StringValue, was: %T`, greenStatusAttribute)) + } + + networkOptimisedAttribute, ok := attributes["network_optimised"] + + if !ok { + diags.AddError( + "Attribute Missing", + `network_optimised is missing from object`) + + return NewFeaturesValueUnknown(), diags + } + + networkOptimisedVal, ok := networkOptimisedAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`network_optimised expected to be basetypes.BoolValue, was: %T`, networkOptimisedAttribute)) + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + return FeaturesValue{ + GreenStatus: greenStatusVal, + NetworkOptimised: networkOptimisedVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) FeaturesValue { + object, diags := NewFeaturesValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewFeaturesValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t FeaturesType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewFeaturesValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewFeaturesValueUnknown(), nil + } + + if in.IsNull() { + return NewFeaturesValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewFeaturesValueMust(FeaturesValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t FeaturesType) ValueType(ctx context.Context) attr.Value { + return FeaturesValue{} +} + +var _ basetypes.ObjectValuable = FeaturesValue{} + +type FeaturesValue struct { + GreenStatus basetypes.StringValue `tfsdk:"green_status"` + NetworkOptimised basetypes.BoolValue `tfsdk:"network_optimised"` + state attr.ValueState +} + +func (v FeaturesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 2) + + var val tftypes.Value + var err error + + attrTypes["green_status"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["network_optimised"] = basetypes.BoolType{}.TerraformType(ctx) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 2) + + val, err = v.GreenStatus.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["green_status"] = val + + val, err = v.NetworkOptimised.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["network_optimised"] = val + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v FeaturesValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v FeaturesValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v FeaturesValue) String() string { + return "FeaturesValue" +} + +func (v FeaturesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + attributeTypes := map[string]attr.Type{ + "green_status": basetypes.StringType{}, + "network_optimised": basetypes.BoolType{}, + } + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{ + "green_status": v.GreenStatus, + "network_optimised": v.NetworkOptimised, + }) + + return objVal, diags +} + +func (v FeaturesValue) Equal(o attr.Value) bool { + other, ok := o.(FeaturesValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + if !v.GreenStatus.Equal(other.GreenStatus) { + return false + } + + if !v.NetworkOptimised.Equal(other.NetworkOptimised) { + return false + } + + return true +} + +func (v FeaturesValue) Type(ctx context.Context) attr.Type { + return FeaturesType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v FeaturesValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{ + "green_status": basetypes.StringType{}, + "network_optimised": basetypes.BoolType{}, + } } diff --git a/internal/genprovider/datasource_core_keypairs/core_keypairs_data_source_gen.go b/internal/genprovider/datasource_core_keypairs/core_keypairs_data_source_gen.go index 046bf15..a32e73a 100644 --- a/internal/genprovider/datasource_core_keypairs/core_keypairs_data_source_gen.go +++ b/internal/genprovider/datasource_core_keypairs/core_keypairs_data_source_gen.go @@ -24,7 +24,42 @@ func CoreKeypairsDataSourceSchema(ctx context.Context) schema.Schema { "created_at": schema.StringAttribute{ Computed: true, }, - "environment": schema.StringAttribute{ + "environment": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "created_at": schema.StringAttribute{ + Computed: true, + }, + "features": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "green_status": schema.StringAttribute{ + Computed: true, + }, + "network_optimised": schema.BoolAttribute{ + Computed: true, + }, + }, + CustomType: FeaturesType{ + ObjectType: types.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + }, + Computed: true, + }, + "id": schema.Int64Attribute{ + Computed: true, + }, + "name": schema.StringAttribute{ + Computed: true, + }, + "region": schema.StringAttribute{ + Computed: true, + }, + }, + CustomType: EnvironmentType{ + ObjectType: types.ObjectType{ + AttrTypes: EnvironmentValue{}.AttributeTypes(ctx), + }, + }, Computed: true, }, "fingerprint": schema.StringAttribute{ @@ -128,12 +163,12 @@ func (t CoreKeypairsType) ValueFromObject(ctx context.Context, in basetypes.Obje return nil, diags } - environmentVal, ok := environmentAttribute.(basetypes.StringValue) + environmentVal, ok := environmentAttribute.(basetypes.ObjectValue) if !ok { diags.AddError( "Attribute Wrong Type", - fmt.Sprintf(`environment expected to be basetypes.StringValue, was: %T`, environmentAttribute)) + fmt.Sprintf(`environment expected to be basetypes.ObjectValue, was: %T`, environmentAttribute)) } fingerprintAttribute, ok := attributes["fingerprint"] @@ -314,12 +349,12 @@ func NewCoreKeypairsValue(attributeTypes map[string]attr.Type, attributes map[st return NewCoreKeypairsValueUnknown(), diags } - environmentVal, ok := environmentAttribute.(basetypes.StringValue) + environmentVal, ok := environmentAttribute.(basetypes.ObjectValue) if !ok { diags.AddError( "Attribute Wrong Type", - fmt.Sprintf(`environment expected to be basetypes.StringValue, was: %T`, environmentAttribute)) + fmt.Sprintf(`environment expected to be basetypes.ObjectValue, was: %T`, environmentAttribute)) } fingerprintAttribute, ok := attributes["fingerprint"] @@ -478,7 +513,7 @@ var _ basetypes.ObjectValuable = CoreKeypairsValue{} type CoreKeypairsValue struct { CreatedAt basetypes.StringValue `tfsdk:"created_at"` - Environment basetypes.StringValue `tfsdk:"environment"` + Environment basetypes.ObjectValue `tfsdk:"environment"` Fingerprint basetypes.StringValue `tfsdk:"fingerprint"` Id basetypes.Int64Value `tfsdk:"id"` Name basetypes.StringValue `tfsdk:"name"` @@ -493,7 +528,9 @@ func (v CoreKeypairsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, var err error attrTypes["created_at"] = basetypes.StringType{}.TerraformType(ctx) - attrTypes["environment"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["environment"] = basetypes.ObjectType{ + AttrTypes: EnvironmentValue{}.AttributeTypes(ctx), + }.TerraformType(ctx) attrTypes["fingerprint"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx) @@ -582,9 +619,32 @@ func (v CoreKeypairsValue) String() string { func (v CoreKeypairsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { var diags diag.Diagnostics + var environment basetypes.ObjectValue + + if v.Environment.IsNull() { + environment = types.ObjectNull( + EnvironmentValue{}.AttributeTypes(ctx), + ) + } + + if v.Environment.IsUnknown() { + environment = types.ObjectUnknown( + EnvironmentValue{}.AttributeTypes(ctx), + ) + } + + if !v.Environment.IsNull() && !v.Environment.IsUnknown() { + environment = types.ObjectValueMust( + EnvironmentValue{}.AttributeTypes(ctx), + v.Environment.Attributes(), + ) + } + attributeTypes := map[string]attr.Type{ - "created_at": basetypes.StringType{}, - "environment": basetypes.StringType{}, + "created_at": basetypes.StringType{}, + "environment": basetypes.ObjectType{ + AttrTypes: EnvironmentValue{}.AttributeTypes(ctx), + }, "fingerprint": basetypes.StringType{}, "id": basetypes.Int64Type{}, "name": basetypes.StringType{}, @@ -603,7 +663,7 @@ func (v CoreKeypairsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectV attributeTypes, map[string]attr.Value{ "created_at": v.CreatedAt, - "environment": v.Environment, + "environment": environment, "fingerprint": v.Fingerprint, "id": v.Id, "name": v.Name, @@ -665,11 +725,963 @@ func (v CoreKeypairsValue) Type(ctx context.Context) attr.Type { func (v CoreKeypairsValue) AttributeTypes(ctx context.Context) map[string]attr.Type { return map[string]attr.Type{ - "created_at": basetypes.StringType{}, - "environment": basetypes.StringType{}, + "created_at": basetypes.StringType{}, + "environment": basetypes.ObjectType{ + AttrTypes: EnvironmentValue{}.AttributeTypes(ctx), + }, "fingerprint": basetypes.StringType{}, "id": basetypes.Int64Type{}, "name": basetypes.StringType{}, "public_key": basetypes.StringType{}, } } + +var _ basetypes.ObjectTypable = EnvironmentType{} + +type EnvironmentType struct { + basetypes.ObjectType +} + +func (t EnvironmentType) Equal(o attr.Type) bool { + other, ok := o.(EnvironmentType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t EnvironmentType) String() string { + return "EnvironmentType" +} + +func (t EnvironmentType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + attributes := in.Attributes() + + createdAtAttribute, ok := attributes["created_at"] + + if !ok { + diags.AddError( + "Attribute Missing", + `created_at is missing from object`) + + return nil, diags + } + + createdAtVal, ok := createdAtAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`created_at expected to be basetypes.StringValue, was: %T`, createdAtAttribute)) + } + + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return nil, diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + + idAttribute, ok := attributes["id"] + + if !ok { + diags.AddError( + "Attribute Missing", + `id is missing from object`) + + return nil, diags + } + + idVal, ok := idAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) + } + + nameAttribute, ok := attributes["name"] + + if !ok { + diags.AddError( + "Attribute Missing", + `name is missing from object`) + + return nil, diags + } + + nameVal, ok := nameAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`name expected to be basetypes.StringValue, was: %T`, nameAttribute)) + } + + regionAttribute, ok := attributes["region"] + + if !ok { + diags.AddError( + "Attribute Missing", + `region is missing from object`) + + return nil, diags + } + + regionVal, ok := regionAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`region expected to be basetypes.StringValue, was: %T`, regionAttribute)) + } + + if diags.HasError() { + return nil, diags + } + + return EnvironmentValue{ + CreatedAt: createdAtVal, + Features: featuresVal, + Id: idVal, + Name: nameVal, + Region: regionVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewEnvironmentValueNull() EnvironmentValue { + return EnvironmentValue{ + state: attr.ValueStateNull, + } +} + +func NewEnvironmentValueUnknown() EnvironmentValue { + return EnvironmentValue{ + state: attr.ValueStateUnknown, + } +} + +func NewEnvironmentValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (EnvironmentValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing EnvironmentValue Attribute Value", + "While creating a EnvironmentValue value, a missing attribute value was detected. "+ + "A EnvironmentValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("EnvironmentValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid EnvironmentValue Attribute Type", + "While creating a EnvironmentValue value, an invalid attribute value was detected. "+ + "A EnvironmentValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("EnvironmentValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("EnvironmentValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra EnvironmentValue Attribute Value", + "While creating a EnvironmentValue value, an extra attribute value was detected. "+ + "A EnvironmentValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra EnvironmentValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewEnvironmentValueUnknown(), diags + } + + createdAtAttribute, ok := attributes["created_at"] + + if !ok { + diags.AddError( + "Attribute Missing", + `created_at is missing from object`) + + return NewEnvironmentValueUnknown(), diags + } + + createdAtVal, ok := createdAtAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`created_at expected to be basetypes.StringValue, was: %T`, createdAtAttribute)) + } + + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return NewEnvironmentValueUnknown(), diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + + idAttribute, ok := attributes["id"] + + if !ok { + diags.AddError( + "Attribute Missing", + `id is missing from object`) + + return NewEnvironmentValueUnknown(), diags + } + + idVal, ok := idAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) + } + + nameAttribute, ok := attributes["name"] + + if !ok { + diags.AddError( + "Attribute Missing", + `name is missing from object`) + + return NewEnvironmentValueUnknown(), diags + } + + nameVal, ok := nameAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`name expected to be basetypes.StringValue, was: %T`, nameAttribute)) + } + + regionAttribute, ok := attributes["region"] + + if !ok { + diags.AddError( + "Attribute Missing", + `region is missing from object`) + + return NewEnvironmentValueUnknown(), diags + } + + regionVal, ok := regionAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`region expected to be basetypes.StringValue, was: %T`, regionAttribute)) + } + + if diags.HasError() { + return NewEnvironmentValueUnknown(), diags + } + + return EnvironmentValue{ + CreatedAt: createdAtVal, + Features: featuresVal, + Id: idVal, + Name: nameVal, + Region: regionVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewEnvironmentValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) EnvironmentValue { + object, diags := NewEnvironmentValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewEnvironmentValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t EnvironmentType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewEnvironmentValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewEnvironmentValueUnknown(), nil + } + + if in.IsNull() { + return NewEnvironmentValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewEnvironmentValueMust(EnvironmentValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t EnvironmentType) ValueType(ctx context.Context) attr.Value { + return EnvironmentValue{} +} + +var _ basetypes.ObjectValuable = EnvironmentValue{} + +type EnvironmentValue struct { + CreatedAt basetypes.StringValue `tfsdk:"created_at"` + Features basetypes.ObjectValue `tfsdk:"features"` + Id basetypes.Int64Value `tfsdk:"id"` + Name basetypes.StringValue `tfsdk:"name"` + Region basetypes.StringValue `tfsdk:"region"` + state attr.ValueState +} + +func (v EnvironmentValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 5) + + var val tftypes.Value + var err error + + attrTypes["created_at"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["features"] = basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }.TerraformType(ctx) + attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["region"] = basetypes.StringType{}.TerraformType(ctx) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 5) + + val, err = v.CreatedAt.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["created_at"] = val + + val, err = v.Features.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["features"] = val + + val, err = v.Id.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["id"] = val + + val, err = v.Name.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["name"] = val + + val, err = v.Region.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["region"] = val + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v EnvironmentValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v EnvironmentValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v EnvironmentValue) String() string { + return "EnvironmentValue" +} + +func (v EnvironmentValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + var features basetypes.ObjectValue + + if v.Features.IsNull() { + features = types.ObjectNull( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if v.Features.IsUnknown() { + features = types.ObjectUnknown( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if !v.Features.IsNull() && !v.Features.IsUnknown() { + features = types.ObjectValueMust( + FeaturesValue{}.AttributeTypes(ctx), + v.Features.Attributes(), + ) + } + + attributeTypes := map[string]attr.Type{ + "created_at": basetypes.StringType{}, + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + "id": basetypes.Int64Type{}, + "name": basetypes.StringType{}, + "region": basetypes.StringType{}, + } + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{ + "created_at": v.CreatedAt, + "features": features, + "id": v.Id, + "name": v.Name, + "region": v.Region, + }) + + return objVal, diags +} + +func (v EnvironmentValue) Equal(o attr.Value) bool { + other, ok := o.(EnvironmentValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + if !v.CreatedAt.Equal(other.CreatedAt) { + return false + } + + if !v.Features.Equal(other.Features) { + return false + } + + if !v.Id.Equal(other.Id) { + return false + } + + if !v.Name.Equal(other.Name) { + return false + } + + if !v.Region.Equal(other.Region) { + return false + } + + return true +} + +func (v EnvironmentValue) Type(ctx context.Context) attr.Type { + return EnvironmentType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v EnvironmentValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{ + "created_at": basetypes.StringType{}, + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + "id": basetypes.Int64Type{}, + "name": basetypes.StringType{}, + "region": basetypes.StringType{}, + } +} + +var _ basetypes.ObjectTypable = FeaturesType{} + +type FeaturesType struct { + basetypes.ObjectType +} + +func (t FeaturesType) Equal(o attr.Type) bool { + other, ok := o.(FeaturesType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t FeaturesType) String() string { + return "FeaturesType" +} + +func (t FeaturesType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + attributes := in.Attributes() + + greenStatusAttribute, ok := attributes["green_status"] + + if !ok { + diags.AddError( + "Attribute Missing", + `green_status is missing from object`) + + return nil, diags + } + + greenStatusVal, ok := greenStatusAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`green_status expected to be basetypes.StringValue, was: %T`, greenStatusAttribute)) + } + + networkOptimisedAttribute, ok := attributes["network_optimised"] + + if !ok { + diags.AddError( + "Attribute Missing", + `network_optimised is missing from object`) + + return nil, diags + } + + networkOptimisedVal, ok := networkOptimisedAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`network_optimised expected to be basetypes.BoolValue, was: %T`, networkOptimisedAttribute)) + } + + if diags.HasError() { + return nil, diags + } + + return FeaturesValue{ + GreenStatus: greenStatusVal, + NetworkOptimised: networkOptimisedVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueNull() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateNull, + } +} + +func NewFeaturesValueUnknown() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateUnknown, + } +} + +func NewFeaturesValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (FeaturesValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing FeaturesValue Attribute Value", + "While creating a FeaturesValue value, a missing attribute value was detected. "+ + "A FeaturesValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid FeaturesValue Attribute Type", + "While creating a FeaturesValue value, an invalid attribute value was detected. "+ + "A FeaturesValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra FeaturesValue Attribute Value", + "While creating a FeaturesValue value, an extra attribute value was detected. "+ + "A FeaturesValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra FeaturesValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + greenStatusAttribute, ok := attributes["green_status"] + + if !ok { + diags.AddError( + "Attribute Missing", + `green_status is missing from object`) + + return NewFeaturesValueUnknown(), diags + } + + greenStatusVal, ok := greenStatusAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`green_status expected to be basetypes.StringValue, was: %T`, greenStatusAttribute)) + } + + networkOptimisedAttribute, ok := attributes["network_optimised"] + + if !ok { + diags.AddError( + "Attribute Missing", + `network_optimised is missing from object`) + + return NewFeaturesValueUnknown(), diags + } + + networkOptimisedVal, ok := networkOptimisedAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`network_optimised expected to be basetypes.BoolValue, was: %T`, networkOptimisedAttribute)) + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + return FeaturesValue{ + GreenStatus: greenStatusVal, + NetworkOptimised: networkOptimisedVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) FeaturesValue { + object, diags := NewFeaturesValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewFeaturesValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t FeaturesType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewFeaturesValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewFeaturesValueUnknown(), nil + } + + if in.IsNull() { + return NewFeaturesValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewFeaturesValueMust(FeaturesValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t FeaturesType) ValueType(ctx context.Context) attr.Value { + return FeaturesValue{} +} + +var _ basetypes.ObjectValuable = FeaturesValue{} + +type FeaturesValue struct { + GreenStatus basetypes.StringValue `tfsdk:"green_status"` + NetworkOptimised basetypes.BoolValue `tfsdk:"network_optimised"` + state attr.ValueState +} + +func (v FeaturesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 2) + + var val tftypes.Value + var err error + + attrTypes["green_status"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["network_optimised"] = basetypes.BoolType{}.TerraformType(ctx) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 2) + + val, err = v.GreenStatus.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["green_status"] = val + + val, err = v.NetworkOptimised.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["network_optimised"] = val + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v FeaturesValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v FeaturesValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v FeaturesValue) String() string { + return "FeaturesValue" +} + +func (v FeaturesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + attributeTypes := map[string]attr.Type{ + "green_status": basetypes.StringType{}, + "network_optimised": basetypes.BoolType{}, + } + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{ + "green_status": v.GreenStatus, + "network_optimised": v.NetworkOptimised, + }) + + return objVal, diags +} + +func (v FeaturesValue) Equal(o attr.Value) bool { + other, ok := o.(FeaturesValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + if !v.GreenStatus.Equal(other.GreenStatus) { + return false + } + + if !v.NetworkOptimised.Equal(other.NetworkOptimised) { + return false + } + + return true +} + +func (v FeaturesValue) Type(ctx context.Context) attr.Type { + return FeaturesType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v FeaturesValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{ + "green_status": basetypes.StringType{}, + "network_optimised": basetypes.BoolType{}, + } +} diff --git a/internal/genprovider/datasource_core_regions/core_regions_data_source_gen.go b/internal/genprovider/datasource_core_regions/core_regions_data_source_gen.go index 6b42ca2..1d3e6e4 100644 --- a/internal/genprovider/datasource_core_regions/core_regions_data_source_gen.go +++ b/internal/genprovider/datasource_core_regions/core_regions_data_source_gen.go @@ -21,9 +21,17 @@ func CoreRegionsDataSourceSchema(ctx context.Context) schema.Schema { "core_regions": schema.SetNestedAttribute{ NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ + "country": schema.StringAttribute{ + Computed: true, + }, "description": schema.StringAttribute{ Computed: true, }, + "green_status": schema.StringAttribute{ + Computed: true, + Description: "Green status", + MarkdownDescription: "Green status", + }, "id": schema.Int64Attribute{ Computed: true, }, @@ -72,6 +80,24 @@ func (t CoreRegionsType) ValueFromObject(ctx context.Context, in basetypes.Objec attributes := in.Attributes() + countryAttribute, ok := attributes["country"] + + if !ok { + diags.AddError( + "Attribute Missing", + `country is missing from object`) + + return nil, diags + } + + countryVal, ok := countryAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`country expected to be basetypes.StringValue, was: %T`, countryAttribute)) + } + descriptionAttribute, ok := attributes["description"] if !ok { @@ -90,6 +116,24 @@ func (t CoreRegionsType) ValueFromObject(ctx context.Context, in basetypes.Objec fmt.Sprintf(`description expected to be basetypes.StringValue, was: %T`, descriptionAttribute)) } + greenStatusAttribute, ok := attributes["green_status"] + + if !ok { + diags.AddError( + "Attribute Missing", + `green_status is missing from object`) + + return nil, diags + } + + greenStatusVal, ok := greenStatusAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`green_status expected to be basetypes.StringValue, was: %T`, greenStatusAttribute)) + } + idAttribute, ok := attributes["id"] if !ok { @@ -131,7 +175,9 @@ func (t CoreRegionsType) ValueFromObject(ctx context.Context, in basetypes.Objec } return CoreRegionsValue{ + Country: countryVal, Description: descriptionVal, + GreenStatus: greenStatusVal, Id: idVal, Name: nameVal, state: attr.ValueStateKnown, @@ -201,6 +247,24 @@ func NewCoreRegionsValue(attributeTypes map[string]attr.Type, attributes map[str return NewCoreRegionsValueUnknown(), diags } + countryAttribute, ok := attributes["country"] + + if !ok { + diags.AddError( + "Attribute Missing", + `country is missing from object`) + + return NewCoreRegionsValueUnknown(), diags + } + + countryVal, ok := countryAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`country expected to be basetypes.StringValue, was: %T`, countryAttribute)) + } + descriptionAttribute, ok := attributes["description"] if !ok { @@ -219,6 +283,24 @@ func NewCoreRegionsValue(attributeTypes map[string]attr.Type, attributes map[str fmt.Sprintf(`description expected to be basetypes.StringValue, was: %T`, descriptionAttribute)) } + greenStatusAttribute, ok := attributes["green_status"] + + if !ok { + diags.AddError( + "Attribute Missing", + `green_status is missing from object`) + + return NewCoreRegionsValueUnknown(), diags + } + + greenStatusVal, ok := greenStatusAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`green_status expected to be basetypes.StringValue, was: %T`, greenStatusAttribute)) + } + idAttribute, ok := attributes["id"] if !ok { @@ -260,7 +342,9 @@ func NewCoreRegionsValue(attributeTypes map[string]attr.Type, attributes map[str } return CoreRegionsValue{ + Country: countryVal, Description: descriptionVal, + GreenStatus: greenStatusVal, Id: idVal, Name: nameVal, state: attr.ValueStateKnown, @@ -335,19 +419,23 @@ func (t CoreRegionsType) ValueType(ctx context.Context) attr.Value { var _ basetypes.ObjectValuable = CoreRegionsValue{} type CoreRegionsValue struct { + Country basetypes.StringValue `tfsdk:"country"` Description basetypes.StringValue `tfsdk:"description"` + GreenStatus basetypes.StringValue `tfsdk:"green_status"` Id basetypes.Int64Value `tfsdk:"id"` Name basetypes.StringValue `tfsdk:"name"` state attr.ValueState } func (v CoreRegionsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { - attrTypes := make(map[string]tftypes.Type, 3) + attrTypes := make(map[string]tftypes.Type, 5) var val tftypes.Value var err error + attrTypes["country"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["description"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["green_status"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx) @@ -355,7 +443,15 @@ func (v CoreRegionsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, switch v.state { case attr.ValueStateKnown: - vals := make(map[string]tftypes.Value, 3) + vals := make(map[string]tftypes.Value, 5) + + val, err = v.Country.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["country"] = val val, err = v.Description.ToTerraformValue(ctx) @@ -365,6 +461,14 @@ func (v CoreRegionsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, vals["description"] = val + val, err = v.GreenStatus.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["green_status"] = val + val, err = v.Id.ToTerraformValue(ctx) if err != nil { @@ -411,9 +515,11 @@ func (v CoreRegionsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectVa var diags diag.Diagnostics attributeTypes := map[string]attr.Type{ - "description": basetypes.StringType{}, - "id": basetypes.Int64Type{}, - "name": basetypes.StringType{}, + "country": basetypes.StringType{}, + "description": basetypes.StringType{}, + "green_status": basetypes.StringType{}, + "id": basetypes.Int64Type{}, + "name": basetypes.StringType{}, } if v.IsNull() { @@ -427,9 +533,11 @@ func (v CoreRegionsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectVa objVal, diags := types.ObjectValue( attributeTypes, map[string]attr.Value{ - "description": v.Description, - "id": v.Id, - "name": v.Name, + "country": v.Country, + "description": v.Description, + "green_status": v.GreenStatus, + "id": v.Id, + "name": v.Name, }) return objVal, diags @@ -450,10 +558,18 @@ func (v CoreRegionsValue) Equal(o attr.Value) bool { return true } + if !v.Country.Equal(other.Country) { + return false + } + if !v.Description.Equal(other.Description) { return false } + if !v.GreenStatus.Equal(other.GreenStatus) { + return false + } + if !v.Id.Equal(other.Id) { return false } @@ -475,8 +591,10 @@ func (v CoreRegionsValue) Type(ctx context.Context) attr.Type { func (v CoreRegionsValue) AttributeTypes(ctx context.Context) map[string]attr.Type { return map[string]attr.Type{ - "description": basetypes.StringType{}, - "id": basetypes.Int64Type{}, - "name": basetypes.StringType{}, + "country": basetypes.StringType{}, + "description": basetypes.StringType{}, + "green_status": basetypes.StringType{}, + "id": basetypes.Int64Type{}, + "name": basetypes.StringType{}, } } diff --git a/internal/genprovider/datasource_core_virtual_machines/core_virtual_machines_data_source_gen.go b/internal/genprovider/datasource_core_virtual_machines/core_virtual_machines_data_source_gen.go index 23fa344..8eb45cd 100644 --- a/internal/genprovider/datasource_core_virtual_machines/core_virtual_machines_data_source_gen.go +++ b/internal/genprovider/datasource_core_virtual_machines/core_virtual_machines_data_source_gen.go @@ -21,6 +21,9 @@ func CoreVirtualMachinesDataSourceSchema(ctx context.Context) schema.Schema { "core_virtual_machines": schema.SetNestedAttribute{ NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ + "callback_url": schema.StringAttribute{ + Computed: true, + }, "contract_id": schema.Int64Attribute{ Computed: true, }, @@ -29,6 +32,22 @@ func CoreVirtualMachinesDataSourceSchema(ctx context.Context) schema.Schema { }, "environment": schema.SingleNestedAttribute{ Attributes: map[string]schema.Attribute{ + "features": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "green_status": schema.StringAttribute{ + Computed: true, + }, + "network_optimised": schema.BoolAttribute{ + Computed: true, + }, + }, + CustomType: FeaturesType{ + ObjectType: types.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + }, + Computed: true, + }, "id": schema.Int64Attribute{ Computed: true, }, @@ -49,6 +68,15 @@ func CoreVirtualMachinesDataSourceSchema(ctx context.Context) schema.Schema { }, Computed: true, }, + "features": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{}, + CustomType: FeaturesType{ + ObjectType: types.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + }, + Computed: true, + }, "fixed_ip": schema.StringAttribute{ Computed: true, }, @@ -63,6 +91,15 @@ func CoreVirtualMachinesDataSourceSchema(ctx context.Context) schema.Schema { "ephemeral": schema.Int64Attribute{ Computed: true, }, + "features": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{}, + CustomType: FeaturesType{ + ObjectType: types.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + }, + Computed: true, + }, "gpu": schema.StringAttribute{ Computed: true, }, @@ -72,6 +109,24 @@ func CoreVirtualMachinesDataSourceSchema(ctx context.Context) schema.Schema { "id": schema.Int64Attribute{ Computed: true, }, + "labels": schema.ListNestedAttribute{ + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "id": schema.Int64Attribute{ + Computed: true, + }, + "label": schema.StringAttribute{ + Computed: true, + }, + }, + CustomType: LabelsType{ + ObjectType: types.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + }, + Computed: true, + }, "name": schema.StringAttribute{ Computed: true, }, @@ -134,9 +189,18 @@ func CoreVirtualMachinesDataSourceSchema(ctx context.Context) schema.Schema { "os": schema.StringAttribute{ Computed: true, }, + "port_randomization": schema.BoolAttribute{ + Computed: true, + }, + "port_randomization_status": schema.StringAttribute{ + Computed: true, + }, "power_state": schema.StringAttribute{ Computed: true, }, + "requires_public_ip": schema.BoolAttribute{ + Computed: true, + }, "security_rules": schema.ListNestedAttribute{ NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ @@ -196,6 +260,9 @@ func CoreVirtualMachinesDataSourceSchema(ctx context.Context) schema.Schema { }, "volume": schema.SingleNestedAttribute{ Attributes: map[string]schema.Attribute{ + "bootable": schema.BoolAttribute{ + Computed: true, + }, "description": schema.StringAttribute{ Computed: true, }, @@ -237,6 +304,12 @@ func CoreVirtualMachinesDataSourceSchema(ctx context.Context) schema.Schema { }, Computed: true, }, + "environment": schema.StringAttribute{ + Optional: true, + Computed: true, + Description: "Filter Environment ID or Name", + MarkdownDescription: "Filter Environment ID or Name", + }, "page": schema.StringAttribute{ Optional: true, Computed: true, @@ -259,6 +332,7 @@ func CoreVirtualMachinesDataSourceSchema(ctx context.Context) schema.Schema { type CoreVirtualMachinesModel struct { CoreVirtualMachines types.Set `tfsdk:"core_virtual_machines"` + Environment types.String `tfsdk:"environment"` Page types.String `tfsdk:"page"` PageSize types.String `tfsdk:"page_size"` Search types.String `tfsdk:"search"` @@ -289,6 +363,24 @@ func (t CoreVirtualMachinesType) ValueFromObject(ctx context.Context, in basetyp attributes := in.Attributes() + callbackUrlAttribute, ok := attributes["callback_url"] + + if !ok { + diags.AddError( + "Attribute Missing", + `callback_url is missing from object`) + + return nil, diags + } + + callbackUrlVal, ok := callbackUrlAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`callback_url expected to be basetypes.StringValue, was: %T`, callbackUrlAttribute)) + } + contractIdAttribute, ok := attributes["contract_id"] if !ok { @@ -343,6 +435,24 @@ func (t CoreVirtualMachinesType) ValueFromObject(ctx context.Context, in basetyp fmt.Sprintf(`environment expected to be basetypes.ObjectValue, was: %T`, environmentAttribute)) } + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return nil, diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + fixedIpAttribute, ok := attributes["fixed_ip"] if !ok { @@ -541,6 +651,42 @@ func (t CoreVirtualMachinesType) ValueFromObject(ctx context.Context, in basetyp fmt.Sprintf(`os expected to be basetypes.StringValue, was: %T`, osAttribute)) } + portRandomizationAttribute, ok := attributes["port_randomization"] + + if !ok { + diags.AddError( + "Attribute Missing", + `port_randomization is missing from object`) + + return nil, diags + } + + portRandomizationVal, ok := portRandomizationAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`port_randomization expected to be basetypes.BoolValue, was: %T`, portRandomizationAttribute)) + } + + portRandomizationStatusAttribute, ok := attributes["port_randomization_status"] + + if !ok { + diags.AddError( + "Attribute Missing", + `port_randomization_status is missing from object`) + + return nil, diags + } + + portRandomizationStatusVal, ok := portRandomizationStatusAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`port_randomization_status expected to be basetypes.StringValue, was: %T`, portRandomizationStatusAttribute)) + } + powerStateAttribute, ok := attributes["power_state"] if !ok { @@ -559,6 +705,24 @@ func (t CoreVirtualMachinesType) ValueFromObject(ctx context.Context, in basetyp fmt.Sprintf(`power_state expected to be basetypes.StringValue, was: %T`, powerStateAttribute)) } + requiresPublicIpAttribute, ok := attributes["requires_public_ip"] + + if !ok { + diags.AddError( + "Attribute Missing", + `requires_public_ip is missing from object`) + + return nil, diags + } + + requiresPublicIpVal, ok := requiresPublicIpAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`requires_public_ip expected to be basetypes.BoolValue, was: %T`, requiresPublicIpAttribute)) + } + securityRulesAttribute, ok := attributes["security_rules"] if !ok { @@ -636,26 +800,31 @@ func (t CoreVirtualMachinesType) ValueFromObject(ctx context.Context, in basetyp } return CoreVirtualMachinesValue{ - ContractId: contractIdVal, - CreatedAt: createdAtVal, - Environment: environmentVal, - FixedIp: fixedIpVal, - Flavor: flavorVal, - FloatingIp: floatingIpVal, - FloatingIpStatus: floatingIpStatusVal, - Id: idVal, - Image: imageVal, - Keypair: keypairVal, - Labels: labelsVal, - Locked: lockedVal, - Name: nameVal, - Os: osVal, - PowerState: powerStateVal, - SecurityRules: securityRulesVal, - Status: statusVal, - VmState: vmStateVal, - VolumeAttachments: volumeAttachmentsVal, - state: attr.ValueStateKnown, + CallbackUrl: callbackUrlVal, + ContractId: contractIdVal, + CreatedAt: createdAtVal, + Environment: environmentVal, + Features: featuresVal, + FixedIp: fixedIpVal, + Flavor: flavorVal, + FloatingIp: floatingIpVal, + FloatingIpStatus: floatingIpStatusVal, + Id: idVal, + Image: imageVal, + Keypair: keypairVal, + Labels: labelsVal, + Locked: lockedVal, + Name: nameVal, + Os: osVal, + PortRandomization: portRandomizationVal, + PortRandomizationStatus: portRandomizationStatusVal, + PowerState: powerStateVal, + RequiresPublicIp: requiresPublicIpVal, + SecurityRules: securityRulesVal, + Status: statusVal, + VmState: vmStateVal, + VolumeAttachments: volumeAttachmentsVal, + state: attr.ValueStateKnown, }, diags } @@ -722,6 +891,24 @@ func NewCoreVirtualMachinesValue(attributeTypes map[string]attr.Type, attributes return NewCoreVirtualMachinesValueUnknown(), diags } + callbackUrlAttribute, ok := attributes["callback_url"] + + if !ok { + diags.AddError( + "Attribute Missing", + `callback_url is missing from object`) + + return NewCoreVirtualMachinesValueUnknown(), diags + } + + callbackUrlVal, ok := callbackUrlAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`callback_url expected to be basetypes.StringValue, was: %T`, callbackUrlAttribute)) + } + contractIdAttribute, ok := attributes["contract_id"] if !ok { @@ -776,6 +963,24 @@ func NewCoreVirtualMachinesValue(attributeTypes map[string]attr.Type, attributes fmt.Sprintf(`environment expected to be basetypes.ObjectValue, was: %T`, environmentAttribute)) } + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return NewCoreVirtualMachinesValueUnknown(), diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + fixedIpAttribute, ok := attributes["fixed_ip"] if !ok { @@ -974,6 +1179,42 @@ func NewCoreVirtualMachinesValue(attributeTypes map[string]attr.Type, attributes fmt.Sprintf(`os expected to be basetypes.StringValue, was: %T`, osAttribute)) } + portRandomizationAttribute, ok := attributes["port_randomization"] + + if !ok { + diags.AddError( + "Attribute Missing", + `port_randomization is missing from object`) + + return NewCoreVirtualMachinesValueUnknown(), diags + } + + portRandomizationVal, ok := portRandomizationAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`port_randomization expected to be basetypes.BoolValue, was: %T`, portRandomizationAttribute)) + } + + portRandomizationStatusAttribute, ok := attributes["port_randomization_status"] + + if !ok { + diags.AddError( + "Attribute Missing", + `port_randomization_status is missing from object`) + + return NewCoreVirtualMachinesValueUnknown(), diags + } + + portRandomizationStatusVal, ok := portRandomizationStatusAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`port_randomization_status expected to be basetypes.StringValue, was: %T`, portRandomizationStatusAttribute)) + } + powerStateAttribute, ok := attributes["power_state"] if !ok { @@ -992,6 +1233,24 @@ func NewCoreVirtualMachinesValue(attributeTypes map[string]attr.Type, attributes fmt.Sprintf(`power_state expected to be basetypes.StringValue, was: %T`, powerStateAttribute)) } + requiresPublicIpAttribute, ok := attributes["requires_public_ip"] + + if !ok { + diags.AddError( + "Attribute Missing", + `requires_public_ip is missing from object`) + + return NewCoreVirtualMachinesValueUnknown(), diags + } + + requiresPublicIpVal, ok := requiresPublicIpAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`requires_public_ip expected to be basetypes.BoolValue, was: %T`, requiresPublicIpAttribute)) + } + securityRulesAttribute, ok := attributes["security_rules"] if !ok { @@ -1069,26 +1328,31 @@ func NewCoreVirtualMachinesValue(attributeTypes map[string]attr.Type, attributes } return CoreVirtualMachinesValue{ - ContractId: contractIdVal, - CreatedAt: createdAtVal, - Environment: environmentVal, - FixedIp: fixedIpVal, - Flavor: flavorVal, - FloatingIp: floatingIpVal, - FloatingIpStatus: floatingIpStatusVal, - Id: idVal, - Image: imageVal, - Keypair: keypairVal, - Labels: labelsVal, - Locked: lockedVal, - Name: nameVal, - Os: osVal, - PowerState: powerStateVal, - SecurityRules: securityRulesVal, - Status: statusVal, - VmState: vmStateVal, - VolumeAttachments: volumeAttachmentsVal, - state: attr.ValueStateKnown, + CallbackUrl: callbackUrlVal, + ContractId: contractIdVal, + CreatedAt: createdAtVal, + Environment: environmentVal, + Features: featuresVal, + FixedIp: fixedIpVal, + Flavor: flavorVal, + FloatingIp: floatingIpVal, + FloatingIpStatus: floatingIpStatusVal, + Id: idVal, + Image: imageVal, + Keypair: keypairVal, + Labels: labelsVal, + Locked: lockedVal, + Name: nameVal, + Os: osVal, + PortRandomization: portRandomizationVal, + PortRandomizationStatus: portRandomizationStatusVal, + PowerState: powerStateVal, + RequiresPublicIp: requiresPublicIpVal, + SecurityRules: securityRulesVal, + Status: statusVal, + VmState: vmStateVal, + VolumeAttachments: volumeAttachmentsVal, + state: attr.ValueStateKnown, }, diags } @@ -1160,39 +1424,48 @@ func (t CoreVirtualMachinesType) ValueType(ctx context.Context) attr.Value { var _ basetypes.ObjectValuable = CoreVirtualMachinesValue{} type CoreVirtualMachinesValue struct { - ContractId basetypes.Int64Value `tfsdk:"contract_id"` - CreatedAt basetypes.StringValue `tfsdk:"created_at"` - Environment basetypes.ObjectValue `tfsdk:"environment"` - FixedIp basetypes.StringValue `tfsdk:"fixed_ip"` - Flavor basetypes.ObjectValue `tfsdk:"flavor"` - FloatingIp basetypes.StringValue `tfsdk:"floating_ip"` - FloatingIpStatus basetypes.StringValue `tfsdk:"floating_ip_status"` - Id basetypes.Int64Value `tfsdk:"id"` - Image basetypes.ObjectValue `tfsdk:"image"` - Keypair basetypes.ObjectValue `tfsdk:"keypair"` - Labels basetypes.ListValue `tfsdk:"labels"` - Locked basetypes.BoolValue `tfsdk:"locked"` - Name basetypes.StringValue `tfsdk:"name"` - Os basetypes.StringValue `tfsdk:"os"` - PowerState basetypes.StringValue `tfsdk:"power_state"` - SecurityRules basetypes.ListValue `tfsdk:"security_rules"` - Status basetypes.StringValue `tfsdk:"status"` - VmState basetypes.StringValue `tfsdk:"vm_state"` - VolumeAttachments basetypes.ListValue `tfsdk:"volume_attachments"` - state attr.ValueState + CallbackUrl basetypes.StringValue `tfsdk:"callback_url"` + ContractId basetypes.Int64Value `tfsdk:"contract_id"` + CreatedAt basetypes.StringValue `tfsdk:"created_at"` + Environment basetypes.ObjectValue `tfsdk:"environment"` + Features basetypes.ObjectValue `tfsdk:"features"` + FixedIp basetypes.StringValue `tfsdk:"fixed_ip"` + Flavor basetypes.ObjectValue `tfsdk:"flavor"` + FloatingIp basetypes.StringValue `tfsdk:"floating_ip"` + FloatingIpStatus basetypes.StringValue `tfsdk:"floating_ip_status"` + Id basetypes.Int64Value `tfsdk:"id"` + Image basetypes.ObjectValue `tfsdk:"image"` + Keypair basetypes.ObjectValue `tfsdk:"keypair"` + Labels basetypes.ListValue `tfsdk:"labels"` + Locked basetypes.BoolValue `tfsdk:"locked"` + Name basetypes.StringValue `tfsdk:"name"` + Os basetypes.StringValue `tfsdk:"os"` + PortRandomization basetypes.BoolValue `tfsdk:"port_randomization"` + PortRandomizationStatus basetypes.StringValue `tfsdk:"port_randomization_status"` + PowerState basetypes.StringValue `tfsdk:"power_state"` + RequiresPublicIp basetypes.BoolValue `tfsdk:"requires_public_ip"` + SecurityRules basetypes.ListValue `tfsdk:"security_rules"` + Status basetypes.StringValue `tfsdk:"status"` + VmState basetypes.StringValue `tfsdk:"vm_state"` + VolumeAttachments basetypes.ListValue `tfsdk:"volume_attachments"` + state attr.ValueState } func (v CoreVirtualMachinesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { - attrTypes := make(map[string]tftypes.Type, 19) + attrTypes := make(map[string]tftypes.Type, 24) var val tftypes.Value var err error + attrTypes["callback_url"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["contract_id"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["created_at"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["environment"] = basetypes.ObjectType{ AttrTypes: EnvironmentValue{}.AttributeTypes(ctx), }.TerraformType(ctx) + attrTypes["features"] = basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }.TerraformType(ctx) attrTypes["fixed_ip"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["flavor"] = basetypes.ObjectType{ AttrTypes: FlavorValue{}.AttributeTypes(ctx), @@ -1212,7 +1485,10 @@ func (v CoreVirtualMachinesValue) ToTerraformValue(ctx context.Context) (tftypes attrTypes["locked"] = basetypes.BoolType{}.TerraformType(ctx) attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["os"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["port_randomization"] = basetypes.BoolType{}.TerraformType(ctx) + attrTypes["port_randomization_status"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["power_state"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["requires_public_ip"] = basetypes.BoolType{}.TerraformType(ctx) attrTypes["security_rules"] = basetypes.ListType{ ElemType: SecurityRulesValue{}.Type(ctx), }.TerraformType(ctx) @@ -1226,7 +1502,15 @@ func (v CoreVirtualMachinesValue) ToTerraformValue(ctx context.Context) (tftypes switch v.state { case attr.ValueStateKnown: - vals := make(map[string]tftypes.Value, 19) + vals := make(map[string]tftypes.Value, 24) + + val, err = v.CallbackUrl.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["callback_url"] = val val, err = v.ContractId.ToTerraformValue(ctx) @@ -1252,6 +1536,14 @@ func (v CoreVirtualMachinesValue) ToTerraformValue(ctx context.Context) (tftypes vals["environment"] = val + val, err = v.Features.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["features"] = val + val, err = v.FixedIp.ToTerraformValue(ctx) if err != nil { @@ -1340,6 +1632,22 @@ func (v CoreVirtualMachinesValue) ToTerraformValue(ctx context.Context) (tftypes vals["os"] = val + val, err = v.PortRandomization.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["port_randomization"] = val + + val, err = v.PortRandomizationStatus.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["port_randomization_status"] = val + val, err = v.PowerState.ToTerraformValue(ctx) if err != nil { @@ -1348,6 +1656,14 @@ func (v CoreVirtualMachinesValue) ToTerraformValue(ctx context.Context) (tftypes vals["power_state"] = val + val, err = v.RequiresPublicIp.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["requires_public_ip"] = val + val, err = v.SecurityRules.ToTerraformValue(ctx) if err != nil { @@ -1430,6 +1746,27 @@ func (v CoreVirtualMachinesValue) ToObjectValue(ctx context.Context) (basetypes. ) } + var features basetypes.ObjectValue + + if v.Features.IsNull() { + features = types.ObjectNull( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if v.Features.IsUnknown() { + features = types.ObjectUnknown( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if !v.Features.IsNull() && !v.Features.IsUnknown() { + features = types.ObjectValueMust( + FeaturesValue{}.AttributeTypes(ctx), + v.Features.Attributes(), + ) + } + var flavor basetypes.ObjectValue if v.Flavor.IsNull() { @@ -1551,17 +1888,29 @@ func (v CoreVirtualMachinesValue) ToObjectValue(ctx context.Context) (basetypes. ) } - labelsVal, d := types.ListValue(types.StringType, v.Labels.Elements()) - - diags.Append(d...) + var labelsVal basetypes.ListValue + switch { + case v.Labels.IsUnknown(): + labelsVal = types.ListUnknown(types.StringType) + case v.Labels.IsNull(): + labelsVal = types.ListNull(types.StringType) + default: + var d diag.Diagnostics + labelsVal, d = types.ListValue(types.StringType, v.Labels.Elements()) + diags.Append(d...) + } - if d.HasError() { + if diags.HasError() { return types.ObjectUnknown(map[string]attr.Type{ - "contract_id": basetypes.Int64Type{}, - "created_at": basetypes.StringType{}, + "callback_url": basetypes.StringType{}, + "contract_id": basetypes.Int64Type{}, + "created_at": basetypes.StringType{}, "environment": basetypes.ObjectType{ AttrTypes: EnvironmentValue{}.AttributeTypes(ctx), }, + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, "fixed_ip": basetypes.StringType{}, "flavor": basetypes.ObjectType{ AttrTypes: FlavorValue{}.AttributeTypes(ctx), @@ -1578,10 +1927,13 @@ func (v CoreVirtualMachinesValue) ToObjectValue(ctx context.Context) (basetypes. "labels": basetypes.ListType{ ElemType: types.StringType, }, - "locked": basetypes.BoolType{}, - "name": basetypes.StringType{}, - "os": basetypes.StringType{}, - "power_state": basetypes.StringType{}, + "locked": basetypes.BoolType{}, + "name": basetypes.StringType{}, + "os": basetypes.StringType{}, + "port_randomization": basetypes.BoolType{}, + "port_randomization_status": basetypes.StringType{}, + "power_state": basetypes.StringType{}, + "requires_public_ip": basetypes.BoolType{}, "security_rules": basetypes.ListType{ ElemType: SecurityRulesValue{}.Type(ctx), }, @@ -1594,11 +1946,15 @@ func (v CoreVirtualMachinesValue) ToObjectValue(ctx context.Context) (basetypes. } attributeTypes := map[string]attr.Type{ - "contract_id": basetypes.Int64Type{}, - "created_at": basetypes.StringType{}, + "callback_url": basetypes.StringType{}, + "contract_id": basetypes.Int64Type{}, + "created_at": basetypes.StringType{}, "environment": basetypes.ObjectType{ AttrTypes: EnvironmentValue{}.AttributeTypes(ctx), }, + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, "fixed_ip": basetypes.StringType{}, "flavor": basetypes.ObjectType{ AttrTypes: FlavorValue{}.AttributeTypes(ctx), @@ -1615,10 +1971,13 @@ func (v CoreVirtualMachinesValue) ToObjectValue(ctx context.Context) (basetypes. "labels": basetypes.ListType{ ElemType: types.StringType, }, - "locked": basetypes.BoolType{}, - "name": basetypes.StringType{}, - "os": basetypes.StringType{}, - "power_state": basetypes.StringType{}, + "locked": basetypes.BoolType{}, + "name": basetypes.StringType{}, + "os": basetypes.StringType{}, + "port_randomization": basetypes.BoolType{}, + "port_randomization_status": basetypes.StringType{}, + "power_state": basetypes.StringType{}, + "requires_public_ip": basetypes.BoolType{}, "security_rules": basetypes.ListType{ ElemType: SecurityRulesValue{}.Type(ctx), }, @@ -1640,25 +1999,30 @@ func (v CoreVirtualMachinesValue) ToObjectValue(ctx context.Context) (basetypes. objVal, diags := types.ObjectValue( attributeTypes, map[string]attr.Value{ - "contract_id": v.ContractId, - "created_at": v.CreatedAt, - "environment": environment, - "fixed_ip": v.FixedIp, - "flavor": flavor, - "floating_ip": v.FloatingIp, - "floating_ip_status": v.FloatingIpStatus, - "id": v.Id, - "image": image, - "keypair": keypair, - "labels": labelsVal, - "locked": v.Locked, - "name": v.Name, - "os": v.Os, - "power_state": v.PowerState, - "security_rules": securityRules, - "status": v.Status, - "vm_state": v.VmState, - "volume_attachments": volumeAttachments, + "callback_url": v.CallbackUrl, + "contract_id": v.ContractId, + "created_at": v.CreatedAt, + "environment": environment, + "features": features, + "fixed_ip": v.FixedIp, + "flavor": flavor, + "floating_ip": v.FloatingIp, + "floating_ip_status": v.FloatingIpStatus, + "id": v.Id, + "image": image, + "keypair": keypair, + "labels": labelsVal, + "locked": v.Locked, + "name": v.Name, + "os": v.Os, + "port_randomization": v.PortRandomization, + "port_randomization_status": v.PortRandomizationStatus, + "power_state": v.PowerState, + "requires_public_ip": v.RequiresPublicIp, + "security_rules": securityRules, + "status": v.Status, + "vm_state": v.VmState, + "volume_attachments": volumeAttachments, }) return objVal, diags @@ -1679,6 +2043,10 @@ func (v CoreVirtualMachinesValue) Equal(o attr.Value) bool { return true } + if !v.CallbackUrl.Equal(other.CallbackUrl) { + return false + } + if !v.ContractId.Equal(other.ContractId) { return false } @@ -1691,6 +2059,10 @@ func (v CoreVirtualMachinesValue) Equal(o attr.Value) bool { return false } + if !v.Features.Equal(other.Features) { + return false + } + if !v.FixedIp.Equal(other.FixedIp) { return false } @@ -1735,10 +2107,22 @@ func (v CoreVirtualMachinesValue) Equal(o attr.Value) bool { return false } + if !v.PortRandomization.Equal(other.PortRandomization) { + return false + } + + if !v.PortRandomizationStatus.Equal(other.PortRandomizationStatus) { + return false + } + if !v.PowerState.Equal(other.PowerState) { return false } + if !v.RequiresPublicIp.Equal(other.RequiresPublicIp) { + return false + } + if !v.SecurityRules.Equal(other.SecurityRules) { return false } @@ -1768,11 +2152,15 @@ func (v CoreVirtualMachinesValue) Type(ctx context.Context) attr.Type { func (v CoreVirtualMachinesValue) AttributeTypes(ctx context.Context) map[string]attr.Type { return map[string]attr.Type{ - "contract_id": basetypes.Int64Type{}, - "created_at": basetypes.StringType{}, + "callback_url": basetypes.StringType{}, + "contract_id": basetypes.Int64Type{}, + "created_at": basetypes.StringType{}, "environment": basetypes.ObjectType{ AttrTypes: EnvironmentValue{}.AttributeTypes(ctx), }, + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, "fixed_ip": basetypes.StringType{}, "flavor": basetypes.ObjectType{ AttrTypes: FlavorValue{}.AttributeTypes(ctx), @@ -1789,10 +2177,13 @@ func (v CoreVirtualMachinesValue) AttributeTypes(ctx context.Context) map[string "labels": basetypes.ListType{ ElemType: types.StringType, }, - "locked": basetypes.BoolType{}, - "name": basetypes.StringType{}, - "os": basetypes.StringType{}, - "power_state": basetypes.StringType{}, + "locked": basetypes.BoolType{}, + "name": basetypes.StringType{}, + "os": basetypes.StringType{}, + "port_randomization": basetypes.BoolType{}, + "port_randomization_status": basetypes.StringType{}, + "power_state": basetypes.StringType{}, + "requires_public_ip": basetypes.BoolType{}, "security_rules": basetypes.ListType{ ElemType: SecurityRulesValue{}.Type(ctx), }, @@ -1829,35 +2220,53 @@ func (t EnvironmentType) ValueFromObject(ctx context.Context, in basetypes.Objec attributes := in.Attributes() - idAttribute, ok := attributes["id"] + featuresAttribute, ok := attributes["features"] if !ok { diags.AddError( "Attribute Missing", - `id is missing from object`) + `features is missing from object`) return nil, diags } - idVal, ok := idAttribute.(basetypes.Int64Value) + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) if !ok { diags.AddError( "Attribute Wrong Type", - fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) } - nameAttribute, ok := attributes["name"] + idAttribute, ok := attributes["id"] if !ok { diags.AddError( "Attribute Missing", - `name is missing from object`) + `id is missing from object`) return nil, diags } - nameVal, ok := nameAttribute.(basetypes.StringValue) + idVal, ok := idAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) + } + + nameAttribute, ok := attributes["name"] + + if !ok { + diags.AddError( + "Attribute Missing", + `name is missing from object`) + + return nil, diags + } + + nameVal, ok := nameAttribute.(basetypes.StringValue) if !ok { diags.AddError( @@ -1906,11 +2315,12 @@ func (t EnvironmentType) ValueFromObject(ctx context.Context, in basetypes.Objec } return EnvironmentValue{ - Id: idVal, - Name: nameVal, - OrgId: orgIdVal, - Region: regionVal, - state: attr.ValueStateKnown, + Features: featuresVal, + Id: idVal, + Name: nameVal, + OrgId: orgIdVal, + Region: regionVal, + state: attr.ValueStateKnown, }, diags } @@ -1977,6 +2387,24 @@ func NewEnvironmentValue(attributeTypes map[string]attr.Type, attributes map[str return NewEnvironmentValueUnknown(), diags } + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return NewEnvironmentValueUnknown(), diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + idAttribute, ok := attributes["id"] if !ok { @@ -2054,11 +2482,12 @@ func NewEnvironmentValue(attributeTypes map[string]attr.Type, attributes map[str } return EnvironmentValue{ - Id: idVal, - Name: nameVal, - OrgId: orgIdVal, - Region: regionVal, - state: attr.ValueStateKnown, + Features: featuresVal, + Id: idVal, + Name: nameVal, + OrgId: orgIdVal, + Region: regionVal, + state: attr.ValueStateKnown, }, diags } @@ -2130,19 +2559,23 @@ func (t EnvironmentType) ValueType(ctx context.Context) attr.Value { var _ basetypes.ObjectValuable = EnvironmentValue{} type EnvironmentValue struct { - Id basetypes.Int64Value `tfsdk:"id"` - Name basetypes.StringValue `tfsdk:"name"` - OrgId basetypes.Int64Value `tfsdk:"org_id"` - Region basetypes.StringValue `tfsdk:"region"` - state attr.ValueState + Features basetypes.ObjectValue `tfsdk:"features"` + Id basetypes.Int64Value `tfsdk:"id"` + Name basetypes.StringValue `tfsdk:"name"` + OrgId basetypes.Int64Value `tfsdk:"org_id"` + Region basetypes.StringValue `tfsdk:"region"` + state attr.ValueState } func (v EnvironmentValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { - attrTypes := make(map[string]tftypes.Type, 4) + attrTypes := make(map[string]tftypes.Type, 5) var val tftypes.Value var err error + attrTypes["features"] = basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }.TerraformType(ctx) attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["org_id"] = basetypes.Int64Type{}.TerraformType(ctx) @@ -2152,7 +2585,15 @@ func (v EnvironmentValue) ToTerraformValue(ctx context.Context) (tftypes.Value, switch v.state { case attr.ValueStateKnown: - vals := make(map[string]tftypes.Value, 4) + vals := make(map[string]tftypes.Value, 5) + + val, err = v.Features.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["features"] = val val, err = v.Id.ToTerraformValue(ctx) @@ -2215,7 +2656,31 @@ func (v EnvironmentValue) String() string { func (v EnvironmentValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { var diags diag.Diagnostics + var features basetypes.ObjectValue + + if v.Features.IsNull() { + features = types.ObjectNull( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if v.Features.IsUnknown() { + features = types.ObjectUnknown( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if !v.Features.IsNull() && !v.Features.IsUnknown() { + features = types.ObjectValueMust( + FeaturesValue{}.AttributeTypes(ctx), + v.Features.Attributes(), + ) + } + attributeTypes := map[string]attr.Type{ + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, "id": basetypes.Int64Type{}, "name": basetypes.StringType{}, "org_id": basetypes.Int64Type{}, @@ -2233,10 +2698,11 @@ func (v EnvironmentValue) ToObjectValue(ctx context.Context) (basetypes.ObjectVa objVal, diags := types.ObjectValue( attributeTypes, map[string]attr.Value{ - "id": v.Id, - "name": v.Name, - "org_id": v.OrgId, - "region": v.Region, + "features": features, + "id": v.Id, + "name": v.Name, + "org_id": v.OrgId, + "region": v.Region, }) return objVal, diags @@ -2257,6 +2723,10 @@ func (v EnvironmentValue) Equal(o attr.Value) bool { return true } + if !v.Features.Equal(other.Features) { + return false + } + if !v.Id.Equal(other.Id) { return false } @@ -2286,6 +2756,9 @@ func (v EnvironmentValue) Type(ctx context.Context) attr.Type { func (v EnvironmentValue) AttributeTypes(ctx context.Context) map[string]attr.Type { return map[string]attr.Type{ + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, "id": basetypes.Int64Type{}, "name": basetypes.StringType{}, "org_id": basetypes.Int64Type{}, @@ -2293,14 +2766,14 @@ func (v EnvironmentValue) AttributeTypes(ctx context.Context) map[string]attr.Ty } } -var _ basetypes.ObjectTypable = FlavorType{} +var _ basetypes.ObjectTypable = FeaturesType{} -type FlavorType struct { +type FeaturesType struct { basetypes.ObjectType } -func (t FlavorType) Equal(o attr.Type) bool { - other, ok := o.(FlavorType) +func (t FeaturesType) Equal(o attr.Type) bool { + other, ok := o.(FeaturesType) if !ok { return false @@ -2309,189 +2782,75 @@ func (t FlavorType) Equal(o attr.Type) bool { return t.ObjectType.Equal(other.ObjectType) } -func (t FlavorType) String() string { - return "FlavorType" +func (t FeaturesType) String() string { + return "FeaturesType" } -func (t FlavorType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { +func (t FeaturesType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { var diags diag.Diagnostics attributes := in.Attributes() - cpuAttribute, ok := attributes["cpu"] - - if !ok { - diags.AddError( - "Attribute Missing", - `cpu is missing from object`) - - return nil, diags - } - - cpuVal, ok := cpuAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`cpu expected to be basetypes.Int64Value, was: %T`, cpuAttribute)) - } - - diskAttribute, ok := attributes["disk"] - - if !ok { - diags.AddError( - "Attribute Missing", - `disk is missing from object`) - - return nil, diags - } - - diskVal, ok := diskAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`disk expected to be basetypes.Int64Value, was: %T`, diskAttribute)) - } - - ephemeralAttribute, ok := attributes["ephemeral"] - - if !ok { - diags.AddError( - "Attribute Missing", - `ephemeral is missing from object`) - - return nil, diags - } - - ephemeralVal, ok := ephemeralAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`ephemeral expected to be basetypes.Int64Value, was: %T`, ephemeralAttribute)) - } - - gpuAttribute, ok := attributes["gpu"] - - if !ok { - diags.AddError( - "Attribute Missing", - `gpu is missing from object`) - - return nil, diags - } - - gpuVal, ok := gpuAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`gpu expected to be basetypes.StringValue, was: %T`, gpuAttribute)) - } - - gpuCountAttribute, ok := attributes["gpu_count"] - - if !ok { - diags.AddError( - "Attribute Missing", - `gpu_count is missing from object`) - - return nil, diags - } - - gpuCountVal, ok := gpuCountAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`gpu_count expected to be basetypes.Int64Value, was: %T`, gpuCountAttribute)) - } - - idAttribute, ok := attributes["id"] - - if !ok { - diags.AddError( - "Attribute Missing", - `id is missing from object`) - - return nil, diags - } - - idVal, ok := idAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) - } - - nameAttribute, ok := attributes["name"] + greenStatusAttribute, ok := attributes["green_status"] if !ok { diags.AddError( "Attribute Missing", - `name is missing from object`) + `green_status is missing from object`) return nil, diags } - nameVal, ok := nameAttribute.(basetypes.StringValue) + greenStatusVal, ok := greenStatusAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", - fmt.Sprintf(`name expected to be basetypes.StringValue, was: %T`, nameAttribute)) + fmt.Sprintf(`green_status expected to be basetypes.StringValue, was: %T`, greenStatusAttribute)) } - ramAttribute, ok := attributes["ram"] + networkOptimisedAttribute, ok := attributes["network_optimised"] if !ok { diags.AddError( "Attribute Missing", - `ram is missing from object`) + `network_optimised is missing from object`) return nil, diags } - ramVal, ok := ramAttribute.(basetypes.NumberValue) + networkOptimisedVal, ok := networkOptimisedAttribute.(basetypes.BoolValue) if !ok { diags.AddError( "Attribute Wrong Type", - fmt.Sprintf(`ram expected to be basetypes.NumberValue, was: %T`, ramAttribute)) + fmt.Sprintf(`network_optimised expected to be basetypes.BoolValue, was: %T`, networkOptimisedAttribute)) } if diags.HasError() { return nil, diags } - return FlavorValue{ - Cpu: cpuVal, - Disk: diskVal, - Ephemeral: ephemeralVal, - Gpu: gpuVal, - GpuCount: gpuCountVal, - Id: idVal, - Name: nameVal, - Ram: ramVal, - state: attr.ValueStateKnown, + return FeaturesValue{ + GreenStatus: greenStatusVal, + NetworkOptimised: networkOptimisedVal, + state: attr.ValueStateKnown, }, diags } -func NewFlavorValueNull() FlavorValue { - return FlavorValue{ +func NewFeaturesValueNull() FeaturesValue { + return FeaturesValue{ state: attr.ValueStateNull, } } -func NewFlavorValueUnknown() FlavorValue { - return FlavorValue{ +func NewFeaturesValueUnknown() FeaturesValue { + return FeaturesValue{ state: attr.ValueStateUnknown, } } -func NewFlavorValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (FlavorValue, diag.Diagnostics) { +func NewFeaturesValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (FeaturesValue, diag.Diagnostics) { var diags diag.Diagnostics // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 @@ -2502,11 +2861,11 @@ func NewFlavorValue(attributeTypes map[string]attr.Type, attributes map[string]a if !ok { diags.AddError( - "Missing FlavorValue Attribute Value", - "While creating a FlavorValue value, a missing attribute value was detected. "+ - "A FlavorValue must contain values for all attributes, even if null or unknown. "+ + "Missing FeaturesValue Attribute Value", + "While creating a FeaturesValue value, a missing attribute value was detected. "+ + "A FeaturesValue must contain values for all attributes, even if null or unknown. "+ "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("FlavorValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), ) continue @@ -2514,12 +2873,12 @@ func NewFlavorValue(attributeTypes map[string]attr.Type, attributes map[string]a if !attributeType.Equal(attribute.Type(ctx)) { diags.AddError( - "Invalid FlavorValue Attribute Type", - "While creating a FlavorValue value, an invalid attribute value was detected. "+ - "A FlavorValue must use a matching attribute type for the value. "+ + "Invalid FeaturesValue Attribute Type", + "While creating a FeaturesValue value, an invalid attribute value was detected. "+ + "A FeaturesValue must use a matching attribute type for the value. "+ "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("FlavorValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ - fmt.Sprintf("FlavorValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), ) } } @@ -2529,107 +2888,1797 @@ func NewFlavorValue(attributeTypes map[string]attr.Type, attributes map[string]a if !ok { diags.AddError( - "Extra FlavorValue Attribute Value", - "While creating a FlavorValue value, an extra attribute value was detected. "+ - "A FlavorValue must not contain values beyond the expected attribute types. "+ + "Extra FeaturesValue Attribute Value", + "While creating a FeaturesValue value, an extra attribute value was detected. "+ + "A FeaturesValue must not contain values beyond the expected attribute types. "+ "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("Extra FlavorValue Attribute Name: %s", name), + fmt.Sprintf("Extra FeaturesValue Attribute Name: %s", name), ) } } if diags.HasError() { - return NewFlavorValueUnknown(), diags + return NewFeaturesValueUnknown(), diags } - cpuAttribute, ok := attributes["cpu"] + greenStatusAttribute, ok := attributes["green_status"] if !ok { diags.AddError( "Attribute Missing", - `cpu is missing from object`) + `green_status is missing from object`) - return NewFlavorValueUnknown(), diags + return NewFeaturesValueUnknown(), diags } - cpuVal, ok := cpuAttribute.(basetypes.Int64Value) + greenStatusVal, ok := greenStatusAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", - fmt.Sprintf(`cpu expected to be basetypes.Int64Value, was: %T`, cpuAttribute)) + fmt.Sprintf(`green_status expected to be basetypes.StringValue, was: %T`, greenStatusAttribute)) } - diskAttribute, ok := attributes["disk"] + networkOptimisedAttribute, ok := attributes["network_optimised"] if !ok { diags.AddError( "Attribute Missing", - `disk is missing from object`) + `network_optimised is missing from object`) - return NewFlavorValueUnknown(), diags + return NewFeaturesValueUnknown(), diags } - diskVal, ok := diskAttribute.(basetypes.Int64Value) + networkOptimisedVal, ok := networkOptimisedAttribute.(basetypes.BoolValue) if !ok { diags.AddError( "Attribute Wrong Type", - fmt.Sprintf(`disk expected to be basetypes.Int64Value, was: %T`, diskAttribute)) + fmt.Sprintf(`network_optimised expected to be basetypes.BoolValue, was: %T`, networkOptimisedAttribute)) } - ephemeralAttribute, ok := attributes["ephemeral"] + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } - if !ok { - diags.AddError( - "Attribute Missing", - `ephemeral is missing from object`) + return FeaturesValue{ + GreenStatus: greenStatusVal, + NetworkOptimised: networkOptimisedVal, + state: attr.ValueStateKnown, + }, diags +} - return NewFlavorValueUnknown(), diags +func NewFeaturesValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) FeaturesValue { + object, diags := NewFeaturesValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewFeaturesValueMust received error(s): " + strings.Join(diagsStrings, "\n")) } - ephemeralVal, ok := ephemeralAttribute.(basetypes.Int64Value) + return object +} - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`ephemeral expected to be basetypes.Int64Value, was: %T`, ephemeralAttribute)) +func (t FeaturesType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewFeaturesValueNull(), nil } - gpuAttribute, ok := attributes["gpu"] + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewFeaturesValueUnknown(), nil + } + + if in.IsNull() { + return NewFeaturesValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewFeaturesValueMust(FeaturesValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t FeaturesType) ValueType(ctx context.Context) attr.Value { + return FeaturesValue{} +} + +var _ basetypes.ObjectValuable = FeaturesValue{} + +type FeaturesValue struct { + GreenStatus basetypes.StringValue `tfsdk:"green_status"` + NetworkOptimised basetypes.BoolValue `tfsdk:"network_optimised"` + state attr.ValueState +} + +func (v FeaturesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 2) + + var val tftypes.Value + var err error + + attrTypes["green_status"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["network_optimised"] = basetypes.BoolType{}.TerraformType(ctx) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 2) + + val, err = v.GreenStatus.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["green_status"] = val + + val, err = v.NetworkOptimised.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["network_optimised"] = val + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v FeaturesValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v FeaturesValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v FeaturesValue) String() string { + return "FeaturesValue" +} + +func (v FeaturesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + attributeTypes := map[string]attr.Type{ + "green_status": basetypes.StringType{}, + "network_optimised": basetypes.BoolType{}, + } + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{ + "green_status": v.GreenStatus, + "network_optimised": v.NetworkOptimised, + }) + + return objVal, diags +} + +func (v FeaturesValue) Equal(o attr.Value) bool { + other, ok := o.(FeaturesValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + if !v.GreenStatus.Equal(other.GreenStatus) { + return false + } + + if !v.NetworkOptimised.Equal(other.NetworkOptimised) { + return false + } + + return true +} + +func (v FeaturesValue) Type(ctx context.Context) attr.Type { + return FeaturesType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v FeaturesValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{ + "green_status": basetypes.StringType{}, + "network_optimised": basetypes.BoolType{}, + } +} + +var _ basetypes.ObjectTypable = FeaturesType{} + +type FeaturesType struct { + basetypes.ObjectType +} + +func (t FeaturesType) Equal(o attr.Type) bool { + other, ok := o.(FeaturesType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t FeaturesType) String() string { + return "FeaturesType" +} + +func (t FeaturesType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + if diags.HasError() { + return nil, diags + } + + return FeaturesValue{ + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueNull() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateNull, + } +} + +func NewFeaturesValueUnknown() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateUnknown, + } +} + +func NewFeaturesValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (FeaturesValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing FeaturesValue Attribute Value", + "While creating a FeaturesValue value, a missing attribute value was detected. "+ + "A FeaturesValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid FeaturesValue Attribute Type", + "While creating a FeaturesValue value, an invalid attribute value was detected. "+ + "A FeaturesValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra FeaturesValue Attribute Value", + "While creating a FeaturesValue value, an extra attribute value was detected. "+ + "A FeaturesValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra FeaturesValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + return FeaturesValue{ + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) FeaturesValue { + object, diags := NewFeaturesValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewFeaturesValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t FeaturesType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewFeaturesValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewFeaturesValueUnknown(), nil + } + + if in.IsNull() { + return NewFeaturesValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewFeaturesValueMust(FeaturesValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t FeaturesType) ValueType(ctx context.Context) attr.Value { + return FeaturesValue{} +} + +var _ basetypes.ObjectValuable = FeaturesValue{} + +type FeaturesValue struct { + state attr.ValueState +} + +func (v FeaturesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 0) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 0) + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v FeaturesValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v FeaturesValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v FeaturesValue) String() string { + return "FeaturesValue" +} + +func (v FeaturesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + attributeTypes := map[string]attr.Type{} + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{}) + + return objVal, diags +} + +func (v FeaturesValue) Equal(o attr.Value) bool { + other, ok := o.(FeaturesValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + return true +} + +func (v FeaturesValue) Type(ctx context.Context) attr.Type { + return FeaturesType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v FeaturesValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{} +} + +var _ basetypes.ObjectTypable = FlavorType{} + +type FlavorType struct { + basetypes.ObjectType +} + +func (t FlavorType) Equal(o attr.Type) bool { + other, ok := o.(FlavorType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t FlavorType) String() string { + return "FlavorType" +} + +func (t FlavorType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + attributes := in.Attributes() + + cpuAttribute, ok := attributes["cpu"] + + if !ok { + diags.AddError( + "Attribute Missing", + `cpu is missing from object`) + + return nil, diags + } + + cpuVal, ok := cpuAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`cpu expected to be basetypes.Int64Value, was: %T`, cpuAttribute)) + } + + diskAttribute, ok := attributes["disk"] + + if !ok { + diags.AddError( + "Attribute Missing", + `disk is missing from object`) + + return nil, diags + } + + diskVal, ok := diskAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`disk expected to be basetypes.Int64Value, was: %T`, diskAttribute)) + } + + ephemeralAttribute, ok := attributes["ephemeral"] + + if !ok { + diags.AddError( + "Attribute Missing", + `ephemeral is missing from object`) + + return nil, diags + } + + ephemeralVal, ok := ephemeralAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`ephemeral expected to be basetypes.Int64Value, was: %T`, ephemeralAttribute)) + } + + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return nil, diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + + gpuAttribute, ok := attributes["gpu"] + + if !ok { + diags.AddError( + "Attribute Missing", + `gpu is missing from object`) + + return nil, diags + } + + gpuVal, ok := gpuAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`gpu expected to be basetypes.StringValue, was: %T`, gpuAttribute)) + } + + gpuCountAttribute, ok := attributes["gpu_count"] + + if !ok { + diags.AddError( + "Attribute Missing", + `gpu_count is missing from object`) + + return nil, diags + } + + gpuCountVal, ok := gpuCountAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`gpu_count expected to be basetypes.Int64Value, was: %T`, gpuCountAttribute)) + } + + idAttribute, ok := attributes["id"] + + if !ok { + diags.AddError( + "Attribute Missing", + `id is missing from object`) + + return nil, diags + } + + idVal, ok := idAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) + } + + labelsAttribute, ok := attributes["labels"] + + if !ok { + diags.AddError( + "Attribute Missing", + `labels is missing from object`) + + return nil, diags + } + + labelsVal, ok := labelsAttribute.(basetypes.ListValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`labels expected to be basetypes.ListValue, was: %T`, labelsAttribute)) + } + + nameAttribute, ok := attributes["name"] + + if !ok { + diags.AddError( + "Attribute Missing", + `name is missing from object`) + + return nil, diags + } + + nameVal, ok := nameAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`name expected to be basetypes.StringValue, was: %T`, nameAttribute)) + } + + ramAttribute, ok := attributes["ram"] + + if !ok { + diags.AddError( + "Attribute Missing", + `ram is missing from object`) + + return nil, diags + } + + ramVal, ok := ramAttribute.(basetypes.NumberValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`ram expected to be basetypes.NumberValue, was: %T`, ramAttribute)) + } + + if diags.HasError() { + return nil, diags + } + + return FlavorValue{ + Cpu: cpuVal, + Disk: diskVal, + Ephemeral: ephemeralVal, + Features: featuresVal, + Gpu: gpuVal, + GpuCount: gpuCountVal, + Id: idVal, + Labels: labelsVal, + Name: nameVal, + Ram: ramVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewFlavorValueNull() FlavorValue { + return FlavorValue{ + state: attr.ValueStateNull, + } +} + +func NewFlavorValueUnknown() FlavorValue { + return FlavorValue{ + state: attr.ValueStateUnknown, + } +} + +func NewFlavorValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (FlavorValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing FlavorValue Attribute Value", + "While creating a FlavorValue value, a missing attribute value was detected. "+ + "A FlavorValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FlavorValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid FlavorValue Attribute Type", + "While creating a FlavorValue value, an invalid attribute value was detected. "+ + "A FlavorValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FlavorValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("FlavorValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra FlavorValue Attribute Value", + "While creating a FlavorValue value, an extra attribute value was detected. "+ + "A FlavorValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra FlavorValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewFlavorValueUnknown(), diags + } + + cpuAttribute, ok := attributes["cpu"] + + if !ok { + diags.AddError( + "Attribute Missing", + `cpu is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + cpuVal, ok := cpuAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`cpu expected to be basetypes.Int64Value, was: %T`, cpuAttribute)) + } + + diskAttribute, ok := attributes["disk"] + + if !ok { + diags.AddError( + "Attribute Missing", + `disk is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + diskVal, ok := diskAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`disk expected to be basetypes.Int64Value, was: %T`, diskAttribute)) + } + + ephemeralAttribute, ok := attributes["ephemeral"] + + if !ok { + diags.AddError( + "Attribute Missing", + `ephemeral is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + ephemeralVal, ok := ephemeralAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`ephemeral expected to be basetypes.Int64Value, was: %T`, ephemeralAttribute)) + } + + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + + gpuAttribute, ok := attributes["gpu"] + + if !ok { + diags.AddError( + "Attribute Missing", + `gpu is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + gpuVal, ok := gpuAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`gpu expected to be basetypes.StringValue, was: %T`, gpuAttribute)) + } + + gpuCountAttribute, ok := attributes["gpu_count"] + + if !ok { + diags.AddError( + "Attribute Missing", + `gpu_count is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + gpuCountVal, ok := gpuCountAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`gpu_count expected to be basetypes.Int64Value, was: %T`, gpuCountAttribute)) + } + + idAttribute, ok := attributes["id"] + + if !ok { + diags.AddError( + "Attribute Missing", + `id is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + idVal, ok := idAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) + } + + labelsAttribute, ok := attributes["labels"] + + if !ok { + diags.AddError( + "Attribute Missing", + `labels is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + labelsVal, ok := labelsAttribute.(basetypes.ListValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`labels expected to be basetypes.ListValue, was: %T`, labelsAttribute)) + } + + nameAttribute, ok := attributes["name"] + + if !ok { + diags.AddError( + "Attribute Missing", + `name is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + nameVal, ok := nameAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`name expected to be basetypes.StringValue, was: %T`, nameAttribute)) + } + + ramAttribute, ok := attributes["ram"] + + if !ok { + diags.AddError( + "Attribute Missing", + `ram is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + ramVal, ok := ramAttribute.(basetypes.NumberValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`ram expected to be basetypes.NumberValue, was: %T`, ramAttribute)) + } + + if diags.HasError() { + return NewFlavorValueUnknown(), diags + } + + return FlavorValue{ + Cpu: cpuVal, + Disk: diskVal, + Ephemeral: ephemeralVal, + Features: featuresVal, + Gpu: gpuVal, + GpuCount: gpuCountVal, + Id: idVal, + Labels: labelsVal, + Name: nameVal, + Ram: ramVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewFlavorValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) FlavorValue { + object, diags := NewFlavorValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewFlavorValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t FlavorType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewFlavorValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewFlavorValueUnknown(), nil + } + + if in.IsNull() { + return NewFlavorValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewFlavorValueMust(FlavorValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t FlavorType) ValueType(ctx context.Context) attr.Value { + return FlavorValue{} +} + +var _ basetypes.ObjectValuable = FlavorValue{} + +type FlavorValue struct { + Cpu basetypes.Int64Value `tfsdk:"cpu"` + Disk basetypes.Int64Value `tfsdk:"disk"` + Ephemeral basetypes.Int64Value `tfsdk:"ephemeral"` + Features basetypes.ObjectValue `tfsdk:"features"` + Gpu basetypes.StringValue `tfsdk:"gpu"` + GpuCount basetypes.Int64Value `tfsdk:"gpu_count"` + Id basetypes.Int64Value `tfsdk:"id"` + Labels basetypes.ListValue `tfsdk:"labels"` + Name basetypes.StringValue `tfsdk:"name"` + Ram basetypes.NumberValue `tfsdk:"ram"` + state attr.ValueState +} + +func (v FlavorValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 10) + + var val tftypes.Value + var err error + + attrTypes["cpu"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["disk"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["ephemeral"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["features"] = basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }.TerraformType(ctx) + attrTypes["gpu"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["gpu_count"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["labels"] = basetypes.ListType{ + ElemType: LabelsValue{}.Type(ctx), + }.TerraformType(ctx) + attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["ram"] = basetypes.NumberType{}.TerraformType(ctx) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 10) + + val, err = v.Cpu.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["cpu"] = val + + val, err = v.Disk.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["disk"] = val + + val, err = v.Ephemeral.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["ephemeral"] = val + + val, err = v.Features.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["features"] = val + + val, err = v.Gpu.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["gpu"] = val + + val, err = v.GpuCount.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["gpu_count"] = val + + val, err = v.Id.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["id"] = val + + val, err = v.Labels.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["labels"] = val + + val, err = v.Name.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["name"] = val + + val, err = v.Ram.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["ram"] = val + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v FlavorValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v FlavorValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v FlavorValue) String() string { + return "FlavorValue" +} + +func (v FlavorValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + var features basetypes.ObjectValue + + if v.Features.IsNull() { + features = types.ObjectNull( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if v.Features.IsUnknown() { + features = types.ObjectUnknown( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if !v.Features.IsNull() && !v.Features.IsUnknown() { + features = types.ObjectValueMust( + FeaturesValue{}.AttributeTypes(ctx), + v.Features.Attributes(), + ) + } + + labels := types.ListValueMust( + LabelsType{ + basetypes.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + v.Labels.Elements(), + ) + + if v.Labels.IsNull() { + labels = types.ListNull( + LabelsType{ + basetypes.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + ) + } + + if v.Labels.IsUnknown() { + labels = types.ListUnknown( + LabelsType{ + basetypes.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + ) + } + + attributeTypes := map[string]attr.Type{ + "cpu": basetypes.Int64Type{}, + "disk": basetypes.Int64Type{}, + "ephemeral": basetypes.Int64Type{}, + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + "gpu": basetypes.StringType{}, + "gpu_count": basetypes.Int64Type{}, + "id": basetypes.Int64Type{}, + "labels": basetypes.ListType{ + ElemType: LabelsValue{}.Type(ctx), + }, + "name": basetypes.StringType{}, + "ram": basetypes.NumberType{}, + } + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{ + "cpu": v.Cpu, + "disk": v.Disk, + "ephemeral": v.Ephemeral, + "features": features, + "gpu": v.Gpu, + "gpu_count": v.GpuCount, + "id": v.Id, + "labels": labels, + "name": v.Name, + "ram": v.Ram, + }) + + return objVal, diags +} + +func (v FlavorValue) Equal(o attr.Value) bool { + other, ok := o.(FlavorValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + if !v.Cpu.Equal(other.Cpu) { + return false + } + + if !v.Disk.Equal(other.Disk) { + return false + } + + if !v.Ephemeral.Equal(other.Ephemeral) { + return false + } + + if !v.Features.Equal(other.Features) { + return false + } + + if !v.Gpu.Equal(other.Gpu) { + return false + } + + if !v.GpuCount.Equal(other.GpuCount) { + return false + } + + if !v.Id.Equal(other.Id) { + return false + } + + if !v.Labels.Equal(other.Labels) { + return false + } + + if !v.Name.Equal(other.Name) { + return false + } + + if !v.Ram.Equal(other.Ram) { + return false + } + + return true +} + +func (v FlavorValue) Type(ctx context.Context) attr.Type { + return FlavorType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v FlavorValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{ + "cpu": basetypes.Int64Type{}, + "disk": basetypes.Int64Type{}, + "ephemeral": basetypes.Int64Type{}, + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + "gpu": basetypes.StringType{}, + "gpu_count": basetypes.Int64Type{}, + "id": basetypes.Int64Type{}, + "labels": basetypes.ListType{ + ElemType: LabelsValue{}.Type(ctx), + }, + "name": basetypes.StringType{}, + "ram": basetypes.NumberType{}, + } +} + +var _ basetypes.ObjectTypable = FeaturesType{} + +type FeaturesType struct { + basetypes.ObjectType +} + +func (t FeaturesType) Equal(o attr.Type) bool { + other, ok := o.(FeaturesType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t FeaturesType) String() string { + return "FeaturesType" +} + +func (t FeaturesType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + if diags.HasError() { + return nil, diags + } + + return FeaturesValue{ + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueNull() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateNull, + } +} + +func NewFeaturesValueUnknown() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateUnknown, + } +} + +func NewFeaturesValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (FeaturesValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing FeaturesValue Attribute Value", + "While creating a FeaturesValue value, a missing attribute value was detected. "+ + "A FeaturesValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid FeaturesValue Attribute Type", + "While creating a FeaturesValue value, an invalid attribute value was detected. "+ + "A FeaturesValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra FeaturesValue Attribute Value", + "While creating a FeaturesValue value, an extra attribute value was detected. "+ + "A FeaturesValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra FeaturesValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + return FeaturesValue{ + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) FeaturesValue { + object, diags := NewFeaturesValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewFeaturesValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t FeaturesType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewFeaturesValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewFeaturesValueUnknown(), nil + } + + if in.IsNull() { + return NewFeaturesValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewFeaturesValueMust(FeaturesValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t FeaturesType) ValueType(ctx context.Context) attr.Value { + return FeaturesValue{} +} + +var _ basetypes.ObjectValuable = FeaturesValue{} + +type FeaturesValue struct { + state attr.ValueState +} + +func (v FeaturesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 0) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 0) + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v FeaturesValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v FeaturesValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v FeaturesValue) String() string { + return "FeaturesValue" +} + +func (v FeaturesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + attributeTypes := map[string]attr.Type{} + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{}) + + return objVal, diags +} + +func (v FeaturesValue) Equal(o attr.Value) bool { + other, ok := o.(FeaturesValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + return true +} + +func (v FeaturesValue) Type(ctx context.Context) attr.Type { + return FeaturesType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v FeaturesValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{} +} + +var _ basetypes.ObjectTypable = LabelsType{} + +type LabelsType struct { + basetypes.ObjectType +} + +func (t LabelsType) Equal(o attr.Type) bool { + other, ok := o.(LabelsType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t LabelsType) String() string { + return "LabelsType" +} + +func (t LabelsType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + attributes := in.Attributes() + + idAttribute, ok := attributes["id"] if !ok { diags.AddError( "Attribute Missing", - `gpu is missing from object`) + `id is missing from object`) - return NewFlavorValueUnknown(), diags + return nil, diags + } + + idVal, ok := idAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) + } + + labelAttribute, ok := attributes["label"] + + if !ok { + diags.AddError( + "Attribute Missing", + `label is missing from object`) + + return nil, diags + } + + labelVal, ok := labelAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`label expected to be basetypes.StringValue, was: %T`, labelAttribute)) + } + + if diags.HasError() { + return nil, diags + } + + return LabelsValue{ + Id: idVal, + Label: labelVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewLabelsValueNull() LabelsValue { + return LabelsValue{ + state: attr.ValueStateNull, + } +} + +func NewLabelsValueUnknown() LabelsValue { + return LabelsValue{ + state: attr.ValueStateUnknown, } +} - gpuVal, ok := gpuAttribute.(basetypes.StringValue) +func NewLabelsValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (LabelsValue, diag.Diagnostics) { + var diags diag.Diagnostics - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`gpu expected to be basetypes.StringValue, was: %T`, gpuAttribute)) - } + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() - gpuCountAttribute, ok := attributes["gpu_count"] + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] - if !ok { - diags.AddError( - "Attribute Missing", - `gpu_count is missing from object`) + if !ok { + diags.AddError( + "Missing LabelsValue Attribute Value", + "While creating a LabelsValue value, a missing attribute value was detected. "+ + "A LabelsValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("LabelsValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) - return NewFlavorValueUnknown(), diags + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid LabelsValue Attribute Type", + "While creating a LabelsValue value, an invalid attribute value was detected. "+ + "A LabelsValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("LabelsValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("LabelsValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } } - gpuCountVal, ok := gpuCountAttribute.(basetypes.Int64Value) + for name := range attributes { + _, ok := attributeTypes[name] - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`gpu_count expected to be basetypes.Int64Value, was: %T`, gpuCountAttribute)) + if !ok { + diags.AddError( + "Extra LabelsValue Attribute Value", + "While creating a LabelsValue value, an extra attribute value was detected. "+ + "A LabelsValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra LabelsValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewLabelsValueUnknown(), diags } idAttribute, ok := attributes["id"] @@ -2639,7 +4688,7 @@ func NewFlavorValue(attributeTypes map[string]attr.Type, attributes map[string]a "Attribute Missing", `id is missing from object`) - return NewFlavorValueUnknown(), diags + return NewLabelsValueUnknown(), diags } idVal, ok := idAttribute.(basetypes.Int64Value) @@ -2650,61 +4699,37 @@ func NewFlavorValue(attributeTypes map[string]attr.Type, attributes map[string]a fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) } - nameAttribute, ok := attributes["name"] - - if !ok { - diags.AddError( - "Attribute Missing", - `name is missing from object`) - - return NewFlavorValueUnknown(), diags - } - - nameVal, ok := nameAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`name expected to be basetypes.StringValue, was: %T`, nameAttribute)) - } - - ramAttribute, ok := attributes["ram"] + labelAttribute, ok := attributes["label"] if !ok { diags.AddError( "Attribute Missing", - `ram is missing from object`) + `label is missing from object`) - return NewFlavorValueUnknown(), diags + return NewLabelsValueUnknown(), diags } - ramVal, ok := ramAttribute.(basetypes.NumberValue) + labelVal, ok := labelAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", - fmt.Sprintf(`ram expected to be basetypes.NumberValue, was: %T`, ramAttribute)) + fmt.Sprintf(`label expected to be basetypes.StringValue, was: %T`, labelAttribute)) } if diags.HasError() { - return NewFlavorValueUnknown(), diags + return NewLabelsValueUnknown(), diags } - return FlavorValue{ - Cpu: cpuVal, - Disk: diskVal, - Ephemeral: ephemeralVal, - Gpu: gpuVal, - GpuCount: gpuCountVal, - Id: idVal, - Name: nameVal, - Ram: ramVal, - state: attr.ValueStateKnown, + return LabelsValue{ + Id: idVal, + Label: labelVal, + state: attr.ValueStateKnown, }, diags } -func NewFlavorValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) FlavorValue { - object, diags := NewFlavorValue(attributeTypes, attributes) +func NewLabelsValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) LabelsValue { + object, diags := NewLabelsValue(attributeTypes, attributes) if diags.HasError() { // This could potentially be added to the diag package. @@ -2718,15 +4743,15 @@ func NewFlavorValueMust(attributeTypes map[string]attr.Type, attributes map[stri diagnostic.Detail())) } - panic("NewFlavorValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + panic("NewLabelsValueMust received error(s): " + strings.Join(diagsStrings, "\n")) } return object } -func (t FlavorType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { +func (t LabelsType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { if in.Type() == nil { - return NewFlavorValueNull(), nil + return NewLabelsValueNull(), nil } if !in.Type().Equal(t.TerraformType(ctx)) { @@ -2734,11 +4759,11 @@ func (t FlavorType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (a } if !in.IsKnown() { - return NewFlavorValueUnknown(), nil + return NewLabelsValueUnknown(), nil } if in.IsNull() { - return NewFlavorValueNull(), nil + return NewLabelsValueNull(), nil } attributes := map[string]attr.Value{} @@ -2761,87 +4786,35 @@ func (t FlavorType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (a attributes[k] = a } - return NewFlavorValueMust(FlavorValue{}.AttributeTypes(ctx), attributes), nil + return NewLabelsValueMust(LabelsValue{}.AttributeTypes(ctx), attributes), nil } -func (t FlavorType) ValueType(ctx context.Context) attr.Value { - return FlavorValue{} +func (t LabelsType) ValueType(ctx context.Context) attr.Value { + return LabelsValue{} } -var _ basetypes.ObjectValuable = FlavorValue{} +var _ basetypes.ObjectValuable = LabelsValue{} -type FlavorValue struct { - Cpu basetypes.Int64Value `tfsdk:"cpu"` - Disk basetypes.Int64Value `tfsdk:"disk"` - Ephemeral basetypes.Int64Value `tfsdk:"ephemeral"` - Gpu basetypes.StringValue `tfsdk:"gpu"` - GpuCount basetypes.Int64Value `tfsdk:"gpu_count"` - Id basetypes.Int64Value `tfsdk:"id"` - Name basetypes.StringValue `tfsdk:"name"` - Ram basetypes.NumberValue `tfsdk:"ram"` - state attr.ValueState +type LabelsValue struct { + Id basetypes.Int64Value `tfsdk:"id"` + Label basetypes.StringValue `tfsdk:"label"` + state attr.ValueState } -func (v FlavorValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { - attrTypes := make(map[string]tftypes.Type, 8) +func (v LabelsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 2) var val tftypes.Value var err error - attrTypes["cpu"] = basetypes.Int64Type{}.TerraformType(ctx) - attrTypes["disk"] = basetypes.Int64Type{}.TerraformType(ctx) - attrTypes["ephemeral"] = basetypes.Int64Type{}.TerraformType(ctx) - attrTypes["gpu"] = basetypes.StringType{}.TerraformType(ctx) - attrTypes["gpu_count"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) - attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx) - attrTypes["ram"] = basetypes.NumberType{}.TerraformType(ctx) + attrTypes["label"] = basetypes.StringType{}.TerraformType(ctx) objectType := tftypes.Object{AttributeTypes: attrTypes} switch v.state { case attr.ValueStateKnown: - vals := make(map[string]tftypes.Value, 8) - - val, err = v.Cpu.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["cpu"] = val - - val, err = v.Disk.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["disk"] = val - - val, err = v.Ephemeral.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["ephemeral"] = val - - val, err = v.Gpu.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["gpu"] = val - - val, err = v.GpuCount.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["gpu_count"] = val + vals := make(map[string]tftypes.Value, 2) val, err = v.Id.ToTerraformValue(ctx) @@ -2851,21 +4824,13 @@ func (v FlavorValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error vals["id"] = val - val, err = v.Name.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["name"] = val - - val, err = v.Ram.ToTerraformValue(ctx) + val, err = v.Label.ToTerraformValue(ctx) if err != nil { return tftypes.NewValue(objectType, tftypes.UnknownValue), err } - vals["ram"] = val + vals["label"] = val if err := tftypes.ValidateValue(objectType, vals); err != nil { return tftypes.NewValue(objectType, tftypes.UnknownValue), err @@ -2881,30 +4846,24 @@ func (v FlavorValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error } } -func (v FlavorValue) IsNull() bool { +func (v LabelsValue) IsNull() bool { return v.state == attr.ValueStateNull } -func (v FlavorValue) IsUnknown() bool { +func (v LabelsValue) IsUnknown() bool { return v.state == attr.ValueStateUnknown } -func (v FlavorValue) String() string { - return "FlavorValue" +func (v LabelsValue) String() string { + return "LabelsValue" } -func (v FlavorValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { +func (v LabelsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { var diags diag.Diagnostics attributeTypes := map[string]attr.Type{ - "cpu": basetypes.Int64Type{}, - "disk": basetypes.Int64Type{}, - "ephemeral": basetypes.Int64Type{}, - "gpu": basetypes.StringType{}, - "gpu_count": basetypes.Int64Type{}, - "id": basetypes.Int64Type{}, - "name": basetypes.StringType{}, - "ram": basetypes.NumberType{}, + "id": basetypes.Int64Type{}, + "label": basetypes.StringType{}, } if v.IsNull() { @@ -2918,21 +4877,15 @@ func (v FlavorValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, objVal, diags := types.ObjectValue( attributeTypes, map[string]attr.Value{ - "cpu": v.Cpu, - "disk": v.Disk, - "ephemeral": v.Ephemeral, - "gpu": v.Gpu, - "gpu_count": v.GpuCount, - "id": v.Id, - "name": v.Name, - "ram": v.Ram, + "id": v.Id, + "label": v.Label, }) return objVal, diags } -func (v FlavorValue) Equal(o attr.Value) bool { - other, ok := o.(FlavorValue) +func (v LabelsValue) Equal(o attr.Value) bool { + other, ok := o.(LabelsValue) if !ok { return false @@ -2946,59 +4899,29 @@ func (v FlavorValue) Equal(o attr.Value) bool { return true } - if !v.Cpu.Equal(other.Cpu) { - return false - } - - if !v.Disk.Equal(other.Disk) { - return false - } - - if !v.Ephemeral.Equal(other.Ephemeral) { - return false - } - - if !v.Gpu.Equal(other.Gpu) { - return false - } - - if !v.GpuCount.Equal(other.GpuCount) { - return false - } - if !v.Id.Equal(other.Id) { return false } - if !v.Name.Equal(other.Name) { - return false - } - - if !v.Ram.Equal(other.Ram) { + if !v.Label.Equal(other.Label) { return false } return true } -func (v FlavorValue) Type(ctx context.Context) attr.Type { - return FlavorType{ +func (v LabelsValue) Type(ctx context.Context) attr.Type { + return LabelsType{ basetypes.ObjectType{ AttrTypes: v.AttributeTypes(ctx), }, } } -func (v FlavorValue) AttributeTypes(ctx context.Context) map[string]attr.Type { +func (v LabelsValue) AttributeTypes(ctx context.Context) map[string]attr.Type { return map[string]attr.Type{ - "cpu": basetypes.Int64Type{}, - "disk": basetypes.Int64Type{}, - "ephemeral": basetypes.Int64Type{}, - "gpu": basetypes.StringType{}, - "gpu_count": basetypes.Int64Type{}, - "id": basetypes.Int64Type{}, - "name": basetypes.StringType{}, - "ram": basetypes.NumberType{}, + "id": basetypes.Int64Type{}, + "label": basetypes.StringType{}, } } @@ -4955,6 +6878,24 @@ func (t VolumeType) ValueFromObject(ctx context.Context, in basetypes.ObjectValu attributes := in.Attributes() + bootableAttribute, ok := attributes["bootable"] + + if !ok { + diags.AddError( + "Attribute Missing", + `bootable is missing from object`) + + return nil, diags + } + + bootableVal, ok := bootableAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`bootable expected to be basetypes.BoolValue, was: %T`, bootableAttribute)) + } + descriptionAttribute, ok := attributes["description"] if !ok { @@ -5050,6 +6991,7 @@ func (t VolumeType) ValueFromObject(ctx context.Context, in basetypes.ObjectValu } return VolumeValue{ + Bootable: bootableVal, Description: descriptionVal, Id: idVal, Name: nameVal, @@ -5122,6 +7064,24 @@ func NewVolumeValue(attributeTypes map[string]attr.Type, attributes map[string]a return NewVolumeValueUnknown(), diags } + bootableAttribute, ok := attributes["bootable"] + + if !ok { + diags.AddError( + "Attribute Missing", + `bootable is missing from object`) + + return NewVolumeValueUnknown(), diags + } + + bootableVal, ok := bootableAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`bootable expected to be basetypes.BoolValue, was: %T`, bootableAttribute)) + } + descriptionAttribute, ok := attributes["description"] if !ok { @@ -5217,6 +7177,7 @@ func NewVolumeValue(attributeTypes map[string]attr.Type, attributes map[string]a } return VolumeValue{ + Bootable: bootableVal, Description: descriptionVal, Id: idVal, Name: nameVal, @@ -5294,6 +7255,7 @@ func (t VolumeType) ValueType(ctx context.Context) attr.Value { var _ basetypes.ObjectValuable = VolumeValue{} type VolumeValue struct { + Bootable basetypes.BoolValue `tfsdk:"bootable"` Description basetypes.StringValue `tfsdk:"description"` Id basetypes.Int64Value `tfsdk:"id"` Name basetypes.StringValue `tfsdk:"name"` @@ -5303,11 +7265,12 @@ type VolumeValue struct { } func (v VolumeValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { - attrTypes := make(map[string]tftypes.Type, 5) + attrTypes := make(map[string]tftypes.Type, 6) var val tftypes.Value var err error + attrTypes["bootable"] = basetypes.BoolType{}.TerraformType(ctx) attrTypes["description"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx) @@ -5318,7 +7281,15 @@ func (v VolumeValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error switch v.state { case attr.ValueStateKnown: - vals := make(map[string]tftypes.Value, 5) + vals := make(map[string]tftypes.Value, 6) + + val, err = v.Bootable.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["bootable"] = val val, err = v.Description.ToTerraformValue(ctx) @@ -5390,6 +7361,7 @@ func (v VolumeValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, var diags diag.Diagnostics attributeTypes := map[string]attr.Type{ + "bootable": basetypes.BoolType{}, "description": basetypes.StringType{}, "id": basetypes.Int64Type{}, "name": basetypes.StringType{}, @@ -5408,6 +7380,7 @@ func (v VolumeValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, objVal, diags := types.ObjectValue( attributeTypes, map[string]attr.Value{ + "bootable": v.Bootable, "description": v.Description, "id": v.Id, "name": v.Name, @@ -5433,6 +7406,10 @@ func (v VolumeValue) Equal(o attr.Value) bool { return true } + if !v.Bootable.Equal(other.Bootable) { + return false + } + if !v.Description.Equal(other.Description) { return false } @@ -5466,6 +7443,7 @@ func (v VolumeValue) Type(ctx context.Context) attr.Type { func (v VolumeValue) AttributeTypes(ctx context.Context) map[string]attr.Type { return map[string]attr.Type{ + "bootable": basetypes.BoolType{}, "description": basetypes.StringType{}, "id": basetypes.Int64Type{}, "name": basetypes.StringType{}, diff --git a/internal/genprovider/datasource_core_volumes/core_volumes_data_source_gen.go b/internal/genprovider/datasource_core_volumes/core_volumes_data_source_gen.go index 444955b..3b0094e 100644 --- a/internal/genprovider/datasource_core_volumes/core_volumes_data_source_gen.go +++ b/internal/genprovider/datasource_core_volumes/core_volumes_data_source_gen.go @@ -55,6 +55,9 @@ func CoreVolumesDataSourceSchema(ctx context.Context) schema.Schema { "name": schema.StringAttribute{ Computed: true, }, + "os_image": schema.StringAttribute{ + Computed: true, + }, "size": schema.Int64Attribute{ Computed: true, }, @@ -76,13 +79,23 @@ func CoreVolumesDataSourceSchema(ctx context.Context) schema.Schema { }, Computed: true, }, - "page": schema.Int64Attribute{ - Optional: true, - Computed: true, + "environment": schema.StringAttribute{ + Optional: true, + Computed: true, + Description: "Filter Environment ID or Name", + MarkdownDescription: "Filter Environment ID or Name", }, - "page_size": schema.Int64Attribute{ - Optional: true, - Computed: true, + "page": schema.StringAttribute{ + Optional: true, + Computed: true, + Description: "Page Number", + MarkdownDescription: "Page Number", + }, + "page_size": schema.StringAttribute{ + Optional: true, + Computed: true, + Description: "Data Per Page", + MarkdownDescription: "Data Per Page", }, "search": schema.StringAttribute{ Optional: true, @@ -94,8 +107,9 @@ func CoreVolumesDataSourceSchema(ctx context.Context) schema.Schema { type CoreVolumesModel struct { CoreVolumes types.Set `tfsdk:"core_volumes"` - Page types.Int64 `tfsdk:"page"` - PageSize types.Int64 `tfsdk:"page_size"` + Environment types.String `tfsdk:"environment"` + Page types.String `tfsdk:"page"` + PageSize types.String `tfsdk:"page_size"` Search types.String `tfsdk:"search"` } @@ -268,6 +282,24 @@ func (t CoreVolumesType) ValueFromObject(ctx context.Context, in basetypes.Objec fmt.Sprintf(`name expected to be basetypes.StringValue, was: %T`, nameAttribute)) } + osImageAttribute, ok := attributes["os_image"] + + if !ok { + diags.AddError( + "Attribute Missing", + `os_image is missing from object`) + + return nil, diags + } + + osImageVal, ok := osImageAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`os_image expected to be basetypes.StringValue, was: %T`, osImageAttribute)) + } + sizeAttribute, ok := attributes["size"] if !ok { @@ -353,6 +385,7 @@ func (t CoreVolumesType) ValueFromObject(ctx context.Context, in basetypes.Objec Id: idVal, ImageId: imageIdVal, Name: nameVal, + OsImage: osImageVal, Size: sizeVal, Status: statusVal, UpdatedAt: updatedAtVal, @@ -568,6 +601,24 @@ func NewCoreVolumesValue(attributeTypes map[string]attr.Type, attributes map[str fmt.Sprintf(`name expected to be basetypes.StringValue, was: %T`, nameAttribute)) } + osImageAttribute, ok := attributes["os_image"] + + if !ok { + diags.AddError( + "Attribute Missing", + `os_image is missing from object`) + + return NewCoreVolumesValueUnknown(), diags + } + + osImageVal, ok := osImageAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`os_image expected to be basetypes.StringValue, was: %T`, osImageAttribute)) + } + sizeAttribute, ok := attributes["size"] if !ok { @@ -653,6 +704,7 @@ func NewCoreVolumesValue(attributeTypes map[string]attr.Type, attributes map[str Id: idVal, ImageId: imageIdVal, Name: nameVal, + OsImage: osImageVal, Size: sizeVal, Status: statusVal, UpdatedAt: updatedAtVal, @@ -737,6 +789,7 @@ type CoreVolumesValue struct { Id basetypes.Int64Value `tfsdk:"id"` ImageId basetypes.Int64Value `tfsdk:"image_id"` Name basetypes.StringValue `tfsdk:"name"` + OsImage basetypes.StringValue `tfsdk:"os_image"` Size basetypes.Int64Value `tfsdk:"size"` Status basetypes.StringValue `tfsdk:"status"` UpdatedAt basetypes.StringValue `tfsdk:"updated_at"` @@ -745,7 +798,7 @@ type CoreVolumesValue struct { } func (v CoreVolumesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { - attrTypes := make(map[string]tftypes.Type, 12) + attrTypes := make(map[string]tftypes.Type, 13) var val tftypes.Value var err error @@ -760,6 +813,7 @@ func (v CoreVolumesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["image_id"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["os_image"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["size"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["status"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["updated_at"] = basetypes.StringType{}.TerraformType(ctx) @@ -769,7 +823,7 @@ func (v CoreVolumesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, switch v.state { case attr.ValueStateKnown: - vals := make(map[string]tftypes.Value, 12) + vals := make(map[string]tftypes.Value, 13) val, err = v.Bootable.ToTerraformValue(ctx) @@ -835,6 +889,14 @@ func (v CoreVolumesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, vals["name"] = val + val, err = v.OsImage.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["os_image"] = val + val, err = v.Size.ToTerraformValue(ctx) if err != nil { @@ -928,6 +990,7 @@ func (v CoreVolumesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectVa "id": basetypes.Int64Type{}, "image_id": basetypes.Int64Type{}, "name": basetypes.StringType{}, + "os_image": basetypes.StringType{}, "size": basetypes.Int64Type{}, "status": basetypes.StringType{}, "updated_at": basetypes.StringType{}, @@ -953,6 +1016,7 @@ func (v CoreVolumesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectVa "id": v.Id, "image_id": v.ImageId, "name": v.Name, + "os_image": v.OsImage, "size": v.Size, "status": v.Status, "updated_at": v.UpdatedAt, @@ -1009,6 +1073,10 @@ func (v CoreVolumesValue) Equal(o attr.Value) bool { return false } + if !v.OsImage.Equal(other.OsImage) { + return false + } + if !v.Size.Equal(other.Size) { return false } @@ -1048,6 +1116,7 @@ func (v CoreVolumesValue) AttributeTypes(ctx context.Context) map[string]attr.Ty "id": basetypes.Int64Type{}, "image_id": basetypes.Int64Type{}, "name": basetypes.StringType{}, + "os_image": basetypes.StringType{}, "size": basetypes.Int64Type{}, "status": basetypes.StringType{}, "updated_at": basetypes.StringType{}, diff --git a/internal/genprovider/resource_core_cluster/core_cluster_resource_gen.go b/internal/genprovider/resource_core_cluster/core_cluster_resource_gen.go index b88c1dc..277cd39 100644 --- a/internal/genprovider/resource_core_cluster/core_cluster_resource_gen.go +++ b/internal/genprovider/resource_core_cluster/core_cluster_resource_gen.go @@ -80,6 +80,15 @@ func CoreClusterResourceSchema(ctx context.Context) schema.Schema { "ephemeral": schema.Int64Attribute{ Computed: true, }, + "features": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{}, + CustomType: FeaturesType{ + ObjectType: types.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + }, + Computed: true, + }, "gpu": schema.StringAttribute{ Computed: true, }, @@ -89,6 +98,24 @@ func CoreClusterResourceSchema(ctx context.Context) schema.Schema { "id": schema.Int64Attribute{ Computed: true, }, + "labels": schema.ListNestedAttribute{ + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "id": schema.Int64Attribute{ + Computed: true, + }, + "label": schema.StringAttribute{ + Computed: true, + }, + }, + CustomType: LabelsType{ + ObjectType: types.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + }, + Computed: true, + }, "name": schema.StringAttribute{ Computed: true, }, @@ -213,6 +240,24 @@ func (t NodeFlavorType) ValueFromObject(ctx context.Context, in basetypes.Object fmt.Sprintf(`ephemeral expected to be basetypes.Int64Value, was: %T`, ephemeralAttribute)) } + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return nil, diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + gpuAttribute, ok := attributes["gpu"] if !ok { @@ -267,6 +312,24 @@ func (t NodeFlavorType) ValueFromObject(ctx context.Context, in basetypes.Object fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) } + labelsAttribute, ok := attributes["labels"] + + if !ok { + diags.AddError( + "Attribute Missing", + `labels is missing from object`) + + return nil, diags + } + + labelsVal, ok := labelsAttribute.(basetypes.ListValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`labels expected to be basetypes.ListValue, was: %T`, labelsAttribute)) + } + nameAttribute, ok := attributes["name"] if !ok { @@ -311,9 +374,11 @@ func (t NodeFlavorType) ValueFromObject(ctx context.Context, in basetypes.Object Cpu: cpuVal, Disk: diskVal, Ephemeral: ephemeralVal, + Features: featuresVal, Gpu: gpuVal, GpuCount: gpuCountVal, Id: idVal, + Labels: labelsVal, Name: nameVal, Ram: ramVal, state: attr.ValueStateKnown, @@ -437,6 +502,24 @@ func NewNodeFlavorValue(attributeTypes map[string]attr.Type, attributes map[stri fmt.Sprintf(`ephemeral expected to be basetypes.Int64Value, was: %T`, ephemeralAttribute)) } + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return NewNodeFlavorValueUnknown(), diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + gpuAttribute, ok := attributes["gpu"] if !ok { @@ -491,6 +574,24 @@ func NewNodeFlavorValue(attributeTypes map[string]attr.Type, attributes map[stri fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) } + labelsAttribute, ok := attributes["labels"] + + if !ok { + diags.AddError( + "Attribute Missing", + `labels is missing from object`) + + return NewNodeFlavorValueUnknown(), diags + } + + labelsVal, ok := labelsAttribute.(basetypes.ListValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`labels expected to be basetypes.ListValue, was: %T`, labelsAttribute)) + } + nameAttribute, ok := attributes["name"] if !ok { @@ -535,9 +636,11 @@ func NewNodeFlavorValue(attributeTypes map[string]attr.Type, attributes map[stri Cpu: cpuVal, Disk: diskVal, Ephemeral: ephemeralVal, + Features: featuresVal, Gpu: gpuVal, GpuCount: gpuCountVal, Id: idVal, + Labels: labelsVal, Name: nameVal, Ram: ramVal, state: attr.ValueStateKnown, @@ -615,16 +718,18 @@ type NodeFlavorValue struct { Cpu basetypes.Int64Value `tfsdk:"cpu"` Disk basetypes.Int64Value `tfsdk:"disk"` Ephemeral basetypes.Int64Value `tfsdk:"ephemeral"` + Features basetypes.ObjectValue `tfsdk:"features"` Gpu basetypes.StringValue `tfsdk:"gpu"` GpuCount basetypes.Int64Value `tfsdk:"gpu_count"` Id basetypes.Int64Value `tfsdk:"id"` + Labels basetypes.ListValue `tfsdk:"labels"` Name basetypes.StringValue `tfsdk:"name"` Ram basetypes.NumberValue `tfsdk:"ram"` state attr.ValueState } func (v NodeFlavorValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { - attrTypes := make(map[string]tftypes.Type, 8) + attrTypes := make(map[string]tftypes.Type, 10) var val tftypes.Value var err error @@ -632,9 +737,15 @@ func (v NodeFlavorValue) ToTerraformValue(ctx context.Context) (tftypes.Value, e attrTypes["cpu"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["disk"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["ephemeral"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["features"] = basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }.TerraformType(ctx) attrTypes["gpu"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["gpu_count"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["labels"] = basetypes.ListType{ + ElemType: LabelsValue{}.Type(ctx), + }.TerraformType(ctx) attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["ram"] = basetypes.NumberType{}.TerraformType(ctx) @@ -642,7 +753,7 @@ func (v NodeFlavorValue) ToTerraformValue(ctx context.Context) (tftypes.Value, e switch v.state { case attr.ValueStateKnown: - vals := make(map[string]tftypes.Value, 8) + vals := make(map[string]tftypes.Value, 10) val, err = v.Cpu.ToTerraformValue(ctx) @@ -668,6 +779,14 @@ func (v NodeFlavorValue) ToTerraformValue(ctx context.Context) (tftypes.Value, e vals["ephemeral"] = val + val, err = v.Features.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["features"] = val + val, err = v.Gpu.ToTerraformValue(ctx) if err != nil { @@ -692,6 +811,14 @@ func (v NodeFlavorValue) ToTerraformValue(ctx context.Context) (tftypes.Value, e vals["id"] = val + val, err = v.Labels.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["labels"] = val + val, err = v.Name.ToTerraformValue(ctx) if err != nil { @@ -737,15 +864,71 @@ func (v NodeFlavorValue) String() string { func (v NodeFlavorValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { var diags diag.Diagnostics + var features basetypes.ObjectValue + + if v.Features.IsNull() { + features = types.ObjectNull( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if v.Features.IsUnknown() { + features = types.ObjectUnknown( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if !v.Features.IsNull() && !v.Features.IsUnknown() { + features = types.ObjectValueMust( + FeaturesValue{}.AttributeTypes(ctx), + v.Features.Attributes(), + ) + } + + labels := types.ListValueMust( + LabelsType{ + basetypes.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + v.Labels.Elements(), + ) + + if v.Labels.IsNull() { + labels = types.ListNull( + LabelsType{ + basetypes.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + ) + } + + if v.Labels.IsUnknown() { + labels = types.ListUnknown( + LabelsType{ + basetypes.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + ) + } + attributeTypes := map[string]attr.Type{ "cpu": basetypes.Int64Type{}, "disk": basetypes.Int64Type{}, "ephemeral": basetypes.Int64Type{}, + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, "gpu": basetypes.StringType{}, "gpu_count": basetypes.Int64Type{}, "id": basetypes.Int64Type{}, - "name": basetypes.StringType{}, - "ram": basetypes.NumberType{}, + "labels": basetypes.ListType{ + ElemType: LabelsValue{}.Type(ctx), + }, + "name": basetypes.StringType{}, + "ram": basetypes.NumberType{}, } if v.IsNull() { @@ -762,9 +945,11 @@ func (v NodeFlavorValue) ToObjectValue(ctx context.Context) (basetypes.ObjectVal "cpu": v.Cpu, "disk": v.Disk, "ephemeral": v.Ephemeral, + "features": features, "gpu": v.Gpu, "gpu_count": v.GpuCount, "id": v.Id, + "labels": labels, "name": v.Name, "ram": v.Ram, }) @@ -799,6 +984,10 @@ func (v NodeFlavorValue) Equal(o attr.Value) bool { return false } + if !v.Features.Equal(other.Features) { + return false + } + if !v.Gpu.Equal(other.Gpu) { return false } @@ -811,6 +1000,10 @@ func (v NodeFlavorValue) Equal(o attr.Value) bool { return false } + if !v.Labels.Equal(other.Labels) { + return false + } + if !v.Name.Equal(other.Name) { return false } @@ -835,10 +1028,655 @@ func (v NodeFlavorValue) AttributeTypes(ctx context.Context) map[string]attr.Typ "cpu": basetypes.Int64Type{}, "disk": basetypes.Int64Type{}, "ephemeral": basetypes.Int64Type{}, + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, "gpu": basetypes.StringType{}, "gpu_count": basetypes.Int64Type{}, "id": basetypes.Int64Type{}, - "name": basetypes.StringType{}, - "ram": basetypes.NumberType{}, + "labels": basetypes.ListType{ + ElemType: LabelsValue{}.Type(ctx), + }, + "name": basetypes.StringType{}, + "ram": basetypes.NumberType{}, + } +} + +var _ basetypes.ObjectTypable = FeaturesType{} + +type FeaturesType struct { + basetypes.ObjectType +} + +func (t FeaturesType) Equal(o attr.Type) bool { + other, ok := o.(FeaturesType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t FeaturesType) String() string { + return "FeaturesType" +} + +func (t FeaturesType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + if diags.HasError() { + return nil, diags + } + + return FeaturesValue{ + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueNull() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateNull, + } +} + +func NewFeaturesValueUnknown() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateUnknown, + } +} + +func NewFeaturesValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (FeaturesValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing FeaturesValue Attribute Value", + "While creating a FeaturesValue value, a missing attribute value was detected. "+ + "A FeaturesValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid FeaturesValue Attribute Type", + "While creating a FeaturesValue value, an invalid attribute value was detected. "+ + "A FeaturesValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra FeaturesValue Attribute Value", + "While creating a FeaturesValue value, an extra attribute value was detected. "+ + "A FeaturesValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra FeaturesValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + return FeaturesValue{ + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) FeaturesValue { + object, diags := NewFeaturesValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewFeaturesValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t FeaturesType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewFeaturesValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewFeaturesValueUnknown(), nil + } + + if in.IsNull() { + return NewFeaturesValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewFeaturesValueMust(FeaturesValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t FeaturesType) ValueType(ctx context.Context) attr.Value { + return FeaturesValue{} +} + +var _ basetypes.ObjectValuable = FeaturesValue{} + +type FeaturesValue struct { + state attr.ValueState +} + +func (v FeaturesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 0) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 0) + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v FeaturesValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v FeaturesValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v FeaturesValue) String() string { + return "FeaturesValue" +} + +func (v FeaturesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + attributeTypes := map[string]attr.Type{} + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{}) + + return objVal, diags +} + +func (v FeaturesValue) Equal(o attr.Value) bool { + other, ok := o.(FeaturesValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + return true +} + +func (v FeaturesValue) Type(ctx context.Context) attr.Type { + return FeaturesType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v FeaturesValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{} +} + +var _ basetypes.ObjectTypable = LabelsType{} + +type LabelsType struct { + basetypes.ObjectType +} + +func (t LabelsType) Equal(o attr.Type) bool { + other, ok := o.(LabelsType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t LabelsType) String() string { + return "LabelsType" +} + +func (t LabelsType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + attributes := in.Attributes() + + idAttribute, ok := attributes["id"] + + if !ok { + diags.AddError( + "Attribute Missing", + `id is missing from object`) + + return nil, diags + } + + idVal, ok := idAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) + } + + labelAttribute, ok := attributes["label"] + + if !ok { + diags.AddError( + "Attribute Missing", + `label is missing from object`) + + return nil, diags + } + + labelVal, ok := labelAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`label expected to be basetypes.StringValue, was: %T`, labelAttribute)) + } + + if diags.HasError() { + return nil, diags + } + + return LabelsValue{ + Id: idVal, + Label: labelVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewLabelsValueNull() LabelsValue { + return LabelsValue{ + state: attr.ValueStateNull, + } +} + +func NewLabelsValueUnknown() LabelsValue { + return LabelsValue{ + state: attr.ValueStateUnknown, + } +} + +func NewLabelsValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (LabelsValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing LabelsValue Attribute Value", + "While creating a LabelsValue value, a missing attribute value was detected. "+ + "A LabelsValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("LabelsValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid LabelsValue Attribute Type", + "While creating a LabelsValue value, an invalid attribute value was detected. "+ + "A LabelsValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("LabelsValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("LabelsValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra LabelsValue Attribute Value", + "While creating a LabelsValue value, an extra attribute value was detected. "+ + "A LabelsValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra LabelsValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewLabelsValueUnknown(), diags + } + + idAttribute, ok := attributes["id"] + + if !ok { + diags.AddError( + "Attribute Missing", + `id is missing from object`) + + return NewLabelsValueUnknown(), diags + } + + idVal, ok := idAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) + } + + labelAttribute, ok := attributes["label"] + + if !ok { + diags.AddError( + "Attribute Missing", + `label is missing from object`) + + return NewLabelsValueUnknown(), diags + } + + labelVal, ok := labelAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`label expected to be basetypes.StringValue, was: %T`, labelAttribute)) + } + + if diags.HasError() { + return NewLabelsValueUnknown(), diags + } + + return LabelsValue{ + Id: idVal, + Label: labelVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewLabelsValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) LabelsValue { + object, diags := NewLabelsValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewLabelsValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t LabelsType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewLabelsValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewLabelsValueUnknown(), nil + } + + if in.IsNull() { + return NewLabelsValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewLabelsValueMust(LabelsValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t LabelsType) ValueType(ctx context.Context) attr.Value { + return LabelsValue{} +} + +var _ basetypes.ObjectValuable = LabelsValue{} + +type LabelsValue struct { + Id basetypes.Int64Value `tfsdk:"id"` + Label basetypes.StringValue `tfsdk:"label"` + state attr.ValueState +} + +func (v LabelsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 2) + + var val tftypes.Value + var err error + + attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["label"] = basetypes.StringType{}.TerraformType(ctx) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 2) + + val, err = v.Id.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["id"] = val + + val, err = v.Label.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["label"] = val + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v LabelsValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v LabelsValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v LabelsValue) String() string { + return "LabelsValue" +} + +func (v LabelsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + attributeTypes := map[string]attr.Type{ + "id": basetypes.Int64Type{}, + "label": basetypes.StringType{}, + } + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{ + "id": v.Id, + "label": v.Label, + }) + + return objVal, diags +} + +func (v LabelsValue) Equal(o attr.Value) bool { + other, ok := o.(LabelsValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + if !v.Id.Equal(other.Id) { + return false + } + + if !v.Label.Equal(other.Label) { + return false + } + + return true +} + +func (v LabelsValue) Type(ctx context.Context) attr.Type { + return LabelsType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v LabelsValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{ + "id": basetypes.Int64Type{}, + "label": basetypes.StringType{}, } } diff --git a/internal/genprovider/resource_core_environment/core_environment_resource_gen.go b/internal/genprovider/resource_core_environment/core_environment_resource_gen.go index 66c6f3d..2098c5b 100644 --- a/internal/genprovider/resource_core_environment/core_environment_resource_gen.go +++ b/internal/genprovider/resource_core_environment/core_environment_resource_gen.go @@ -4,9 +4,15 @@ package resource_core_environment import ( "context" + "fmt" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "github.com/hashicorp/terraform-plugin-go/tftypes" + "strings" "github.com/hashicorp/terraform-plugin-framework/resource/schema" ) @@ -17,6 +23,22 @@ func CoreEnvironmentResourceSchema(ctx context.Context) schema.Schema { "created_at": schema.StringAttribute{ Computed: true, }, + "features": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "green_status": schema.StringAttribute{ + Computed: true, + }, + "network_optimised": schema.BoolAttribute{ + Computed: true, + }, + }, + CustomType: FeaturesType{ + ObjectType: types.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + }, + Computed: true, + }, "id": schema.Int64Attribute{ Computed: true, }, @@ -38,8 +60,388 @@ func CoreEnvironmentResourceSchema(ctx context.Context) schema.Schema { } type CoreEnvironmentModel struct { - CreatedAt types.String `tfsdk:"created_at"` - Id types.Int64 `tfsdk:"id"` - Name types.String `tfsdk:"name"` - Region types.String `tfsdk:"region"` + CreatedAt types.String `tfsdk:"created_at"` + Features FeaturesValue `tfsdk:"features"` + Id types.Int64 `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Region types.String `tfsdk:"region"` +} + +var _ basetypes.ObjectTypable = FeaturesType{} + +type FeaturesType struct { + basetypes.ObjectType +} + +func (t FeaturesType) Equal(o attr.Type) bool { + other, ok := o.(FeaturesType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t FeaturesType) String() string { + return "FeaturesType" +} + +func (t FeaturesType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + attributes := in.Attributes() + + greenStatusAttribute, ok := attributes["green_status"] + + if !ok { + diags.AddError( + "Attribute Missing", + `green_status is missing from object`) + + return nil, diags + } + + greenStatusVal, ok := greenStatusAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`green_status expected to be basetypes.StringValue, was: %T`, greenStatusAttribute)) + } + + networkOptimisedAttribute, ok := attributes["network_optimised"] + + if !ok { + diags.AddError( + "Attribute Missing", + `network_optimised is missing from object`) + + return nil, diags + } + + networkOptimisedVal, ok := networkOptimisedAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`network_optimised expected to be basetypes.BoolValue, was: %T`, networkOptimisedAttribute)) + } + + if diags.HasError() { + return nil, diags + } + + return FeaturesValue{ + GreenStatus: greenStatusVal, + NetworkOptimised: networkOptimisedVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueNull() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateNull, + } +} + +func NewFeaturesValueUnknown() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateUnknown, + } +} + +func NewFeaturesValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (FeaturesValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing FeaturesValue Attribute Value", + "While creating a FeaturesValue value, a missing attribute value was detected. "+ + "A FeaturesValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid FeaturesValue Attribute Type", + "While creating a FeaturesValue value, an invalid attribute value was detected. "+ + "A FeaturesValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra FeaturesValue Attribute Value", + "While creating a FeaturesValue value, an extra attribute value was detected. "+ + "A FeaturesValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra FeaturesValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + greenStatusAttribute, ok := attributes["green_status"] + + if !ok { + diags.AddError( + "Attribute Missing", + `green_status is missing from object`) + + return NewFeaturesValueUnknown(), diags + } + + greenStatusVal, ok := greenStatusAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`green_status expected to be basetypes.StringValue, was: %T`, greenStatusAttribute)) + } + + networkOptimisedAttribute, ok := attributes["network_optimised"] + + if !ok { + diags.AddError( + "Attribute Missing", + `network_optimised is missing from object`) + + return NewFeaturesValueUnknown(), diags + } + + networkOptimisedVal, ok := networkOptimisedAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`network_optimised expected to be basetypes.BoolValue, was: %T`, networkOptimisedAttribute)) + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + return FeaturesValue{ + GreenStatus: greenStatusVal, + NetworkOptimised: networkOptimisedVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) FeaturesValue { + object, diags := NewFeaturesValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewFeaturesValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t FeaturesType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewFeaturesValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewFeaturesValueUnknown(), nil + } + + if in.IsNull() { + return NewFeaturesValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewFeaturesValueMust(FeaturesValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t FeaturesType) ValueType(ctx context.Context) attr.Value { + return FeaturesValue{} +} + +var _ basetypes.ObjectValuable = FeaturesValue{} + +type FeaturesValue struct { + GreenStatus basetypes.StringValue `tfsdk:"green_status"` + NetworkOptimised basetypes.BoolValue `tfsdk:"network_optimised"` + state attr.ValueState +} + +func (v FeaturesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 2) + + var val tftypes.Value + var err error + + attrTypes["green_status"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["network_optimised"] = basetypes.BoolType{}.TerraformType(ctx) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 2) + + val, err = v.GreenStatus.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["green_status"] = val + + val, err = v.NetworkOptimised.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["network_optimised"] = val + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v FeaturesValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v FeaturesValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v FeaturesValue) String() string { + return "FeaturesValue" +} + +func (v FeaturesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + attributeTypes := map[string]attr.Type{ + "green_status": basetypes.StringType{}, + "network_optimised": basetypes.BoolType{}, + } + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{ + "green_status": v.GreenStatus, + "network_optimised": v.NetworkOptimised, + }) + + return objVal, diags +} + +func (v FeaturesValue) Equal(o attr.Value) bool { + other, ok := o.(FeaturesValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + if !v.GreenStatus.Equal(other.GreenStatus) { + return false + } + + if !v.NetworkOptimised.Equal(other.NetworkOptimised) { + return false + } + + return true +} + +func (v FeaturesValue) Type(ctx context.Context) attr.Type { + return FeaturesType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v FeaturesValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{ + "green_status": basetypes.StringType{}, + "network_optimised": basetypes.BoolType{}, + } } diff --git a/internal/genprovider/resource_core_virtual_machine/core_virtual_machine_resource_gen.go b/internal/genprovider/resource_core_virtual_machine/core_virtual_machine_resource_gen.go index 128236a..43b71fc 100644 --- a/internal/genprovider/resource_core_virtual_machine/core_virtual_machine_resource_gen.go +++ b/internal/genprovider/resource_core_virtual_machine/core_virtual_machine_resource_gen.go @@ -31,8 +31,8 @@ func CoreVirtualMachineResourceSchema(ctx context.Context) schema.Schema { "assign_floating_ip": schema.BoolAttribute{ Optional: true, Computed: true, - Description: "When this field is set to `true`, it attaches a [public IP address](https://infrahub-doc.nexgencloud.com/docs/virtual-machines/public-ip) to the virtual machine, enabling internet accessibility.", - MarkdownDescription: "When this field is set to `true`, it attaches a [public IP address](https://infrahub-doc.nexgencloud.com/docs/virtual-machines/public-ip) to the virtual machine, enabling internet accessibility.", + Description: "When this field is set to `true`, it attaches a [public IP address](https://infrahub-doc.nexgencloud.com/docs/virtual-machines/public-ip)to the virtual machine, enabling internet accessibility.", + MarkdownDescription: "When this field is set to `true`, it attaches a [public IP address](https://infrahub-doc.nexgencloud.com/docs/virtual-machines/public-ip)to the virtual machine, enabling internet accessibility.", PlanModifiers: []planmodifier.Bool{ boolplanmodifier.RequiresReplace(), }, @@ -65,8 +65,31 @@ func CoreVirtualMachineResourceSchema(ctx context.Context) schema.Schema { stringplanmodifier.UseStateForUnknown(), }, }, + "enable_port_randomization": schema.BoolAttribute{ + Optional: true, + Computed: true, + Description: "Indicates whether to enable port randomization.This setting is only effective if 'assign_floating_ip' is true. Defaults to true.", + MarkdownDescription: "Indicates whether to enable port randomization.This setting is only effective if 'assign_floating_ip' is true. Defaults to true.", + Default: booldefault.StaticBool(true), + }, "environment": schema.SingleNestedAttribute{ Attributes: map[string]schema.Attribute{ + "features": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "green_status": schema.StringAttribute{ + Computed: true, + }, + "network_optimised": schema.BoolAttribute{ + Computed: true, + }, + }, + CustomType: FeaturesType{ + ObjectType: types.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + }, + Computed: true, + }, "id": schema.Int64Attribute{ Computed: true, }, @@ -95,6 +118,15 @@ func CoreVirtualMachineResourceSchema(ctx context.Context) schema.Schema { stringplanmodifier.RequiresReplace(), }, }, + "features": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{}, + CustomType: FeaturesType{ + ObjectType: types.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + }, + Computed: true, + }, "fixed_ip": schema.StringAttribute{ Computed: true, PlanModifiers: []planmodifier.String{ @@ -112,6 +144,15 @@ func CoreVirtualMachineResourceSchema(ctx context.Context) schema.Schema { "ephemeral": schema.Int64Attribute{ Computed: true, }, + "features": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{}, + CustomType: FeaturesType{ + ObjectType: types.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + }, + Computed: true, + }, "gpu": schema.StringAttribute{ Computed: true, }, @@ -121,6 +162,24 @@ func CoreVirtualMachineResourceSchema(ctx context.Context) schema.Schema { "id": schema.Int64Attribute{ Computed: true, }, + "labels": schema.ListNestedAttribute{ + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "id": schema.Int64Attribute{ + Computed: true, + }, + "label": schema.StringAttribute{ + Computed: true, + }, + }, + CustomType: LabelsType{ + ObjectType: types.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + }, + Computed: true, + }, "name": schema.StringAttribute{ Computed: true, }, @@ -177,8 +236,8 @@ func CoreVirtualMachineResourceSchema(ctx context.Context) schema.Schema { "image_name": schema.StringAttribute{ Optional: true, Computed: true, - Description: "The [operating system (OS) image](https://infrahub-doc.nexgencloud.com/docs/virtual-machines/images) name designated for installation on the virtual machine.", - MarkdownDescription: "The [operating system (OS) image](https://infrahub-doc.nexgencloud.com/docs/virtual-machines/images) name designated for installation on the virtual machine.", + Description: "The [operating system (OS) image](https://infrahub-doc.nexgencloud.com/docs/virtual-machines/images) name designated for installation on the virtual machine.It also accepts custom, private images, created from [existing snapshots](https://infrahub-doc.nexgencloud.com/docs/virtual-machines/custom-images).", + MarkdownDescription: "The [operating system (OS) image](https://infrahub-doc.nexgencloud.com/docs/virtual-machines/images) name designated for installation on the virtual machine.It also accepts custom, private images, created from [existing snapshots](https://infrahub-doc.nexgencloud.com/docs/virtual-machines/custom-images).", PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, @@ -233,12 +292,21 @@ func CoreVirtualMachineResourceSchema(ctx context.Context) schema.Schema { stringplanmodifier.UseStateForUnknown(), }, }, + "port_randomization": schema.BoolAttribute{ + Computed: true, + }, + "port_randomization_status": schema.StringAttribute{ + Computed: true, + }, "power_state": schema.StringAttribute{ Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), }, }, + "requires_public_ip": schema.BoolAttribute{ + Computed: true, + }, "security_rules": schema.ListNestedAttribute{ NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ @@ -367,6 +435,10 @@ func CoreVirtualMachineResourceSchema(ctx context.Context) schema.Schema { stringplanmodifier.UseStateForUnknown(), }, }, + "vm_id": schema.Int64Attribute{ + Optional: true, + Computed: true, + }, "vm_state": schema.StringAttribute{ Computed: true, PlanModifiers: []planmodifier.String{ @@ -396,6 +468,12 @@ func CoreVirtualMachineResourceSchema(ctx context.Context) schema.Schema { }, "volume": schema.SingleNestedAttribute{ Attributes: map[string]schema.Attribute{ + "bootable": schema.BoolAttribute{ + Computed: true, + PlanModifiers: []planmodifier.Bool{ + boolplanmodifier.RequiresReplace(), + }, + }, "description": schema.StringAttribute{ Computed: true, PlanModifiers: []planmodifier.String{ @@ -488,34 +566,40 @@ func CoreVirtualMachineResourceSchema(ctx context.Context) schema.Schema { } type CoreVirtualMachineModel struct { - AssignFloatingIp types.Bool `tfsdk:"assign_floating_ip"` - CallbackUrl types.String `tfsdk:"callback_url"` - CreateBootableVolume types.Bool `tfsdk:"create_bootable_volume"` - CreatedAt types.String `tfsdk:"created_at"` - Environment EnvironmentValue `tfsdk:"environment"` - EnvironmentName types.String `tfsdk:"environment_name"` - FixedIp types.String `tfsdk:"fixed_ip"` - Flavor FlavorValue `tfsdk:"flavor"` - FlavorName types.String `tfsdk:"flavor_name"` - FloatingIp types.String `tfsdk:"floating_ip"` - FloatingIpStatus types.String `tfsdk:"floating_ip_status"` - Id types.Int64 `tfsdk:"id"` - Image ImageValue `tfsdk:"image"` - ImageName types.String `tfsdk:"image_name"` - KeyName types.String `tfsdk:"key_name"` - Keypair KeypairValue `tfsdk:"keypair"` - Labels types.List `tfsdk:"labels"` - Locked types.Bool `tfsdk:"locked"` - Name types.String `tfsdk:"name"` - Os types.String `tfsdk:"os"` - PowerState types.String `tfsdk:"power_state"` - SecurityRules types.List `tfsdk:"security_rules"` - Status types.String `tfsdk:"status"` - UserData types.String `tfsdk:"user_data"` - VmState types.String `tfsdk:"vm_state"` - VolumeAttachments types.List `tfsdk:"volume_attachments"` - VolumeName types.String `tfsdk:"volume_name"` - Profile types.List `tfsdk:"profile"` + AssignFloatingIp types.Bool `tfsdk:"assign_floating_ip"` + CallbackUrl types.String `tfsdk:"callback_url"` + CreateBootableVolume types.Bool `tfsdk:"create_bootable_volume"` + CreatedAt types.String `tfsdk:"created_at"` + EnablePortRandomization types.Bool `tfsdk:"enable_port_randomization"` + Environment EnvironmentValue `tfsdk:"environment"` + EnvironmentName types.String `tfsdk:"environment_name"` + Features FeaturesValue `tfsdk:"features"` + FixedIp types.String `tfsdk:"fixed_ip"` + Flavor FlavorValue `tfsdk:"flavor"` + FlavorName types.String `tfsdk:"flavor_name"` + FloatingIp types.String `tfsdk:"floating_ip"` + FloatingIpStatus types.String `tfsdk:"floating_ip_status"` + Id types.Int64 `tfsdk:"id"` + Image ImageValue `tfsdk:"image"` + ImageName types.String `tfsdk:"image_name"` + KeyName types.String `tfsdk:"key_name"` + Keypair KeypairValue `tfsdk:"keypair"` + Labels types.List `tfsdk:"labels"` + Locked types.Bool `tfsdk:"locked"` + Name types.String `tfsdk:"name"` + Os types.String `tfsdk:"os"` + PortRandomization types.Bool `tfsdk:"port_randomization"` + PortRandomizationStatus types.String `tfsdk:"port_randomization_status"` + PowerState types.String `tfsdk:"power_state"` + RequiresPublicIp types.Bool `tfsdk:"requires_public_ip"` + SecurityRules types.List `tfsdk:"security_rules"` + Status types.String `tfsdk:"status"` + UserData types.String `tfsdk:"user_data"` + VmId types.Int64 `tfsdk:"vm_id"` + VmState types.String `tfsdk:"vm_state"` + VolumeAttachments types.List `tfsdk:"volume_attachments"` + VolumeName types.String `tfsdk:"volume_name"` + Profile types.List `tfsdk:"profile"` } var _ basetypes.ObjectTypable = EnvironmentType{} @@ -543,6 +627,24 @@ func (t EnvironmentType) ValueFromObject(ctx context.Context, in basetypes.Objec attributes := in.Attributes() + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return nil, diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + idAttribute, ok := attributes["id"] if !ok { @@ -620,11 +722,12 @@ func (t EnvironmentType) ValueFromObject(ctx context.Context, in basetypes.Objec } return EnvironmentValue{ - Id: idVal, - Name: nameVal, - OrgId: orgIdVal, - Region: regionVal, - state: attr.ValueStateKnown, + Features: featuresVal, + Id: idVal, + Name: nameVal, + OrgId: orgIdVal, + Region: regionVal, + state: attr.ValueStateKnown, }, diags } @@ -691,6 +794,24 @@ func NewEnvironmentValue(attributeTypes map[string]attr.Type, attributes map[str return NewEnvironmentValueUnknown(), diags } + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return NewEnvironmentValueUnknown(), diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + idAttribute, ok := attributes["id"] if !ok { @@ -768,11 +889,12 @@ func NewEnvironmentValue(attributeTypes map[string]attr.Type, attributes map[str } return EnvironmentValue{ - Id: idVal, - Name: nameVal, - OrgId: orgIdVal, - Region: regionVal, - state: attr.ValueStateKnown, + Features: featuresVal, + Id: idVal, + Name: nameVal, + OrgId: orgIdVal, + Region: regionVal, + state: attr.ValueStateKnown, }, diags } @@ -844,19 +966,23 @@ func (t EnvironmentType) ValueType(ctx context.Context) attr.Value { var _ basetypes.ObjectValuable = EnvironmentValue{} type EnvironmentValue struct { - Id basetypes.Int64Value `tfsdk:"id"` - Name basetypes.StringValue `tfsdk:"name"` - OrgId basetypes.Int64Value `tfsdk:"org_id"` - Region basetypes.StringValue `tfsdk:"region"` - state attr.ValueState + Features basetypes.ObjectValue `tfsdk:"features"` + Id basetypes.Int64Value `tfsdk:"id"` + Name basetypes.StringValue `tfsdk:"name"` + OrgId basetypes.Int64Value `tfsdk:"org_id"` + Region basetypes.StringValue `tfsdk:"region"` + state attr.ValueState } func (v EnvironmentValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { - attrTypes := make(map[string]tftypes.Type, 4) + attrTypes := make(map[string]tftypes.Type, 5) var val tftypes.Value var err error + attrTypes["features"] = basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }.TerraformType(ctx) attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["org_id"] = basetypes.Int64Type{}.TerraformType(ctx) @@ -866,7 +992,15 @@ func (v EnvironmentValue) ToTerraformValue(ctx context.Context) (tftypes.Value, switch v.state { case attr.ValueStateKnown: - vals := make(map[string]tftypes.Value, 4) + vals := make(map[string]tftypes.Value, 5) + + val, err = v.Features.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["features"] = val val, err = v.Id.ToTerraformValue(ctx) @@ -929,7 +1063,31 @@ func (v EnvironmentValue) String() string { func (v EnvironmentValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { var diags diag.Diagnostics + var features basetypes.ObjectValue + + if v.Features.IsNull() { + features = types.ObjectNull( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if v.Features.IsUnknown() { + features = types.ObjectUnknown( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if !v.Features.IsNull() && !v.Features.IsUnknown() { + features = types.ObjectValueMust( + FeaturesValue{}.AttributeTypes(ctx), + v.Features.Attributes(), + ) + } + attributeTypes := map[string]attr.Type{ + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, "id": basetypes.Int64Type{}, "name": basetypes.StringType{}, "org_id": basetypes.Int64Type{}, @@ -947,10 +1105,11 @@ func (v EnvironmentValue) ToObjectValue(ctx context.Context) (basetypes.ObjectVa objVal, diags := types.ObjectValue( attributeTypes, map[string]attr.Value{ - "id": v.Id, - "name": v.Name, - "org_id": v.OrgId, - "region": v.Region, + "features": features, + "id": v.Id, + "name": v.Name, + "org_id": v.OrgId, + "region": v.Region, }) return objVal, diags @@ -971,6 +1130,10 @@ func (v EnvironmentValue) Equal(o attr.Value) bool { return true } + if !v.Features.Equal(other.Features) { + return false + } + if !v.Id.Equal(other.Id) { return false } @@ -1000,6 +1163,9 @@ func (v EnvironmentValue) Type(ctx context.Context) attr.Type { func (v EnvironmentValue) AttributeTypes(ctx context.Context) map[string]attr.Type { return map[string]attr.Type{ + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, "id": basetypes.Int64Type{}, "name": basetypes.StringType{}, "org_id": basetypes.Int64Type{}, @@ -1007,14 +1173,14 @@ func (v EnvironmentValue) AttributeTypes(ctx context.Context) map[string]attr.Ty } } -var _ basetypes.ObjectTypable = FlavorType{} +var _ basetypes.ObjectTypable = FeaturesType{} -type FlavorType struct { +type FeaturesType struct { basetypes.ObjectType } -func (t FlavorType) Equal(o attr.Type) bool { - other, ok := o.(FlavorType) +func (t FeaturesType) Equal(o attr.Type) bool { + other, ok := o.(FeaturesType) if !ok { return false @@ -1023,189 +1189,75 @@ func (t FlavorType) Equal(o attr.Type) bool { return t.ObjectType.Equal(other.ObjectType) } -func (t FlavorType) String() string { - return "FlavorType" +func (t FeaturesType) String() string { + return "FeaturesType" } -func (t FlavorType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { +func (t FeaturesType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { var diags diag.Diagnostics attributes := in.Attributes() - cpuAttribute, ok := attributes["cpu"] - - if !ok { - diags.AddError( - "Attribute Missing", - `cpu is missing from object`) - - return nil, diags - } - - cpuVal, ok := cpuAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`cpu expected to be basetypes.Int64Value, was: %T`, cpuAttribute)) - } - - diskAttribute, ok := attributes["disk"] - - if !ok { - diags.AddError( - "Attribute Missing", - `disk is missing from object`) - - return nil, diags - } - - diskVal, ok := diskAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`disk expected to be basetypes.Int64Value, was: %T`, diskAttribute)) - } - - ephemeralAttribute, ok := attributes["ephemeral"] - - if !ok { - diags.AddError( - "Attribute Missing", - `ephemeral is missing from object`) - - return nil, diags - } - - ephemeralVal, ok := ephemeralAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`ephemeral expected to be basetypes.Int64Value, was: %T`, ephemeralAttribute)) - } - - gpuAttribute, ok := attributes["gpu"] - - if !ok { - diags.AddError( - "Attribute Missing", - `gpu is missing from object`) - - return nil, diags - } - - gpuVal, ok := gpuAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`gpu expected to be basetypes.StringValue, was: %T`, gpuAttribute)) - } - - gpuCountAttribute, ok := attributes["gpu_count"] - - if !ok { - diags.AddError( - "Attribute Missing", - `gpu_count is missing from object`) - - return nil, diags - } - - gpuCountVal, ok := gpuCountAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`gpu_count expected to be basetypes.Int64Value, was: %T`, gpuCountAttribute)) - } - - idAttribute, ok := attributes["id"] - - if !ok { - diags.AddError( - "Attribute Missing", - `id is missing from object`) - - return nil, diags - } - - idVal, ok := idAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) - } - - nameAttribute, ok := attributes["name"] + greenStatusAttribute, ok := attributes["green_status"] if !ok { diags.AddError( "Attribute Missing", - `name is missing from object`) + `green_status is missing from object`) return nil, diags } - nameVal, ok := nameAttribute.(basetypes.StringValue) + greenStatusVal, ok := greenStatusAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", - fmt.Sprintf(`name expected to be basetypes.StringValue, was: %T`, nameAttribute)) + fmt.Sprintf(`green_status expected to be basetypes.StringValue, was: %T`, greenStatusAttribute)) } - ramAttribute, ok := attributes["ram"] + networkOptimisedAttribute, ok := attributes["network_optimised"] if !ok { diags.AddError( "Attribute Missing", - `ram is missing from object`) + `network_optimised is missing from object`) return nil, diags } - ramVal, ok := ramAttribute.(basetypes.NumberValue) + networkOptimisedVal, ok := networkOptimisedAttribute.(basetypes.BoolValue) if !ok { diags.AddError( "Attribute Wrong Type", - fmt.Sprintf(`ram expected to be basetypes.NumberValue, was: %T`, ramAttribute)) + fmt.Sprintf(`network_optimised expected to be basetypes.BoolValue, was: %T`, networkOptimisedAttribute)) } if diags.HasError() { return nil, diags } - return FlavorValue{ - Cpu: cpuVal, - Disk: diskVal, - Ephemeral: ephemeralVal, - Gpu: gpuVal, - GpuCount: gpuCountVal, - Id: idVal, - Name: nameVal, - Ram: ramVal, - state: attr.ValueStateKnown, + return FeaturesValue{ + GreenStatus: greenStatusVal, + NetworkOptimised: networkOptimisedVal, + state: attr.ValueStateKnown, }, diags } -func NewFlavorValueNull() FlavorValue { - return FlavorValue{ +func NewFeaturesValueNull() FeaturesValue { + return FeaturesValue{ state: attr.ValueStateNull, } } -func NewFlavorValueUnknown() FlavorValue { - return FlavorValue{ +func NewFeaturesValueUnknown() FeaturesValue { + return FeaturesValue{ state: attr.ValueStateUnknown, } } -func NewFlavorValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (FlavorValue, diag.Diagnostics) { +func NewFeaturesValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (FeaturesValue, diag.Diagnostics) { var diags diag.Diagnostics // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 @@ -1216,11 +1268,11 @@ func NewFlavorValue(attributeTypes map[string]attr.Type, attributes map[string]a if !ok { diags.AddError( - "Missing FlavorValue Attribute Value", - "While creating a FlavorValue value, a missing attribute value was detected. "+ - "A FlavorValue must contain values for all attributes, even if null or unknown. "+ + "Missing FeaturesValue Attribute Value", + "While creating a FeaturesValue value, a missing attribute value was detected. "+ + "A FeaturesValue must contain values for all attributes, even if null or unknown. "+ "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("FlavorValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), ) continue @@ -1228,12 +1280,12 @@ func NewFlavorValue(attributeTypes map[string]attr.Type, attributes map[string]a if !attributeType.Equal(attribute.Type(ctx)) { diags.AddError( - "Invalid FlavorValue Attribute Type", - "While creating a FlavorValue value, an invalid attribute value was detected. "+ - "A FlavorValue must use a matching attribute type for the value. "+ + "Invalid FeaturesValue Attribute Type", + "While creating a FeaturesValue value, an invalid attribute value was detected. "+ + "A FeaturesValue must use a matching attribute type for the value. "+ "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("FlavorValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ - fmt.Sprintf("FlavorValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), ) } } @@ -1243,107 +1295,1797 @@ func NewFlavorValue(attributeTypes map[string]attr.Type, attributes map[string]a if !ok { diags.AddError( - "Extra FlavorValue Attribute Value", - "While creating a FlavorValue value, an extra attribute value was detected. "+ - "A FlavorValue must not contain values beyond the expected attribute types. "+ + "Extra FeaturesValue Attribute Value", + "While creating a FeaturesValue value, an extra attribute value was detected. "+ + "A FeaturesValue must not contain values beyond the expected attribute types. "+ "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("Extra FlavorValue Attribute Name: %s", name), + fmt.Sprintf("Extra FeaturesValue Attribute Name: %s", name), ) } } if diags.HasError() { - return NewFlavorValueUnknown(), diags + return NewFeaturesValueUnknown(), diags } - cpuAttribute, ok := attributes["cpu"] + greenStatusAttribute, ok := attributes["green_status"] if !ok { diags.AddError( "Attribute Missing", - `cpu is missing from object`) + `green_status is missing from object`) - return NewFlavorValueUnknown(), diags + return NewFeaturesValueUnknown(), diags } - cpuVal, ok := cpuAttribute.(basetypes.Int64Value) + greenStatusVal, ok := greenStatusAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", - fmt.Sprintf(`cpu expected to be basetypes.Int64Value, was: %T`, cpuAttribute)) + fmt.Sprintf(`green_status expected to be basetypes.StringValue, was: %T`, greenStatusAttribute)) } - diskAttribute, ok := attributes["disk"] + networkOptimisedAttribute, ok := attributes["network_optimised"] + + if !ok { + diags.AddError( + "Attribute Missing", + `network_optimised is missing from object`) + + return NewFeaturesValueUnknown(), diags + } + + networkOptimisedVal, ok := networkOptimisedAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`network_optimised expected to be basetypes.BoolValue, was: %T`, networkOptimisedAttribute)) + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + return FeaturesValue{ + GreenStatus: greenStatusVal, + NetworkOptimised: networkOptimisedVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) FeaturesValue { + object, diags := NewFeaturesValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewFeaturesValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t FeaturesType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewFeaturesValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewFeaturesValueUnknown(), nil + } + + if in.IsNull() { + return NewFeaturesValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewFeaturesValueMust(FeaturesValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t FeaturesType) ValueType(ctx context.Context) attr.Value { + return FeaturesValue{} +} + +var _ basetypes.ObjectValuable = FeaturesValue{} + +type FeaturesValue struct { + GreenStatus basetypes.StringValue `tfsdk:"green_status"` + NetworkOptimised basetypes.BoolValue `tfsdk:"network_optimised"` + state attr.ValueState +} + +func (v FeaturesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 2) + + var val tftypes.Value + var err error + + attrTypes["green_status"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["network_optimised"] = basetypes.BoolType{}.TerraformType(ctx) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 2) + + val, err = v.GreenStatus.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["green_status"] = val + + val, err = v.NetworkOptimised.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["network_optimised"] = val + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v FeaturesValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v FeaturesValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v FeaturesValue) String() string { + return "FeaturesValue" +} + +func (v FeaturesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + attributeTypes := map[string]attr.Type{ + "green_status": basetypes.StringType{}, + "network_optimised": basetypes.BoolType{}, + } + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{ + "green_status": v.GreenStatus, + "network_optimised": v.NetworkOptimised, + }) + + return objVal, diags +} + +func (v FeaturesValue) Equal(o attr.Value) bool { + other, ok := o.(FeaturesValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + if !v.GreenStatus.Equal(other.GreenStatus) { + return false + } + + if !v.NetworkOptimised.Equal(other.NetworkOptimised) { + return false + } + + return true +} + +func (v FeaturesValue) Type(ctx context.Context) attr.Type { + return FeaturesType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v FeaturesValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{ + "green_status": basetypes.StringType{}, + "network_optimised": basetypes.BoolType{}, + } +} + +var _ basetypes.ObjectTypable = FeaturesType{} + +type FeaturesType struct { + basetypes.ObjectType +} + +func (t FeaturesType) Equal(o attr.Type) bool { + other, ok := o.(FeaturesType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t FeaturesType) String() string { + return "FeaturesType" +} + +func (t FeaturesType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + if diags.HasError() { + return nil, diags + } + + return FeaturesValue{ + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueNull() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateNull, + } +} + +func NewFeaturesValueUnknown() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateUnknown, + } +} + +func NewFeaturesValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (FeaturesValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing FeaturesValue Attribute Value", + "While creating a FeaturesValue value, a missing attribute value was detected. "+ + "A FeaturesValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid FeaturesValue Attribute Type", + "While creating a FeaturesValue value, an invalid attribute value was detected. "+ + "A FeaturesValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra FeaturesValue Attribute Value", + "While creating a FeaturesValue value, an extra attribute value was detected. "+ + "A FeaturesValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra FeaturesValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + return FeaturesValue{ + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) FeaturesValue { + object, diags := NewFeaturesValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewFeaturesValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t FeaturesType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewFeaturesValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewFeaturesValueUnknown(), nil + } + + if in.IsNull() { + return NewFeaturesValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewFeaturesValueMust(FeaturesValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t FeaturesType) ValueType(ctx context.Context) attr.Value { + return FeaturesValue{} +} + +var _ basetypes.ObjectValuable = FeaturesValue{} + +type FeaturesValue struct { + state attr.ValueState +} + +func (v FeaturesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 0) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 0) + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v FeaturesValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v FeaturesValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v FeaturesValue) String() string { + return "FeaturesValue" +} + +func (v FeaturesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + attributeTypes := map[string]attr.Type{} + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{}) + + return objVal, diags +} + +func (v FeaturesValue) Equal(o attr.Value) bool { + other, ok := o.(FeaturesValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + return true +} + +func (v FeaturesValue) Type(ctx context.Context) attr.Type { + return FeaturesType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v FeaturesValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{} +} + +var _ basetypes.ObjectTypable = FlavorType{} + +type FlavorType struct { + basetypes.ObjectType +} + +func (t FlavorType) Equal(o attr.Type) bool { + other, ok := o.(FlavorType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t FlavorType) String() string { + return "FlavorType" +} + +func (t FlavorType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + attributes := in.Attributes() + + cpuAttribute, ok := attributes["cpu"] + + if !ok { + diags.AddError( + "Attribute Missing", + `cpu is missing from object`) + + return nil, diags + } + + cpuVal, ok := cpuAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`cpu expected to be basetypes.Int64Value, was: %T`, cpuAttribute)) + } + + diskAttribute, ok := attributes["disk"] + + if !ok { + diags.AddError( + "Attribute Missing", + `disk is missing from object`) + + return nil, diags + } + + diskVal, ok := diskAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`disk expected to be basetypes.Int64Value, was: %T`, diskAttribute)) + } + + ephemeralAttribute, ok := attributes["ephemeral"] + + if !ok { + diags.AddError( + "Attribute Missing", + `ephemeral is missing from object`) + + return nil, diags + } + + ephemeralVal, ok := ephemeralAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`ephemeral expected to be basetypes.Int64Value, was: %T`, ephemeralAttribute)) + } + + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return nil, diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + + gpuAttribute, ok := attributes["gpu"] + + if !ok { + diags.AddError( + "Attribute Missing", + `gpu is missing from object`) + + return nil, diags + } + + gpuVal, ok := gpuAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`gpu expected to be basetypes.StringValue, was: %T`, gpuAttribute)) + } + + gpuCountAttribute, ok := attributes["gpu_count"] + + if !ok { + diags.AddError( + "Attribute Missing", + `gpu_count is missing from object`) + + return nil, diags + } + + gpuCountVal, ok := gpuCountAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`gpu_count expected to be basetypes.Int64Value, was: %T`, gpuCountAttribute)) + } + + idAttribute, ok := attributes["id"] + + if !ok { + diags.AddError( + "Attribute Missing", + `id is missing from object`) + + return nil, diags + } + + idVal, ok := idAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) + } + + labelsAttribute, ok := attributes["labels"] + + if !ok { + diags.AddError( + "Attribute Missing", + `labels is missing from object`) + + return nil, diags + } + + labelsVal, ok := labelsAttribute.(basetypes.ListValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`labels expected to be basetypes.ListValue, was: %T`, labelsAttribute)) + } + + nameAttribute, ok := attributes["name"] + + if !ok { + diags.AddError( + "Attribute Missing", + `name is missing from object`) + + return nil, diags + } + + nameVal, ok := nameAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`name expected to be basetypes.StringValue, was: %T`, nameAttribute)) + } + + ramAttribute, ok := attributes["ram"] + + if !ok { + diags.AddError( + "Attribute Missing", + `ram is missing from object`) + + return nil, diags + } + + ramVal, ok := ramAttribute.(basetypes.NumberValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`ram expected to be basetypes.NumberValue, was: %T`, ramAttribute)) + } + + if diags.HasError() { + return nil, diags + } + + return FlavorValue{ + Cpu: cpuVal, + Disk: diskVal, + Ephemeral: ephemeralVal, + Features: featuresVal, + Gpu: gpuVal, + GpuCount: gpuCountVal, + Id: idVal, + Labels: labelsVal, + Name: nameVal, + Ram: ramVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewFlavorValueNull() FlavorValue { + return FlavorValue{ + state: attr.ValueStateNull, + } +} + +func NewFlavorValueUnknown() FlavorValue { + return FlavorValue{ + state: attr.ValueStateUnknown, + } +} + +func NewFlavorValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (FlavorValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing FlavorValue Attribute Value", + "While creating a FlavorValue value, a missing attribute value was detected. "+ + "A FlavorValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FlavorValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid FlavorValue Attribute Type", + "While creating a FlavorValue value, an invalid attribute value was detected. "+ + "A FlavorValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FlavorValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("FlavorValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra FlavorValue Attribute Value", + "While creating a FlavorValue value, an extra attribute value was detected. "+ + "A FlavorValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra FlavorValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewFlavorValueUnknown(), diags + } + + cpuAttribute, ok := attributes["cpu"] + + if !ok { + diags.AddError( + "Attribute Missing", + `cpu is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + cpuVal, ok := cpuAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`cpu expected to be basetypes.Int64Value, was: %T`, cpuAttribute)) + } + + diskAttribute, ok := attributes["disk"] if !ok { diags.AddError( "Attribute Missing", `disk is missing from object`) - return NewFlavorValueUnknown(), diags + return NewFlavorValueUnknown(), diags + } + + diskVal, ok := diskAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`disk expected to be basetypes.Int64Value, was: %T`, diskAttribute)) + } + + ephemeralAttribute, ok := attributes["ephemeral"] + + if !ok { + diags.AddError( + "Attribute Missing", + `ephemeral is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + ephemeralVal, ok := ephemeralAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`ephemeral expected to be basetypes.Int64Value, was: %T`, ephemeralAttribute)) + } + + featuresAttribute, ok := attributes["features"] + + if !ok { + diags.AddError( + "Attribute Missing", + `features is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + featuresVal, ok := featuresAttribute.(basetypes.ObjectValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`features expected to be basetypes.ObjectValue, was: %T`, featuresAttribute)) + } + + gpuAttribute, ok := attributes["gpu"] + + if !ok { + diags.AddError( + "Attribute Missing", + `gpu is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + gpuVal, ok := gpuAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`gpu expected to be basetypes.StringValue, was: %T`, gpuAttribute)) + } + + gpuCountAttribute, ok := attributes["gpu_count"] + + if !ok { + diags.AddError( + "Attribute Missing", + `gpu_count is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + gpuCountVal, ok := gpuCountAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`gpu_count expected to be basetypes.Int64Value, was: %T`, gpuCountAttribute)) + } + + idAttribute, ok := attributes["id"] + + if !ok { + diags.AddError( + "Attribute Missing", + `id is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + idVal, ok := idAttribute.(basetypes.Int64Value) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) + } + + labelsAttribute, ok := attributes["labels"] + + if !ok { + diags.AddError( + "Attribute Missing", + `labels is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + labelsVal, ok := labelsAttribute.(basetypes.ListValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`labels expected to be basetypes.ListValue, was: %T`, labelsAttribute)) + } + + nameAttribute, ok := attributes["name"] + + if !ok { + diags.AddError( + "Attribute Missing", + `name is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + nameVal, ok := nameAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`name expected to be basetypes.StringValue, was: %T`, nameAttribute)) + } + + ramAttribute, ok := attributes["ram"] + + if !ok { + diags.AddError( + "Attribute Missing", + `ram is missing from object`) + + return NewFlavorValueUnknown(), diags + } + + ramVal, ok := ramAttribute.(basetypes.NumberValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`ram expected to be basetypes.NumberValue, was: %T`, ramAttribute)) + } + + if diags.HasError() { + return NewFlavorValueUnknown(), diags + } + + return FlavorValue{ + Cpu: cpuVal, + Disk: diskVal, + Ephemeral: ephemeralVal, + Features: featuresVal, + Gpu: gpuVal, + GpuCount: gpuCountVal, + Id: idVal, + Labels: labelsVal, + Name: nameVal, + Ram: ramVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewFlavorValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) FlavorValue { + object, diags := NewFlavorValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewFlavorValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t FlavorType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewFlavorValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewFlavorValueUnknown(), nil + } + + if in.IsNull() { + return NewFlavorValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewFlavorValueMust(FlavorValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t FlavorType) ValueType(ctx context.Context) attr.Value { + return FlavorValue{} +} + +var _ basetypes.ObjectValuable = FlavorValue{} + +type FlavorValue struct { + Cpu basetypes.Int64Value `tfsdk:"cpu"` + Disk basetypes.Int64Value `tfsdk:"disk"` + Ephemeral basetypes.Int64Value `tfsdk:"ephemeral"` + Features basetypes.ObjectValue `tfsdk:"features"` + Gpu basetypes.StringValue `tfsdk:"gpu"` + GpuCount basetypes.Int64Value `tfsdk:"gpu_count"` + Id basetypes.Int64Value `tfsdk:"id"` + Labels basetypes.ListValue `tfsdk:"labels"` + Name basetypes.StringValue `tfsdk:"name"` + Ram basetypes.NumberValue `tfsdk:"ram"` + state attr.ValueState +} + +func (v FlavorValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 10) + + var val tftypes.Value + var err error + + attrTypes["cpu"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["disk"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["ephemeral"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["features"] = basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }.TerraformType(ctx) + attrTypes["gpu"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["gpu_count"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) + attrTypes["labels"] = basetypes.ListType{ + ElemType: LabelsValue{}.Type(ctx), + }.TerraformType(ctx) + attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx) + attrTypes["ram"] = basetypes.NumberType{}.TerraformType(ctx) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 10) + + val, err = v.Cpu.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["cpu"] = val + + val, err = v.Disk.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["disk"] = val + + val, err = v.Ephemeral.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["ephemeral"] = val + + val, err = v.Features.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["features"] = val + + val, err = v.Gpu.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["gpu"] = val + + val, err = v.GpuCount.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["gpu_count"] = val + + val, err = v.Id.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["id"] = val + + val, err = v.Labels.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["labels"] = val + + val, err = v.Name.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["name"] = val + + val, err = v.Ram.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["ram"] = val + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v FlavorValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v FlavorValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v FlavorValue) String() string { + return "FlavorValue" +} + +func (v FlavorValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + var features basetypes.ObjectValue + + if v.Features.IsNull() { + features = types.ObjectNull( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if v.Features.IsUnknown() { + features = types.ObjectUnknown( + FeaturesValue{}.AttributeTypes(ctx), + ) + } + + if !v.Features.IsNull() && !v.Features.IsUnknown() { + features = types.ObjectValueMust( + FeaturesValue{}.AttributeTypes(ctx), + v.Features.Attributes(), + ) + } + + labels := types.ListValueMust( + LabelsType{ + basetypes.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + v.Labels.Elements(), + ) + + if v.Labels.IsNull() { + labels = types.ListNull( + LabelsType{ + basetypes.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + ) + } + + if v.Labels.IsUnknown() { + labels = types.ListUnknown( + LabelsType{ + basetypes.ObjectType{ + AttrTypes: LabelsValue{}.AttributeTypes(ctx), + }, + }, + ) + } + + attributeTypes := map[string]attr.Type{ + "cpu": basetypes.Int64Type{}, + "disk": basetypes.Int64Type{}, + "ephemeral": basetypes.Int64Type{}, + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + "gpu": basetypes.StringType{}, + "gpu_count": basetypes.Int64Type{}, + "id": basetypes.Int64Type{}, + "labels": basetypes.ListType{ + ElemType: LabelsValue{}.Type(ctx), + }, + "name": basetypes.StringType{}, + "ram": basetypes.NumberType{}, + } + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{ + "cpu": v.Cpu, + "disk": v.Disk, + "ephemeral": v.Ephemeral, + "features": features, + "gpu": v.Gpu, + "gpu_count": v.GpuCount, + "id": v.Id, + "labels": labels, + "name": v.Name, + "ram": v.Ram, + }) + + return objVal, diags +} + +func (v FlavorValue) Equal(o attr.Value) bool { + other, ok := o.(FlavorValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + if !v.Cpu.Equal(other.Cpu) { + return false + } + + if !v.Disk.Equal(other.Disk) { + return false + } + + if !v.Ephemeral.Equal(other.Ephemeral) { + return false + } + + if !v.Features.Equal(other.Features) { + return false + } + + if !v.Gpu.Equal(other.Gpu) { + return false + } + + if !v.GpuCount.Equal(other.GpuCount) { + return false + } + + if !v.Id.Equal(other.Id) { + return false + } + + if !v.Labels.Equal(other.Labels) { + return false + } + + if !v.Name.Equal(other.Name) { + return false + } + + if !v.Ram.Equal(other.Ram) { + return false + } + + return true +} + +func (v FlavorValue) Type(ctx context.Context) attr.Type { + return FlavorType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v FlavorValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{ + "cpu": basetypes.Int64Type{}, + "disk": basetypes.Int64Type{}, + "ephemeral": basetypes.Int64Type{}, + "features": basetypes.ObjectType{ + AttrTypes: FeaturesValue{}.AttributeTypes(ctx), + }, + "gpu": basetypes.StringType{}, + "gpu_count": basetypes.Int64Type{}, + "id": basetypes.Int64Type{}, + "labels": basetypes.ListType{ + ElemType: LabelsValue{}.Type(ctx), + }, + "name": basetypes.StringType{}, + "ram": basetypes.NumberType{}, + } +} + +var _ basetypes.ObjectTypable = FeaturesType{} + +type FeaturesType struct { + basetypes.ObjectType +} + +func (t FeaturesType) Equal(o attr.Type) bool { + other, ok := o.(FeaturesType) + + if !ok { + return false } - diskVal, ok := diskAttribute.(basetypes.Int64Value) + return t.ObjectType.Equal(other.ObjectType) +} + +func (t FeaturesType) String() string { + return "FeaturesType" +} + +func (t FeaturesType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + if diags.HasError() { + return nil, diags + } + + return FeaturesValue{ + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueNull() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateNull, + } +} + +func NewFeaturesValueUnknown() FeaturesValue { + return FeaturesValue{ + state: attr.ValueStateUnknown, + } +} + +func NewFeaturesValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (FeaturesValue, diag.Diagnostics) { + var diags diag.Diagnostics + + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() + + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] + + if !ok { + diags.AddError( + "Missing FeaturesValue Attribute Value", + "While creating a FeaturesValue value, a missing attribute value was detected. "+ + "A FeaturesValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid FeaturesValue Attribute Type", + "While creating a FeaturesValue value, an invalid attribute value was detected. "+ + "A FeaturesValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("FeaturesValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra FeaturesValue Attribute Value", + "While creating a FeaturesValue value, an extra attribute value was detected. "+ + "A FeaturesValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra FeaturesValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + if diags.HasError() { + return NewFeaturesValueUnknown(), diags + } + + return FeaturesValue{ + state: attr.ValueStateKnown, + }, diags +} + +func NewFeaturesValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) FeaturesValue { + object, diags := NewFeaturesValue(attributeTypes, attributes) + + if diags.HasError() { + // This could potentially be added to the diag package. + diagsStrings := make([]string, 0, len(diags)) + + for _, diagnostic := range diags { + diagsStrings = append(diagsStrings, fmt.Sprintf( + "%s | %s | %s", + diagnostic.Severity(), + diagnostic.Summary(), + diagnostic.Detail())) + } + + panic("NewFeaturesValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t FeaturesType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewFeaturesValueNull(), nil + } + + if !in.Type().Equal(t.TerraformType(ctx)) { + return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) + } + + if !in.IsKnown() { + return NewFeaturesValueUnknown(), nil + } + + if in.IsNull() { + return NewFeaturesValueNull(), nil + } + + attributes := map[string]attr.Value{} + + val := map[string]tftypes.Value{} + + err := in.As(&val) + + if err != nil { + return nil, err + } + + for k, v := range val { + a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) + + if err != nil { + return nil, err + } + + attributes[k] = a + } + + return NewFeaturesValueMust(FeaturesValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t FeaturesType) ValueType(ctx context.Context) attr.Value { + return FeaturesValue{} +} + +var _ basetypes.ObjectValuable = FeaturesValue{} + +type FeaturesValue struct { + state attr.ValueState +} + +func (v FeaturesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 0) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 0) + + if err := tftypes.ValidateValue(objectType, vals); err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + return tftypes.NewValue(objectType, vals), nil + case attr.ValueStateNull: + return tftypes.NewValue(objectType, nil), nil + case attr.ValueStateUnknown: + return tftypes.NewValue(objectType, tftypes.UnknownValue), nil + default: + panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) + } +} + +func (v FeaturesValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v FeaturesValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v FeaturesValue) String() string { + return "FeaturesValue" +} + +func (v FeaturesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + attributeTypes := map[string]attr.Type{} + + if v.IsNull() { + return types.ObjectNull(attributeTypes), diags + } + + if v.IsUnknown() { + return types.ObjectUnknown(attributeTypes), diags + } + + objVal, diags := types.ObjectValue( + attributeTypes, + map[string]attr.Value{}) + + return objVal, diags +} + +func (v FeaturesValue) Equal(o attr.Value) bool { + other, ok := o.(FeaturesValue) if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`disk expected to be basetypes.Int64Value, was: %T`, diskAttribute)) + return false } - ephemeralAttribute, ok := attributes["ephemeral"] + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + return true +} + +func (v FeaturesValue) Type(ctx context.Context) attr.Type { + return FeaturesType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v FeaturesValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{} +} + +var _ basetypes.ObjectTypable = LabelsType{} + +type LabelsType struct { + basetypes.ObjectType +} + +func (t LabelsType) Equal(o attr.Type) bool { + other, ok := o.(LabelsType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t LabelsType) String() string { + return "LabelsType" +} + +func (t LabelsType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + attributes := in.Attributes() + + idAttribute, ok := attributes["id"] if !ok { diags.AddError( "Attribute Missing", - `ephemeral is missing from object`) + `id is missing from object`) - return NewFlavorValueUnknown(), diags + return nil, diags } - ephemeralVal, ok := ephemeralAttribute.(basetypes.Int64Value) + idVal, ok := idAttribute.(basetypes.Int64Value) if !ok { diags.AddError( "Attribute Wrong Type", - fmt.Sprintf(`ephemeral expected to be basetypes.Int64Value, was: %T`, ephemeralAttribute)) + fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) } - gpuAttribute, ok := attributes["gpu"] + labelAttribute, ok := attributes["label"] if !ok { diags.AddError( "Attribute Missing", - `gpu is missing from object`) + `label is missing from object`) - return NewFlavorValueUnknown(), diags + return nil, diags + } + + labelVal, ok := labelAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`label expected to be basetypes.StringValue, was: %T`, labelAttribute)) } - gpuVal, ok := gpuAttribute.(basetypes.StringValue) + if diags.HasError() { + return nil, diags + } + + return LabelsValue{ + Id: idVal, + Label: labelVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewLabelsValueNull() LabelsValue { + return LabelsValue{ + state: attr.ValueStateNull, + } +} + +func NewLabelsValueUnknown() LabelsValue { + return LabelsValue{ + state: attr.ValueStateUnknown, + } +} + +func NewLabelsValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (LabelsValue, diag.Diagnostics) { + var diags diag.Diagnostics - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`gpu expected to be basetypes.StringValue, was: %T`, gpuAttribute)) - } + // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 + ctx := context.Background() - gpuCountAttribute, ok := attributes["gpu_count"] + for name, attributeType := range attributeTypes { + attribute, ok := attributes[name] - if !ok { - diags.AddError( - "Attribute Missing", - `gpu_count is missing from object`) + if !ok { + diags.AddError( + "Missing LabelsValue Attribute Value", + "While creating a LabelsValue value, a missing attribute value was detected. "+ + "A LabelsValue must contain values for all attributes, even if null or unknown. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("LabelsValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) - return NewFlavorValueUnknown(), diags + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid LabelsValue Attribute Type", + "While creating a LabelsValue value, an invalid attribute value was detected. "+ + "A LabelsValue must use a matching attribute type for the value. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("LabelsValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("LabelsValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } } - gpuCountVal, ok := gpuCountAttribute.(basetypes.Int64Value) + for name := range attributes { + _, ok := attributeTypes[name] - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`gpu_count expected to be basetypes.Int64Value, was: %T`, gpuCountAttribute)) + if !ok { + diags.AddError( + "Extra LabelsValue Attribute Value", + "While creating a LabelsValue value, an extra attribute value was detected. "+ + "A LabelsValue must not contain values beyond the expected attribute types. "+ + "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ + fmt.Sprintf("Extra LabelsValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewLabelsValueUnknown(), diags } idAttribute, ok := attributes["id"] @@ -1353,7 +3095,7 @@ func NewFlavorValue(attributeTypes map[string]attr.Type, attributes map[string]a "Attribute Missing", `id is missing from object`) - return NewFlavorValueUnknown(), diags + return NewLabelsValueUnknown(), diags } idVal, ok := idAttribute.(basetypes.Int64Value) @@ -1364,61 +3106,37 @@ func NewFlavorValue(attributeTypes map[string]attr.Type, attributes map[string]a fmt.Sprintf(`id expected to be basetypes.Int64Value, was: %T`, idAttribute)) } - nameAttribute, ok := attributes["name"] - - if !ok { - diags.AddError( - "Attribute Missing", - `name is missing from object`) - - return NewFlavorValueUnknown(), diags - } - - nameVal, ok := nameAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`name expected to be basetypes.StringValue, was: %T`, nameAttribute)) - } - - ramAttribute, ok := attributes["ram"] + labelAttribute, ok := attributes["label"] if !ok { diags.AddError( "Attribute Missing", - `ram is missing from object`) + `label is missing from object`) - return NewFlavorValueUnknown(), diags + return NewLabelsValueUnknown(), diags } - ramVal, ok := ramAttribute.(basetypes.NumberValue) + labelVal, ok := labelAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", - fmt.Sprintf(`ram expected to be basetypes.NumberValue, was: %T`, ramAttribute)) + fmt.Sprintf(`label expected to be basetypes.StringValue, was: %T`, labelAttribute)) } if diags.HasError() { - return NewFlavorValueUnknown(), diags + return NewLabelsValueUnknown(), diags } - return FlavorValue{ - Cpu: cpuVal, - Disk: diskVal, - Ephemeral: ephemeralVal, - Gpu: gpuVal, - GpuCount: gpuCountVal, - Id: idVal, - Name: nameVal, - Ram: ramVal, - state: attr.ValueStateKnown, + return LabelsValue{ + Id: idVal, + Label: labelVal, + state: attr.ValueStateKnown, }, diags } -func NewFlavorValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) FlavorValue { - object, diags := NewFlavorValue(attributeTypes, attributes) +func NewLabelsValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) LabelsValue { + object, diags := NewLabelsValue(attributeTypes, attributes) if diags.HasError() { // This could potentially be added to the diag package. @@ -1432,15 +3150,15 @@ func NewFlavorValueMust(attributeTypes map[string]attr.Type, attributes map[stri diagnostic.Detail())) } - panic("NewFlavorValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + panic("NewLabelsValueMust received error(s): " + strings.Join(diagsStrings, "\n")) } return object } -func (t FlavorType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { +func (t LabelsType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { if in.Type() == nil { - return NewFlavorValueNull(), nil + return NewLabelsValueNull(), nil } if !in.Type().Equal(t.TerraformType(ctx)) { @@ -1448,11 +3166,11 @@ func (t FlavorType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (a } if !in.IsKnown() { - return NewFlavorValueUnknown(), nil + return NewLabelsValueUnknown(), nil } if in.IsNull() { - return NewFlavorValueNull(), nil + return NewLabelsValueNull(), nil } attributes := map[string]attr.Value{} @@ -1475,87 +3193,35 @@ func (t FlavorType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (a attributes[k] = a } - return NewFlavorValueMust(FlavorValue{}.AttributeTypes(ctx), attributes), nil + return NewLabelsValueMust(LabelsValue{}.AttributeTypes(ctx), attributes), nil } -func (t FlavorType) ValueType(ctx context.Context) attr.Value { - return FlavorValue{} +func (t LabelsType) ValueType(ctx context.Context) attr.Value { + return LabelsValue{} } -var _ basetypes.ObjectValuable = FlavorValue{} +var _ basetypes.ObjectValuable = LabelsValue{} -type FlavorValue struct { - Cpu basetypes.Int64Value `tfsdk:"cpu"` - Disk basetypes.Int64Value `tfsdk:"disk"` - Ephemeral basetypes.Int64Value `tfsdk:"ephemeral"` - Gpu basetypes.StringValue `tfsdk:"gpu"` - GpuCount basetypes.Int64Value `tfsdk:"gpu_count"` - Id basetypes.Int64Value `tfsdk:"id"` - Name basetypes.StringValue `tfsdk:"name"` - Ram basetypes.NumberValue `tfsdk:"ram"` - state attr.ValueState +type LabelsValue struct { + Id basetypes.Int64Value `tfsdk:"id"` + Label basetypes.StringValue `tfsdk:"label"` + state attr.ValueState } -func (v FlavorValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { - attrTypes := make(map[string]tftypes.Type, 8) +func (v LabelsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 2) var val tftypes.Value var err error - attrTypes["cpu"] = basetypes.Int64Type{}.TerraformType(ctx) - attrTypes["disk"] = basetypes.Int64Type{}.TerraformType(ctx) - attrTypes["ephemeral"] = basetypes.Int64Type{}.TerraformType(ctx) - attrTypes["gpu"] = basetypes.StringType{}.TerraformType(ctx) - attrTypes["gpu_count"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) - attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx) - attrTypes["ram"] = basetypes.NumberType{}.TerraformType(ctx) + attrTypes["label"] = basetypes.StringType{}.TerraformType(ctx) objectType := tftypes.Object{AttributeTypes: attrTypes} switch v.state { case attr.ValueStateKnown: - vals := make(map[string]tftypes.Value, 8) - - val, err = v.Cpu.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["cpu"] = val - - val, err = v.Disk.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["disk"] = val - - val, err = v.Ephemeral.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["ephemeral"] = val - - val, err = v.Gpu.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["gpu"] = val - - val, err = v.GpuCount.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["gpu_count"] = val + vals := make(map[string]tftypes.Value, 2) val, err = v.Id.ToTerraformValue(ctx) @@ -1565,21 +3231,13 @@ func (v FlavorValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error vals["id"] = val - val, err = v.Name.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["name"] = val - - val, err = v.Ram.ToTerraformValue(ctx) + val, err = v.Label.ToTerraformValue(ctx) if err != nil { return tftypes.NewValue(objectType, tftypes.UnknownValue), err } - vals["ram"] = val + vals["label"] = val if err := tftypes.ValidateValue(objectType, vals); err != nil { return tftypes.NewValue(objectType, tftypes.UnknownValue), err @@ -1595,30 +3253,24 @@ func (v FlavorValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error } } -func (v FlavorValue) IsNull() bool { +func (v LabelsValue) IsNull() bool { return v.state == attr.ValueStateNull } -func (v FlavorValue) IsUnknown() bool { +func (v LabelsValue) IsUnknown() bool { return v.state == attr.ValueStateUnknown } -func (v FlavorValue) String() string { - return "FlavorValue" +func (v LabelsValue) String() string { + return "LabelsValue" } -func (v FlavorValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { +func (v LabelsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { var diags diag.Diagnostics attributeTypes := map[string]attr.Type{ - "cpu": basetypes.Int64Type{}, - "disk": basetypes.Int64Type{}, - "ephemeral": basetypes.Int64Type{}, - "gpu": basetypes.StringType{}, - "gpu_count": basetypes.Int64Type{}, - "id": basetypes.Int64Type{}, - "name": basetypes.StringType{}, - "ram": basetypes.NumberType{}, + "id": basetypes.Int64Type{}, + "label": basetypes.StringType{}, } if v.IsNull() { @@ -1632,21 +3284,15 @@ func (v FlavorValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, objVal, diags := types.ObjectValue( attributeTypes, map[string]attr.Value{ - "cpu": v.Cpu, - "disk": v.Disk, - "ephemeral": v.Ephemeral, - "gpu": v.Gpu, - "gpu_count": v.GpuCount, - "id": v.Id, - "name": v.Name, - "ram": v.Ram, + "id": v.Id, + "label": v.Label, }) return objVal, diags } -func (v FlavorValue) Equal(o attr.Value) bool { - other, ok := o.(FlavorValue) +func (v LabelsValue) Equal(o attr.Value) bool { + other, ok := o.(LabelsValue) if !ok { return false @@ -1660,59 +3306,29 @@ func (v FlavorValue) Equal(o attr.Value) bool { return true } - if !v.Cpu.Equal(other.Cpu) { - return false - } - - if !v.Disk.Equal(other.Disk) { - return false - } - - if !v.Ephemeral.Equal(other.Ephemeral) { - return false - } - - if !v.Gpu.Equal(other.Gpu) { - return false - } - - if !v.GpuCount.Equal(other.GpuCount) { - return false - } - if !v.Id.Equal(other.Id) { return false } - if !v.Name.Equal(other.Name) { - return false - } - - if !v.Ram.Equal(other.Ram) { + if !v.Label.Equal(other.Label) { return false } return true } -func (v FlavorValue) Type(ctx context.Context) attr.Type { - return FlavorType{ +func (v LabelsValue) Type(ctx context.Context) attr.Type { + return LabelsType{ basetypes.ObjectType{ AttrTypes: v.AttributeTypes(ctx), }, } } -func (v FlavorValue) AttributeTypes(ctx context.Context) map[string]attr.Type { +func (v LabelsValue) AttributeTypes(ctx context.Context) map[string]attr.Type { return map[string]attr.Type{ - "cpu": basetypes.Int64Type{}, - "disk": basetypes.Int64Type{}, - "ephemeral": basetypes.Int64Type{}, - "gpu": basetypes.StringType{}, - "gpu_count": basetypes.Int64Type{}, - "id": basetypes.Int64Type{}, - "name": basetypes.StringType{}, - "ram": basetypes.NumberType{}, + "id": basetypes.Int64Type{}, + "label": basetypes.StringType{}, } } @@ -3724,6 +5340,24 @@ func (t VolumeType) ValueFromObject(ctx context.Context, in basetypes.ObjectValu attributes := in.Attributes() + bootableAttribute, ok := attributes["bootable"] + + if !ok { + diags.AddError( + "Attribute Missing", + `bootable is missing from object`) + + return nil, diags + } + + bootableVal, ok := bootableAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`bootable expected to be basetypes.BoolValue, was: %T`, bootableAttribute)) + } + descriptionAttribute, ok := attributes["description"] if !ok { @@ -3819,6 +5453,7 @@ func (t VolumeType) ValueFromObject(ctx context.Context, in basetypes.ObjectValu } return VolumeValue{ + Bootable: bootableVal, Description: descriptionVal, Id: idVal, Name: nameVal, @@ -3891,6 +5526,24 @@ func NewVolumeValue(attributeTypes map[string]attr.Type, attributes map[string]a return NewVolumeValueUnknown(), diags } + bootableAttribute, ok := attributes["bootable"] + + if !ok { + diags.AddError( + "Attribute Missing", + `bootable is missing from object`) + + return NewVolumeValueUnknown(), diags + } + + bootableVal, ok := bootableAttribute.(basetypes.BoolValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`bootable expected to be basetypes.BoolValue, was: %T`, bootableAttribute)) + } + descriptionAttribute, ok := attributes["description"] if !ok { @@ -3986,6 +5639,7 @@ func NewVolumeValue(attributeTypes map[string]attr.Type, attributes map[string]a } return VolumeValue{ + Bootable: bootableVal, Description: descriptionVal, Id: idVal, Name: nameVal, @@ -4063,6 +5717,7 @@ func (t VolumeType) ValueType(ctx context.Context) attr.Value { var _ basetypes.ObjectValuable = VolumeValue{} type VolumeValue struct { + Bootable basetypes.BoolValue `tfsdk:"bootable"` Description basetypes.StringValue `tfsdk:"description"` Id basetypes.Int64Value `tfsdk:"id"` Name basetypes.StringValue `tfsdk:"name"` @@ -4072,11 +5727,12 @@ type VolumeValue struct { } func (v VolumeValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { - attrTypes := make(map[string]tftypes.Type, 5) + attrTypes := make(map[string]tftypes.Type, 6) var val tftypes.Value var err error + attrTypes["bootable"] = basetypes.BoolType{}.TerraformType(ctx) attrTypes["description"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx) attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx) @@ -4087,7 +5743,15 @@ func (v VolumeValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error switch v.state { case attr.ValueStateKnown: - vals := make(map[string]tftypes.Value, 5) + vals := make(map[string]tftypes.Value, 6) + + val, err = v.Bootable.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["bootable"] = val val, err = v.Description.ToTerraformValue(ctx) @@ -4159,6 +5823,7 @@ func (v VolumeValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, var diags diag.Diagnostics attributeTypes := map[string]attr.Type{ + "bootable": basetypes.BoolType{}, "description": basetypes.StringType{}, "id": basetypes.Int64Type{}, "name": basetypes.StringType{}, @@ -4177,6 +5842,7 @@ func (v VolumeValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, objVal, diags := types.ObjectValue( attributeTypes, map[string]attr.Value{ + "bootable": v.Bootable, "description": v.Description, "id": v.Id, "name": v.Name, @@ -4202,6 +5868,10 @@ func (v VolumeValue) Equal(o attr.Value) bool { return true } + if !v.Bootable.Equal(other.Bootable) { + return false + } + if !v.Description.Equal(other.Description) { return false } @@ -4235,6 +5905,7 @@ func (v VolumeValue) Type(ctx context.Context) attr.Type { func (v VolumeValue) AttributeTypes(ctx context.Context) map[string]attr.Type { return map[string]attr.Type{ + "bootable": basetypes.BoolType{}, "description": basetypes.StringType{}, "id": basetypes.Int64Type{}, "name": basetypes.StringType{}, diff --git a/internal/genprovider/resource_core_volume/core_volume_resource_gen.go b/internal/genprovider/resource_core_volume/core_volume_resource_gen.go index 4466753..9da9cd9 100644 --- a/internal/genprovider/resource_core_volume/core_volume_resource_gen.go +++ b/internal/genprovider/resource_core_volume/core_volume_resource_gen.go @@ -42,7 +42,8 @@ func CoreVolumeResourceSchema(ctx context.Context) schema.Schema { Computed: true, }, "description": schema.StringAttribute{ - Required: true, + Optional: true, + Computed: true, Description: "A brief description or comment about the volume.", MarkdownDescription: "A brief description or comment about the volume.", PlanModifiers: []planmodifier.String{ @@ -93,6 +94,9 @@ func CoreVolumeResourceSchema(ctx context.Context) schema.Schema { stringvalidator.LengthAtMost(50), }, }, + "os_image": schema.StringAttribute{ + Computed: true, + }, "size": schema.Int64Attribute{ Required: true, Description: "The size of the volume in GB. 1048576GB storage capacity per volume.", @@ -109,8 +113,8 @@ func CoreVolumeResourceSchema(ctx context.Context) schema.Schema { }, "volume_type": schema.StringAttribute{ Required: true, - Description: "Specifies the type of volume being created, which determines the storage technology it will use. Call the \"[List volume types](https://infrahub-api-doc.nexgencloud.com/#get-/core/volumes)\" endpoint to retrieve a list of available volume model types.", - MarkdownDescription: "Specifies the type of volume being created, which determines the storage technology it will use. Call the \"[List volume types](https://infrahub-api-doc.nexgencloud.com/#get-/core/volumes)\" endpoint to retrieve a list of available volume model types.", + Description: "Specifies the type of volume being created, which determines the storage technology it will use. Call the [List volume types](https://infrahub-api-doc.nexgencloud.com/#get-/core/volumes) endpoint to retrieve a list of available volume model types.", + MarkdownDescription: "Specifies the type of volume being created, which determines the storage technology it will use. Call the [List volume types](https://infrahub-api-doc.nexgencloud.com/#get-/core/volumes) endpoint to retrieve a list of available volume model types.", PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, @@ -129,6 +133,7 @@ type CoreVolumeModel struct { Id types.Int64 `tfsdk:"id"` ImageId types.Int64 `tfsdk:"image_id"` Name types.String `tfsdk:"name"` + OsImage types.String `tfsdk:"os_image"` Size types.Int64 `tfsdk:"size"` Status types.String `tfsdk:"status"` UpdatedAt types.String `tfsdk:"updated_at"` diff --git a/scripts/fix_api_spec.py b/scripts/fix_api_spec.py index 5355789..ae7e274 100644 --- a/scripts/fix_api_spec.py +++ b/scripts/fix_api_spec.py @@ -148,18 +148,17 @@ def attr_fix_components(data: AttrType) -> None: for p in list(props.keys()): props["N%s" % p] = props.pop(p) - paths["/core/virtual-machines/{virtual_machine_id}/sg-rules"] = paths["/core/virtual-machines/{id}/sg-rules"] - del paths["/core/virtual-machines/{id}/sg-rules"] + paths["/core/virtual-machines/{virtual_machine_id}/sg-rules"] = paths["/core/virtual-machines/{vm_id}/sg-rules"] + del paths["/core/virtual-machines/{vm_id}/sg-rules"] paths["/core/virtual-machines/{virtual_machine_id}/sg-rules"]["post"]["parameters"][0]["name"] = "virtual_machine_id" paths["/core/virtual-machines/{virtual_machine_id}/sg-rules/{id}"] = paths[ - "/core/virtual-machines/{virtual_machine_id}/sg-rules/{sg_rule_id}"] - del paths["/core/virtual-machines/{virtual_machine_id}/sg-rules/{sg_rule_id}"] + "/core/virtual-machines/{vm_id}/sg-rules/{sg_rule_id}"] + del paths["/core/virtual-machines/{vm_id}/sg-rules/{sg_rule_id}"] paths["/core/virtual-machines/{virtual_machine_id}/sg-rules/{id}"]["delete"]["parameters"][0][ "name"] = "virtual_machine_id" paths["/core/virtual-machines/{virtual_machine_id}/sg-rules/{id}"]["delete"]["parameters"][1]["name"] = "id" - def fix_api_spec(spec_file: str) -> None: """ Updates specification file in place, applying various schema fixes. diff --git a/scripts/fix_provider_spec.py b/scripts/fix_provider_spec.py index 58c4a5e..8287fed 100644 --- a/scripts/fix_provider_spec.py +++ b/scripts/fix_provider_spec.py @@ -59,8 +59,11 @@ def attr_update_nested(attr: AttrType, updater: Callable[[str, AttrType, str], N # For nested definitions we need to go through all nested attributes if "single_nested" in attr: updater("single_nested", attr["single_nested"], "object") - for nested in attr["single_nested"]["attributes"]: - attr_update_nested(nested, updater) + + # Make sure that in attr single_nested object has attributes array + if attr.get("single_nested", {}).get("attributes"): + for nested in attr["single_nested"]["attributes"]: + attr_update_nested(nested, updater) if "list_nested" in attr: updater("list_nested", attr["list_nested"], "list") for nested in attr["list_nested"]["nested_object"]["attributes"]: