diff --git a/cloudfoundry/resource_cf_route_service_binding.go b/cloudfoundry/resource_cf_route_service_binding.go index 6487a2d3..02714247 100644 --- a/cloudfoundry/resource_cf_route_service_binding.go +++ b/cloudfoundry/resource_cf_route_service_binding.go @@ -2,6 +2,11 @@ package cloudfoundry import ( "context" + "log" + "strings" + + "github.com/cloudfoundry/go-cfclient/v3/client" + "github.com/cloudfoundry/go-cfclient/v3/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/terraform-providers/terraform-provider-cloudfoundry/cloudfoundry/managers" @@ -21,18 +26,32 @@ func resourceRouteServiceBinding() *schema.Resource { StateContext: resourceRouteServiceBindingImport, }, + Schema: resourceRouteServiceBindingSchema().Schema, + SchemaVersion: 1, + StateUpgraders: []schema.StateUpgrader{ + { + Type: resourceRouteServiceBindingSchema().CoreConfigSchema().ImpliedType(), + Upgrade: upgradeStateRouteServiceBindingStateV0toV1ChangeID, + Version: 0, + }, + }, + } +} + +func resourceRouteServiceBindingSchema() *schema.Resource { + return &schema.Resource{ Schema: map[string]*schema.Schema{ - "service_instance": &schema.Schema{ + "service_instance": { Type: schema.TypeString, Required: true, ForceNew: true, }, - "route": &schema.Schema{ + "route": { Type: schema.TypeString, Required: true, ForceNew: true, }, - "json_params": &schema.Schema{ + "json_params": { Type: schema.TypeString, Optional: true, ForceNew: true, @@ -41,15 +60,11 @@ func resourceRouteServiceBinding() *schema.Resource { } } -func resourceRouteServiceBindingImport(ctx context.Context, d *schema.ResourceData, meta interface{}) (res []*schema.ResourceData, err error) { - id := d.Id() - if _, _, err = parseID(id); err != nil { - return - } +func resourceRouteServiceBindingImport(ctx context.Context, d *schema.ResourceData, meta any) (res []*schema.ResourceData, err error) { return ImportReadContext(resourceRouteServiceBindingRead)(ctx, d, meta) } -func resourceRouteServiceBindingCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceRouteServiceBindingCreate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { session := meta.(*managers.Session) var data map[string]interface{} @@ -63,48 +78,110 @@ func resourceRouteServiceBindingCreate(ctx context.Context, d *schema.ResourceDa return diag.FromErr(err) } } - _, err := session.ClientV2.CreateServiceBindingRoute(serviceID, routeID, data) + + jobGUID, _, err := session.ClientGo.ServiceRouteBindings.Create(context.Background(), &resource.ServiceRouteBindingCreate{ + Relationships: resource.ServiceRouteBindingRelationships{ + // ServiceInstance ToOneRelationship `json:"service_instance"` + // // The route that the service instance is bound to + // Route ToOneRelationship `json:"route"` + ServiceInstance: resource.ToOneRelationship{ + Data: &resource.Relationship{ + GUID: serviceID, + }, + }, + Route: resource.ToOneRelationship{ + Data: &resource.Relationship{ + GUID: routeID, + }, + }, + }, + }) + if err != nil { return diag.FromErr(err) } - d.SetId(computeID(serviceID, routeID)) - return nil -} - -func resourceRouteServiceBindingRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - session := meta.(*managers.Session) - - serviceID, routeID, err := parseID(d.Id()) + if jobGUID != "" { + err = session.ClientGo.Jobs.PollComplete(context.Background(), jobGUID, nil) + } if err != nil { return diag.FromErr(err) } - routes, _, err := session.ClientV2.GetServiceBindingRoutes(serviceID) + + options := client.NewServiceRouteBindingListOptions() + options.ServiceInstanceGUIDs = client.Filter{Values: []string{serviceID}} + options.RouteGUIDs = client.Filter{Values: []string{routeID}} + + routeBinding, err := session.ClientGo.ServiceRouteBindings.Single(context.Background(), options) + if err != nil { return diag.FromErr(err) } - found := false - for _, route := range routes { - if route.GUID == routeID { - found = true - break + + d.SetId(routeBinding.GUID) + return nil +} + +func resourceRouteServiceBindingRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + session := meta.(*managers.Session) + + routeServiceBinding, err := session.ClientGo.ServiceRouteBindings.Get(context.Background(), d.Id()) + + if err != nil { + if strings.Contains(err.Error(), "CF-ResourceNotFound") { + d.SetId("") + return nil } - } - if !found { - d.SetId("") - return diag.Errorf("Route '%s' not found in service instance '%s'", routeID, serviceID) + return diag.Errorf("Error when reading routeServiceBinding with id '%s': %s", d.Id(), err) } - d.Set("service_instance", serviceID) - d.Set("route", routeID) + d.Set("service_instance", routeServiceBinding.Relationships.ServiceInstance.Data.GUID) + d.Set("route", routeServiceBinding.Relationships.Route.Data.GUID) + return nil } -func resourceRouteServiceBindingDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceRouteServiceBindingDelete(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { session := meta.(*managers.Session) - serviceID := d.Get("service_instance").(string) - routeID := d.Get("route").(string) - _, err := session.ClientV2.DeleteServiceBindingRoute(serviceID, routeID) + jobGUID, err := session.ClientGo.ServiceRouteBindings.Delete(context.Background(), d.Id()) + + if err != nil { + return diag.FromErr(err) + } + if jobGUID != "" { + err = session.ClientGo.Jobs.PollComplete(context.Background(), jobGUID, nil) + } return diag.FromErr(err) } + +func upgradeStateRouteServiceBindingStateV0toV1ChangeID(ctx context.Context, rawState map[string]any, meta any) (map[string]any, error) { + session := meta.(*managers.Session) + + if len(rawState) == 0 { + log.Println("[DEBUG] Empty RouteServiceBinding; nothing to migrate.") + return rawState, nil + } + + log.Printf("[DEBUG] Attributes before migration: %#v", rawState) + options := client.NewServiceRouteBindingListOptions() + options.ServiceInstanceGUIDs = client.Filter{Values: []string{rawState["service_instance"].(string)}} + options.RouteGUIDs = client.Filter{Values: []string{rawState["route"].(string)}} + + routeBinding, err := session.ClientGo.ServiceRouteBindings.Single(context.Background(), options) + + if err != nil { + if err == client.ErrExactlyOneResultNotReturned { + rawState["id"] = "" + return rawState, nil + } + log.Println("[DEBUG] Failed to migrate RouteServiceBinding id: error while searching for the route service binding.") + return rawState, err + } + + rawState["id"] = routeBinding.GUID + + log.Printf("[DEBUG] Attributes after migration: %#v", rawState) + + return rawState, nil +}