@@ -98,6 +98,7 @@ type ServiceResourceModel struct {
9898 MaxscaleSize types.String `tfsdk:"maxscale_size"`
9999 FQDN types.String `tfsdk:"fqdn"`
100100 AvailabilityZone types.String `tfsdk:"availability_zone"`
101+ Tags types.Map `tfsdk:"tags"`
101102}
102103
103104// ServiceResourceNamedPortModel is an endpoint port
@@ -403,6 +404,12 @@ var serviceResourceSchemaV0 = schema.Schema{
403404 stringplanmodifier .RequiresReplace (),
404405 },
405406 },
407+ "tags" : schema.MapAttribute {
408+ Optional : true ,
409+ Computed : true ,
410+ ElementType : types .StringType ,
411+ Description : "Tags associated with the service" ,
412+ },
406413 },
407414 Blocks : map [string ]schema.Block {
408415 "timeouts" : timeouts .Block (context .Background (), timeouts.Opts {
@@ -721,6 +728,11 @@ func (r *ServiceResource) readServiceState(ctx context.Context, data *ServiceRes
721728 if ! (data .MaxscaleNodes .IsUnknown () || data .MaxscaleSize .IsNull ()) {
722729 data .MaxscaleNodes = types .Int64Value (int64 (service .MaxscaleNodes ))
723730 }
731+ if service .Tags != nil {
732+ data .Tags , _ = types .MapValueFrom (ctx , types .StringType , service .Tags )
733+ } else {
734+ data .Tags = types .MapNull (types .StringType )
735+ }
724736 return nil
725737}
726738
@@ -783,6 +795,11 @@ func (r *ServiceResource) Update(ctx context.Context, req resource.UpdateRequest
783795 return
784796 }
785797
798+ r .updateServiceTags (ctx , plan , state , resp )
799+ if resp .Diagnostics .HasError () {
800+ return
801+ }
802+
786803 err := r .readServiceState (ctx , state )
787804 if err != nil {
788805 if errors .Is (err , skysql .ErrorServiceNotFound ) {
@@ -1035,6 +1052,63 @@ func (r *ServiceResource) updateServicePowerState(ctx context.Context, plan *Ser
10351052 }
10361053}
10371054
1055+ func (r * ServiceResource ) updateServiceTags (ctx context.Context , plan * ServiceResourceModel , state * ServiceResourceModel , resp * resource.UpdateResponse ) {
1056+ if ! plan .Tags .IsUnknown () {
1057+ var planTags map [string ]string
1058+ diags := plan .Tags .ElementsAs (ctx , & planTags , false )
1059+ if diags .HasError () {
1060+ // Log warning but don't fail the update to protect against state incompatibility
1061+ tflog .Warn (ctx , "Failed to parse plan tags, skipping tag update" , map [string ]interface {}{
1062+ "id" : state .ID .ValueString (),
1063+ "error" : diags .Errors (),
1064+ })
1065+ return
1066+ }
1067+
1068+ var stateTags map [string ]string
1069+ diags = state .Tags .ElementsAs (ctx , & stateTags , false )
1070+ if diags .HasError () {
1071+ // For backward compatibility, if state tags can't be parsed (e.g., from older provider version),
1072+ // treat as empty map and continue with the update
1073+ tflog .Warn (ctx , "Failed to parse state tags, treating as empty" , map [string ]interface {}{
1074+ "id" : state .ID .ValueString (),
1075+ "error" : diags .Errors (),
1076+ })
1077+ stateTags = make (map [string ]string )
1078+ }
1079+
1080+ if ! reflect .DeepEqual (planTags , stateTags ) {
1081+ tflog .Info (ctx , "Updating service tags" , map [string ]interface {}{
1082+ "id" : state .ID .ValueString (),
1083+ })
1084+
1085+ err := r .client .UpdateServiceTags (ctx , state .ID .ValueString (), planTags )
1086+ if err != nil {
1087+ if errors .Is (err , skysql .ErrorServiceNotFound ) {
1088+ tflog .Warn (ctx , "SkySQL service not found, removing from state" , map [string ]interface {}{
1089+ "id" : state .ID .ValueString (),
1090+ })
1091+ resp .State .RemoveResource (ctx )
1092+ return
1093+ }
1094+ // Log warning but don't fail the update to protect against tag API errors
1095+ tflog .Warn (ctx , "Failed to update service tags, continuing with other updates" , map [string ]interface {}{
1096+ "id" : state .ID .ValueString (),
1097+ "error" : err .Error (),
1098+ })
1099+ return
1100+ }
1101+
1102+ state .Tags = plan .Tags
1103+ resp .Diagnostics .Append (resp .State .Set (ctx , & state )... )
1104+ if resp .Diagnostics .HasError () {
1105+ return
1106+ }
1107+ r .waitForUpdate (ctx , state , resp )
1108+ }
1109+ }
1110+ }
1111+
10381112var serviceUpdateWaitStates = []string {"ready" , "failed" , "stopped" }
10391113
10401114func (r * ServiceResource ) waitForUpdate (ctx context.Context , state * ServiceResourceModel , resp * resource.UpdateResponse ) {
0 commit comments