diff --git a/cloudfoundry/provider.go b/cloudfoundry/provider.go index 30c3c470..1e4517f9 100644 --- a/cloudfoundry/provider.go +++ b/cloudfoundry/provider.go @@ -142,6 +142,7 @@ func Provider() *schema.Provider { "cloudfoundry_service_instance": resourceServiceInstance(), "cloudfoundry_service_key": resourceServiceKey(), "cloudfoundry_user_provided_service": resourceUserProvidedService(), + "cloudfoundry_service_instance_sharing": resourceServiceInstanceSharing(), "cloudfoundry_buildpack": resourceBuildpack(), "cloudfoundry_route": ResourceRoute(), "cloudfoundry_route_service_binding": resourceRouteServiceBinding(), diff --git a/cloudfoundry/resource_cf_service_instance_sharing.go b/cloudfoundry/resource_cf_service_instance_sharing.go new file mode 100644 index 00000000..3b481d15 --- /dev/null +++ b/cloudfoundry/resource_cf_service_instance_sharing.go @@ -0,0 +1,92 @@ +package cloudfoundry + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/terraform-providers/terraform-provider-cloudfoundry/cloudfoundry/managers" +) + +func resourceServiceInstanceSharing() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceServiceInstanceSharingCreate, + ReadContext: resourceServiceInstanceSharingRead, + DeleteContext: resourceServiceInstanceSharingDelete, + + Schema: map[string]*schema.Schema{ + "service_instance_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The ID of the service instance to share", + }, + "space_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The ID of the space to share the service instance with, the space can be in the same or different org", + }, + }, + } +} + +func resourceServiceInstanceSharingRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + session := meta.(*managers.Session) + + serviceID, spaceID, err := parseID(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + spaceWithOrganizationList, _, err := session.ClientV3.GetServiceInstanceSharedSpaces(serviceID) + + if err != nil { + return diag.FromErr(err) + } + + found := false + for _, spaceWithOrganization := range spaceWithOrganizationList { + if spaceWithOrganization.SpaceGUID == spaceID { + found = true + break + } + } + + if !found { + d.SetId("") + return nil + } + + d.Set("service_instance_id", serviceID) + d.Set("space_id", spaceID) + return nil +} + +func resourceServiceInstanceSharingCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + session := meta.(*managers.Session) + serviceID := d.Get("service_instance_id").(string) + spaceID := d.Get("space_id").(string) + + spacesGUIDList, _, err := session.ClientV3.ShareServiceInstanceToSpaces(serviceID, []string{spaceID}) + + if err != nil { + return diag.FromErr(err) + } + + if len(spacesGUIDList.GUIDs) < 1 { + return diag.Errorf("failed to share service instance %s to space %s", serviceID, spaceID) + } + + d.SetId(computeID(serviceID, spaceID)) + return nil +} + +func resourceServiceInstanceSharingDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + session := meta.(*managers.Session) + serviceID := d.Get("service_instance_id").(string) + spaceID := d.Get("space_id").(string) + _, err := session.ClientV3.UnshareServiceInstanceFromSpace(serviceID, spaceID) + + return diag.FromErr(err) +} diff --git a/cloudfoundry/resource_cf_service_instance_sharing_test.go b/cloudfoundry/resource_cf_service_instance_sharing_test.go new file mode 100644 index 00000000..fde0e998 --- /dev/null +++ b/cloudfoundry/resource_cf_service_instance_sharing_test.go @@ -0,0 +1,87 @@ +package cloudfoundry + +import ( + "fmt" + "testing" + + guuid "github.com/google/uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +const serviceInstanceSharing = ` +data "cloudfoundry_service" "test-service" { + name = "%s" +} + +data "cloudfoundry_user" "u"{ + name = "%s" + org_id = "%s" +} + +resource "cloudfoundry_space" "test-space-1" { + name = "space-1-%s" + org = "%s" + managers = [ data.cloudfoundry_user.u.id ] + developers = [ data.cloudfoundry_user.u.id ] + auditors = [ data.cloudfoundry_user.u.id ] +} + +resource "cloudfoundry_space" "test-space-2" { + name = "space-2-%s" + org = "%s" + managers = [ data.cloudfoundry_user.u.id ] + developers = [ data.cloudfoundry_user.u.id ] + auditors = [ data.cloudfoundry_user.u.id ] +} + +resource "cloudfoundry_service_instance" "test-service-instance" { + name = "test-service-instance-sharing-%s" + space = resource.cloudfoundry_space.test-space-1.id + service_plan = data.cloudfoundry_service.test-service.service_plans["%s"] +} + +resource "cloudfoundry_service_instance_sharing" "test-service-instance-sharing" { + service_instance_id = resource.cloudfoundry_service_instance.test-service-instance.id + space_id = resource.cloudfoundry_space.test-space-2.id +} +` + +func TestAccResServiceInstanceSharing_normal(t *testing.T) { + t.Parallel() + orgId, _ := defaultTestOrg(t) + + serviceName, _, servicePlan := getTestServiceBrokers(t) + userName := testSession().Config.User + + testId := guuid.New().String() + + ref := "cloudfoundry_service_instance.test-service-instance" + + resource.Test(t, + resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProvidersFactories, + CheckDestroy: resource.ComposeTestCheckFunc( + testAccCheckServiceInstanceDestroyed([]string{"test-service-instance-sharing-%s"}, ref), + testAccCheckSpaceDestroyed(fmt.Sprintf("space-1-%s", testId)), + testAccCheckSpaceDestroyed(fmt.Sprintf("space-2-%s", testId)), + ), + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf(serviceInstanceSharing, serviceName, userName, orgId, testId, orgId, testId, orgId, testId, servicePlan), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceInstanceExists(ref), + func(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type == "cloudfoundry_service_instance_sharing" { + return nil + } + } + return fmt.Errorf("resource 'cloudfoundry_service_instance_sharing' not found in terraform state") + }, + ), + }, + }, + }) +} diff --git a/docs/resources/service_instance_sharing.md b/docs/resources/service_instance_sharing.md new file mode 100644 index 00000000..fa1f89da --- /dev/null +++ b/docs/resources/service_instance_sharing.md @@ -0,0 +1,40 @@ +--- +layout: "cloudfoundry" +page_title: "Cloud Foundry: cloudfoundry_service_instance_sharing" +sidebar_current: "docs-cf-resource-service-instance-sharing" +description: |- Sharing a service instance to another space. +--- + +# cloudfoundry\_service\_instance\_sharing + +Sharing a service instance to another space [Sharing Service Instances](https://docs.cloudfoundry.org/devguide/services/sharing-instances.html) within spaces. + +## Example Usage + +The following example shares a specific service instance to the given space. + +```hcl +data "cloudfoundry_service_instance" "my-redis" { + name_or_id = "my-redis" + space = cloudfoundry_space.dev-1.id +} + +resource "cloudfoundry_service_instance_sharing" "share-to-dev-2" { + service_instance_id = data.cloudfoundry_service_instance.my-redis.id + space_id = cloudfoundry_space.dev-2.id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `service_instance_id` - (Required, String) The ID of the service instance to share. +* `space_id` - (Required, String) The ID of the space to share the service instance with, the space can be in the same or different org. + +## Import + +Existing Instance Shared can be imported using the composite `id` formed +with service instance's GUID and space's GUID, seperated by a forward slash '/'. + +example: `bb4ea411-service-instance-guid/820b9339-space-guid`