diff --git a/internal/datasources/system/system_data_source_gen.go b/internal/datasources/system/system_data_source_gen.go index a3ac101..cfc56c2 100644 --- a/internal/datasources/system/system_data_source_gen.go +++ b/internal/datasources/system/system_data_source_gen.go @@ -4,7 +4,13 @@ package system 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" ) @@ -14,19 +20,361 @@ func SystemDataSourceSchema(ctx context.Context) schema.Schema { Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ Computed: true, - Description: "Unique Identifier of the system, usually a UUID.", - MarkdownDescription: "Unique Identifier of the system, usually a UUID.", + Description: "The UUID of the system", + MarkdownDescription: "The UUID of the system", }, "name": schema.StringAttribute{ Required: true, - Description: "A system specified name for the resource.", - MarkdownDescription: "A system specified name for the resource.", + Description: "The system name", + MarkdownDescription: "The system name", + }, + "storage_system": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "storage_serial": schema.StringAttribute{ + Computed: true, + Description: "Serial number of the storage system.", + MarkdownDescription: "Serial number of the storage system.", + }, + }, + CustomType: StorageSystemType{ + ObjectType: types.ObjectType{ + AttrTypes: StorageSystemValue{}.AttributeTypes(ctx), + }, + }, + Computed: true, + Description: "Storage Information of system.", + MarkdownDescription: "Storage Information of system.", }, }, } } type SystemModel struct { - Id types.String `tfsdk:"id"` - Name types.String `tfsdk:"name"` + Id types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + StorageSystem StorageSystemValue `tfsdk:"storage_system"` +} + +var _ basetypes.ObjectTypable = StorageSystemType{} + +type StorageSystemType struct { + basetypes.ObjectType +} + +func (t StorageSystemType) Equal(o attr.Type) bool { + other, ok := o.(StorageSystemType) + + if !ok { + return false + } + + return t.ObjectType.Equal(other.ObjectType) +} + +func (t StorageSystemType) String() string { + return "StorageSystemType" +} + +func (t StorageSystemType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { + var diags diag.Diagnostics + + attributes := in.Attributes() + + storageSerialAttribute, ok := attributes["storage_serial"] + + if !ok { + diags.AddError( + "Attribute Missing", + `storage_serial is missing from object`) + + return nil, diags + } + + storageSerialVal, ok := storageSerialAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`storage_serial expected to be basetypes.StringValue, was: %T`, storageSerialAttribute)) + } + + if diags.HasError() { + return nil, diags + } + + return StorageSystemValue{ + StorageSerial: storageSerialVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewStorageSystemValueNull() StorageSystemValue { + return StorageSystemValue{ + state: attr.ValueStateNull, + } +} + +func NewStorageSystemValueUnknown() StorageSystemValue { + return StorageSystemValue{ + state: attr.ValueStateUnknown, + } +} + +func NewStorageSystemValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (StorageSystemValue, 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 StorageSystemValue Attribute Value", + "While creating a StorageSystemValue value, a missing attribute value was detected. "+ + "A StorageSystemValue 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("StorageSystemValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), + ) + + continue + } + + if !attributeType.Equal(attribute.Type(ctx)) { + diags.AddError( + "Invalid StorageSystemValue Attribute Type", + "While creating a StorageSystemValue value, an invalid attribute value was detected. "+ + "A StorageSystemValue 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("StorageSystemValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ + fmt.Sprintf("StorageSystemValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), + ) + } + } + + for name := range attributes { + _, ok := attributeTypes[name] + + if !ok { + diags.AddError( + "Extra StorageSystemValue Attribute Value", + "While creating a StorageSystemValue value, an extra attribute value was detected. "+ + "A StorageSystemValue 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 StorageSystemValue Attribute Name: %s", name), + ) + } + } + + if diags.HasError() { + return NewStorageSystemValueUnknown(), diags + } + + storageSerialAttribute, ok := attributes["storage_serial"] + + if !ok { + diags.AddError( + "Attribute Missing", + `storage_serial is missing from object`) + + return NewStorageSystemValueUnknown(), diags + } + + storageSerialVal, ok := storageSerialAttribute.(basetypes.StringValue) + + if !ok { + diags.AddError( + "Attribute Wrong Type", + fmt.Sprintf(`storage_serial expected to be basetypes.StringValue, was: %T`, storageSerialAttribute)) + } + + if diags.HasError() { + return NewStorageSystemValueUnknown(), diags + } + + return StorageSystemValue{ + StorageSerial: storageSerialVal, + state: attr.ValueStateKnown, + }, diags +} + +func NewStorageSystemValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) StorageSystemValue { + object, diags := NewStorageSystemValue(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("NewStorageSystemValueMust received error(s): " + strings.Join(diagsStrings, "\n")) + } + + return object +} + +func (t StorageSystemType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + if in.Type() == nil { + return NewStorageSystemValueNull(), 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 NewStorageSystemValueUnknown(), nil + } + + if in.IsNull() { + return NewStorageSystemValueNull(), 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 NewStorageSystemValueMust(StorageSystemValue{}.AttributeTypes(ctx), attributes), nil +} + +func (t StorageSystemType) ValueType(ctx context.Context) attr.Value { + return StorageSystemValue{} +} + +var _ basetypes.ObjectValuable = StorageSystemValue{} + +type StorageSystemValue struct { + StorageSerial basetypes.StringValue `tfsdk:"storage_serial"` + state attr.ValueState +} + +func (v StorageSystemValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + attrTypes := make(map[string]tftypes.Type, 1) + + var val tftypes.Value + var err error + + attrTypes["storage_serial"] = basetypes.StringType{}.TerraformType(ctx) + + objectType := tftypes.Object{AttributeTypes: attrTypes} + + switch v.state { + case attr.ValueStateKnown: + vals := make(map[string]tftypes.Value, 1) + + val, err = v.StorageSerial.ToTerraformValue(ctx) + + if err != nil { + return tftypes.NewValue(objectType, tftypes.UnknownValue), err + } + + vals["storage_serial"] = 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 StorageSystemValue) IsNull() bool { + return v.state == attr.ValueStateNull +} + +func (v StorageSystemValue) IsUnknown() bool { + return v.state == attr.ValueStateUnknown +} + +func (v StorageSystemValue) String() string { + return "StorageSystemValue" +} + +func (v StorageSystemValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { + var diags diag.Diagnostics + + attributeTypes := map[string]attr.Type{ + "storage_serial": 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{ + "storage_serial": v.StorageSerial, + }) + + return objVal, diags +} + +func (v StorageSystemValue) Equal(o attr.Value) bool { + other, ok := o.(StorageSystemValue) + + if !ok { + return false + } + + if v.state != other.state { + return false + } + + if v.state != attr.ValueStateKnown { + return true + } + + if !v.StorageSerial.Equal(other.StorageSerial) { + return false + } + + return true +} + +func (v StorageSystemValue) Type(ctx context.Context) attr.Type { + return StorageSystemType{ + basetypes.ObjectType{ + AttrTypes: v.AttributeTypes(ctx), + }, + } +} + +func (v StorageSystemValue) AttributeTypes(ctx context.Context) map[string]attr.Type { + return map[string]attr.Type{ + "storage_serial": basetypes.StringType{}, + } }