@@ -26,7 +26,6 @@ var ReservedResourceFields = []string{
2626 "connection" ,
2727 "count" ,
2828 "depends_on" ,
29- "id" ,
3029 "lifecycle" ,
3130 "provider" ,
3231 "provisioner" ,
@@ -649,6 +648,14 @@ func (r *Resource) InternalValidate(topSchemaMap schemaMap, writable bool) error
649648 }
650649 }
651650
651+ if f , ok := tsm ["id" ]; ok {
652+ // if there is an explicit ID, validate it...
653+ err := validateResourceID (f )
654+ if err != nil {
655+ return err
656+ }
657+ }
658+
652659 for k , f := range tsm {
653660 if isReservedResourceFieldName (k , f ) {
654661 return fmt .Errorf ("%s is a reserved field name" , k )
@@ -717,18 +724,30 @@ func isReservedDataSourceFieldName(name string) bool {
717724 return false
718725}
719726
720- func isReservedResourceFieldName (name string , s * Schema ) bool {
721- // Allow phasing out "id"
722- // See https://github.com/terraform-providers/terraform-provider-aws/pull/1626#issuecomment-328881415
723- if name == "id" && s .Deprecated != "" {
724- return false
727+ func validateResourceID (s * Schema ) error {
728+ if s .Type != TypeString {
729+ return fmt .Errorf (`the "id" attribute must be of TypeString` )
730+ }
731+
732+ if s .Required {
733+ return fmt .Errorf (`the "id" attribute cannot be marked Required` )
725734 }
726735
736+ // ID should at least be computed. If unspecified it will be set to Computed and Optional,
737+ // but Optional is unnecessary if undesired.
738+ if s .Computed != true {
739+ return fmt .Errorf (`the "id" attribute must be marked Computed` )
740+ }
741+ return nil
742+ }
743+
744+ func isReservedResourceFieldName (name string , s * Schema ) bool {
727745 for _ , reservedName := range ReservedResourceFields {
728746 if name == reservedName {
729747 return true
730748 }
731749 }
750+
732751 return false
733752}
734753
0 commit comments