From 59c45067c50d8cf305f7f62b194337001ac31bef Mon Sep 17 00:00:00 2001 From: Ludwig Patte Date: Fri, 15 Jul 2022 14:33:40 +0000 Subject: [PATCH] Add Cloud Database Ip Restriction provider --- ovh/data_cloud_project_database.go | 200 ++++++++++++++++++ ..._cloud_project_database_ip_restrictions.go | 70 ++++++ ...d_project_database_ip_restrictions_test.go | 70 ++++++ ovh/data_cloud_project_database_test.go | 95 +++++++++ ovh/data_cloud_project_databases.go | 63 ++++++ ovh/data_cloud_project_databases_test.go | 42 ++++ ovh/provider.go | 4 + ovh/provider_test.go | 7 +- ovh/resource_cloud_project_database.go | 7 +- ...e_cloud_project_database_ip_restriction.go | 189 +++++++++++++++++ ...ud_project_database_ip_restriction_test.go | 76 +++++++ ovh/resource_cloud_project_database_test.go | 22 +- ovh/types_cloud_project_database.go | 46 ++++ .../d/cloud_project_database.html.markdown | 62 ++++++ ...ect_database_ip_restrictions.html.markdown | 40 ++++ .../d/cloud_project_databases.html.markdown | 38 ++++ website/docs/index.html.markdown | 2 + .../r/cloud_project_database.html.markdown | 6 +- ...ject_database_ip_restriction.html.markdown | 50 +++++ 19 files changed, 1074 insertions(+), 15 deletions(-) create mode 100644 ovh/data_cloud_project_database.go create mode 100644 ovh/data_cloud_project_database_ip_restrictions.go create mode 100644 ovh/data_cloud_project_database_ip_restrictions_test.go create mode 100644 ovh/data_cloud_project_database_test.go create mode 100644 ovh/data_cloud_project_databases.go create mode 100644 ovh/data_cloud_project_databases_test.go create mode 100644 ovh/resource_cloud_project_database_ip_restriction.go create mode 100644 ovh/resource_cloud_project_database_ip_restriction_test.go create mode 100644 website/docs/d/cloud_project_database.html.markdown create mode 100644 website/docs/d/cloud_project_database_ip_restrictions.html.markdown create mode 100644 website/docs/d/cloud_project_databases.html.markdown create mode 100644 website/docs/r/cloud_project_database_ip_restriction.html.markdown diff --git a/ovh/data_cloud_project_database.go b/ovh/data_cloud_project_database.go new file mode 100644 index 000000000..75a0e7997 --- /dev/null +++ b/ovh/data_cloud_project_database.go @@ -0,0 +1,200 @@ +package ovh + +import ( + "fmt" + "log" + "net/url" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/ovh/terraform-provider-ovh/ovh/helpers" +) + +func dataSourceCloudProjectDatabase() *schema.Resource { + return &schema.Resource{ + Read: dataSourceCloudProjectDatabaseRead, + Schema: map[string]*schema.Schema{ + "service_name": { + Type: schema.TypeString, + Required: true, + DefaultFunc: schema.EnvDefaultFunc("OVH_CLOUD_PROJECT_SERVICE", nil), + }, + "engine": { + Type: schema.TypeString, + Description: "Name of the engine of the service", + Required: true, + }, + "cluster_id": { + Type: schema.TypeString, + Description: "Cluster ID", + Required: true, + }, + + //Computed + "backup_time": { + Type: schema.TypeString, + Description: "Time on which backups start every day", + Computed: true, + }, + "created_at": { + Type: schema.TypeString, + Description: "Date of the creation of the cluster", + Computed: true, + }, + "description": { + Type: schema.TypeString, + Description: "Description of the cluster", + Computed: true, + }, + "endpoints": { + Type: schema.TypeList, + Description: "List of all endpoints of the service", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "component": { + Type: schema.TypeString, + Description: "Type of component the URI relates to", + Computed: true, + }, + "domain": { + Type: schema.TypeString, + Description: "Domain of the cluster", + Computed: true, + }, + "path": { + Type: schema.TypeString, + Description: "Path of the endpoint", + Computed: true, + }, + "port": { + Type: schema.TypeInt, + Description: "Connection port for the endpoint", + Computed: true, + }, + "scheme": { + Type: schema.TypeString, + Description: "Scheme used to generate the URI", + Computed: true, + }, + "ssl": { + Type: schema.TypeBool, + Description: "Defines whether the endpoint uses SSL", + Computed: true, + }, + "ssl_mode": { + Type: schema.TypeString, + Description: "SSL mode used to connect to the service if the SSL is enabled", + Computed: true, + }, + "uri": { + Type: schema.TypeString, + Description: "URI of the endpoint", + Computed: true, + }, + }, + }, + }, + "flavor": { + Type: schema.TypeString, + Description: "The node flavor used for this cluster", + Computed: true, + }, + "maintenance_time": { + Type: schema.TypeString, + Description: "Time on which maintenances can start every day", + Computed: true, + }, + "network_type": { + Type: schema.TypeString, + Description: "Type of network of the cluster", + Computed: true, + }, + "nodes": { + Type: schema.TypeList, + Description: "List of nodes composing the service", + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "network_id": { + Type: schema.TypeString, + Description: "Private network ID in which the node is", + Computed: true, + }, + "region": { + Type: schema.TypeString, + Description: "Region of the node", + Computed: true, + }, + "subnet_id": { + Type: schema.TypeString, + Description: "Private subnet ID in which the node is", + Computed: true, + }, + }, + }, + }, + "plan": { + Type: schema.TypeString, + Description: "Plan of the cluster", + Computed: true, + }, + "status": { + Type: schema.TypeString, + Description: "Current status of the cluster", + Computed: true, + }, + "version": { + Type: schema.TypeString, + Description: "Version of the engine deployed on the cluster", + Computed: true, + }, + }, + } +} + +func dataSourceCloudProjectDatabaseRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + serviceName := d.Get("service_name").(string) + engine := d.Get("engine").(string) + id := d.Get("cluster_id").(string) + + serviceEndpoint := fmt.Sprintf("/cloud/project/%s/database/%s/%s", + url.PathEscape(serviceName), + url.PathEscape(engine), + url.PathEscape(id), + ) + res := &CloudProjectDatabaseResponse{} + + log.Printf("[DEBUG] Will read database %s from project: %s", id, serviceName) + if err := config.OVHClient.Get(serviceEndpoint, res); err != nil { + return helpers.CheckDeleted(d, err, serviceEndpoint) + } + + nodesEndpoint := fmt.Sprintf("%s/node", serviceEndpoint) + nodeList := &[]string{} + if err := config.OVHClient.Get(nodesEndpoint, nodeList); err != nil { + return fmt.Errorf("unable to get database %s nodes: %v", res.Id, err) + } + + if len(*nodeList) == 0 { + return fmt.Errorf("no node found for database %s", res.Id) + } + nodeEndpoint := fmt.Sprintf("%s/%s", nodesEndpoint, url.PathEscape((*nodeList)[0])) + node := &CloudProjectDatabaseNodes{} + if err := config.OVHClient.Get(nodeEndpoint, node); err != nil { + return fmt.Errorf("unable to get database %s node %s: %v", res.Id, (*nodeList)[0], err) + } + + res.Region = node.Region + + for k, v := range res.ToMap() { + if k != "id" { + d.Set(k, v) + } else { + d.SetId(fmt.Sprint(v)) + } + } + + log.Printf("[DEBUG] Read Database %+v", res) + return nil +} diff --git a/ovh/data_cloud_project_database_ip_restrictions.go b/ovh/data_cloud_project_database_ip_restrictions.go new file mode 100644 index 000000000..1a9811994 --- /dev/null +++ b/ovh/data_cloud_project_database_ip_restrictions.go @@ -0,0 +1,70 @@ +package ovh + +import ( + "fmt" + "log" + "net/url" + "sort" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/ovh/terraform-provider-ovh/ovh/helpers" + "github.com/ovh/terraform-provider-ovh/ovh/helpers/hashcode" +) + +func dataSourceCloudProjectDatabaseIpRestrictions() *schema.Resource { + return &schema.Resource{ + Read: dataSourceCloudProjectDatabaseIpRestrictionsRead, + Schema: map[string]*schema.Schema{ + "service_name": { + Type: schema.TypeString, + Required: true, + DefaultFunc: schema.EnvDefaultFunc("OVH_CLOUD_PROJECT_SERVICE", nil), + }, + "engine": { + Type: schema.TypeString, + Description: "Name of the engine of the service", + Required: true, + }, + "cluster_id": { + Type: schema.TypeString, + Description: "Cluster ID", + Required: true, + }, + + //Computed + "result": { + Type: schema.TypeList, + Description: "List of ip restriction", + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func dataSourceCloudProjectDatabaseIpRestrictionsRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + serviceName := d.Get("service_name").(string) + engine := d.Get("engine").(string) + clusterId := d.Get("cluster_id").(string) + + endpoint := fmt.Sprintf("/cloud/project/%s/database/%s/%s/ipRestriction", + url.PathEscape(serviceName), + url.PathEscape(engine), + url.PathEscape(clusterId), + ) + res := make([]string, 0) + + log.Printf("[DEBUG] Will read ip restrictions from cluster %s from project %s", clusterId, serviceName) + if err := config.OVHClient.Get(endpoint, &res); err != nil { + return helpers.CheckDeleted(d, err, endpoint) + } + + // sort.Strings sorts in place, returns nothing + sort.Strings(res) + + d.SetId(hashcode.Strings(res)) + d.Set("result", res) + + return nil +} diff --git a/ovh/data_cloud_project_database_ip_restrictions_test.go b/ovh/data_cloud_project_database_ip_restrictions_test.go new file mode 100644 index 000000000..b75708f38 --- /dev/null +++ b/ovh/data_cloud_project_database_ip_restrictions_test.go @@ -0,0 +1,70 @@ +package ovh + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +const testAccCloudProjectDatabaseIpRestrictionsDatasourceConfig_Basic = ` +resource "ovh_cloud_project_database" "db" { + service_name = "%s" + engine = "%s" + version = "%s" + plan = "essential" + nodes { + region = "%s" + } + flavor = "%s" +} + +resource "ovh_cloud_project_database_ip_restriction" "ip" { + service_name = ovh_cloud_project_database.db.service_name + engine = ovh_cloud_project_database.db.engine + cluster_id = ovh_cloud_project_database.db.id + ip = "%s" +} + +data "ovh_cloud_project_database_ip_restrictions" "ips" { + service_name = ovh_cloud_project_database_ip_restriction.ip.service_name + engine = ovh_cloud_project_database_ip_restriction.ip.engine + cluster_id = ovh_cloud_project_database_ip_restriction.ip.cluster_id +} +` + +func TestAccCloudProjectDatabaseIpRestrictionsDataSource_basic(t *testing.T) { + serviceName := os.Getenv("OVH_CLOUD_PROJECT_SERVICE_TEST") + engine := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_ENGINE_TEST") + version := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_VERSION_TEST") + region := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_REGION_TEST") + flavor := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_FLAVOR_TEST") + ip := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_IP_RESTRICTION_IP_TEST") + + config := fmt.Sprintf( + testAccCloudProjectDatabaseIpRestrictionsDatasourceConfig_Basic, + serviceName, + engine, + version, + region, + flavor, + ip, + ) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheckCloudDatabaseIpRestriction(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet( + "data.ovh_cloud_project_database_ip_restrictions.ips", + "result.#", + ), + ), + }, + }, + }) +} diff --git a/ovh/data_cloud_project_database_test.go b/ovh/data_cloud_project_database_test.go new file mode 100644 index 000000000..65250005d --- /dev/null +++ b/ovh/data_cloud_project_database_test.go @@ -0,0 +1,95 @@ +package ovh + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +const testAccCloudProjectDatabaseDatasourceConfig_Basic = ` +resource "ovh_cloud_project_database" "db" { + service_name = "%s" + description = "%s" + engine = "%s" + version = "%s" + plan = "essential" + nodes { + region = "%s" + } + flavor = "%s" +} + +data "ovh_cloud_project_database" "db" { + service_name = ovh_cloud_project_database.db.service_name + engine = ovh_cloud_project_database.db.engine + cluster_id = ovh_cloud_project_database.db.id +} +` + +func TestAccCloudProjectDatabaseDataSource_basic(t *testing.T) { + serviceName := os.Getenv("OVH_CLOUD_PROJECT_SERVICE_TEST") + engine := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_ENGINE_TEST") + version := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_VERSION_TEST") + region := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_REGION_TEST") + flavor := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_FLAVOR_TEST") + description := acctest.RandomWithPrefix(test_prefix) + + config := fmt.Sprintf( + testAccCloudProjectDatabaseDatasourceConfig_Basic, + serviceName, + description, + engine, + version, + region, + flavor, + ) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheckCloudDatabase(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet( + "data.ovh_cloud_project_database.db", "backup_time"), + resource.TestCheckResourceAttrSet( + "data.ovh_cloud_project_database.db", "created_at"), + resource.TestCheckResourceAttr( + "data.ovh_cloud_project_database.db", "description", description), + resource.TestCheckResourceAttrSet( + "data.ovh_cloud_project_database.db", "endpoints.#"), + resource.TestCheckResourceAttrSet( + "data.ovh_cloud_project_database.db", "endpoints.0.component"), + resource.TestCheckResourceAttrSet( + "data.ovh_cloud_project_database.db", "endpoints.0.domain"), + resource.TestCheckResourceAttrSet( + "data.ovh_cloud_project_database.db", "endpoints.0.ssl"), + resource.TestCheckResourceAttrSet( + "data.ovh_cloud_project_database.db", "endpoints.0.ssl_mode"), + resource.TestCheckResourceAttr( + "data.ovh_cloud_project_database.db", "engine", engine), + resource.TestCheckResourceAttr( + "data.ovh_cloud_project_database.db", "flavor", flavor), + resource.TestCheckResourceAttrSet( + "data.ovh_cloud_project_database.db", "maintenance_time"), + resource.TestCheckResourceAttrSet( + "data.ovh_cloud_project_database.db", "network_type"), + resource.TestCheckResourceAttrSet( + "data.ovh_cloud_project_database.db", "nodes.#"), + resource.TestCheckResourceAttr( + "data.ovh_cloud_project_database.db", "nodes.0.region", region), + resource.TestCheckResourceAttr( + "data.ovh_cloud_project_database.db", "plan", "essential"), + resource.TestCheckResourceAttrSet( + "data.ovh_cloud_project_database.db", "status"), + resource.TestCheckResourceAttr( + "data.ovh_cloud_project_database.db", "version", version), + ), + }, + }, + }) +} diff --git a/ovh/data_cloud_project_databases.go b/ovh/data_cloud_project_databases.go new file mode 100644 index 000000000..2023d1cee --- /dev/null +++ b/ovh/data_cloud_project_databases.go @@ -0,0 +1,63 @@ +package ovh + +import ( + "fmt" + "log" + "net/url" + "sort" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/ovh/terraform-provider-ovh/ovh/helpers" + "github.com/ovh/terraform-provider-ovh/ovh/helpers/hashcode" +) + +func dataSourceCloudProjectDatabases() *schema.Resource { + return &schema.Resource{ + Read: dataSourceCloudProjectDatabasesRead, + Schema: map[string]*schema.Schema{ + "service_name": { + Type: schema.TypeString, + Required: true, + DefaultFunc: schema.EnvDefaultFunc("OVH_CLOUD_PROJECT_SERVICE", nil), + }, + "engine": { + Type: schema.TypeString, + Description: "Name of the engine of the service", + Required: true, + }, + + //Computed + "result": { + Type: schema.TypeList, + Description: "List of database clusters uuids", + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func dataSourceCloudProjectDatabasesRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + serviceName := d.Get("service_name").(string) + engine := d.Get("engine").(string) + + serviceEndpoint := fmt.Sprintf("/cloud/project/%s/database/%s", + url.PathEscape(serviceName), + url.PathEscape(engine), + ) + res := make([]string, 0) + + log.Printf("[DEBUG] Will list databases from project: %s", serviceName) + if err := config.OVHClient.Get(serviceEndpoint, &res); err != nil { + return helpers.CheckDeleted(d, err, serviceEndpoint) + } + + // sort.Strings sorts in place, returns nothing + sort.Strings(res) + + d.SetId(hashcode.Strings(res)) + d.Set("result", res) + + return nil +} diff --git a/ovh/data_cloud_project_databases_test.go b/ovh/data_cloud_project_databases_test.go new file mode 100644 index 000000000..8e37ccf71 --- /dev/null +++ b/ovh/data_cloud_project_databases_test.go @@ -0,0 +1,42 @@ +package ovh + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +const testAccCloudProjectDatabasesDatasourceConfig_Basic = ` +data "ovh_cloud_project_databases" "dbs" { + service_name = "%s" + engine = "%s" +} +` + +func TestAccCloudProjectDatabasesDataSource_basic(t *testing.T) { + serviceName := os.Getenv("OVH_CLOUD_PROJECT_SERVICE_TEST") + engine := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_ENGINE_TEST") + config := fmt.Sprintf( + testAccCloudProjectDatabasesDatasourceConfig_Basic, + serviceName, + engine, + ) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheckCloudDatabase(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet( + "data.ovh_cloud_project_databases.dbs", + "result.#", + ), + ), + }, + }, + }) +} diff --git a/ovh/provider.go b/ovh/provider.go index eca03c485..3de3b3f57 100644 --- a/ovh/provider.go +++ b/ovh/provider.go @@ -46,6 +46,9 @@ func Provider() *schema.Provider { "ovh_cloud_project_containerregistries": dataSourceCloudProjectContainerRegistries(), "ovh_cloud_project_containerregistry": dataSourceCloudProjectContainerRegistry(), "ovh_cloud_project_containerregistry_users": dataSourceCloudProjectContainerRegistryUsers(), + "ovh_cloud_project_databases": dataSourceCloudProjectDatabases(), + "ovh_cloud_project_database": dataSourceCloudProjectDatabase(), + "ovh_cloud_project_database_ip_restrictions": dataSourceCloudProjectDatabaseIpRestrictions(), "ovh_cloud_project_failover_ip_attach": dataSourceCloudProjectFailoverIpAttach(), "ovh_cloud_project_kube": dataSourceCloudProjectKube(), "ovh_cloud_project_region": dataSourceCloudProjectRegion(), @@ -87,6 +90,7 @@ func Provider() *schema.Provider { "ovh_cloud_project_containerregistry": resourceCloudProjectContainerRegistry(), "ovh_cloud_project_containerregistry_user": resourceCloudProjectContainerRegistryUser(), "ovh_cloud_project_database": resourceCloudProjectDatabase(), + "ovh_cloud_project_database_ip_restriction": resourceCloudProjectDatabaseIpRestriction(), "ovh_cloud_project_failover_ip_attach": resourceCloudProjectFailoverIpAttach(), "ovh_cloud_project_kube": resourceCloudProjectKube(), "ovh_cloud_project_kube_nodepool": resourceCloudProjectKubeNodePool(), diff --git a/ovh/provider_test.go b/ovh/provider_test.go index 0e7e12213..0472044a3 100644 --- a/ovh/provider_test.go +++ b/ovh/provider_test.go @@ -122,13 +122,18 @@ func testAccPreCheckCloud(t *testing.T) { // Checks that the environment variables needed for the /cloud/project/{projectId}/database/ acceptance tests are set. func testAccPreCheckCloudDatabase(t *testing.T) { - testAccPreCheckCredentials(t) testAccPreCheckCloud(t) + testAccCheckCloudProjectExists(t) checkEnvOrSkip(t, "OVH_CLOUD_PROJECT_DATABASE_ENGINE_TEST") checkEnvOrSkip(t, "OVH_CLOUD_PROJECT_DATABASE_VERSION_TEST") checkEnvOrSkip(t, "OVH_CLOUD_PROJECT_DATABASE_REGION_TEST") checkEnvOrSkip(t, "OVH_CLOUD_PROJECT_DATABASE_FLAVOR_TEST") +} +// Checks that the environment variables needed for the /cloud/project/{projectId}/database/{engine}/{clusterId}/ipRestriction/ acceptance tests are set. +func testAccPreCheckCloudDatabaseIpRestriction(t *testing.T) { + testAccPreCheckCloudDatabase(t) + checkEnvOrSkip(t, "OVH_CLOUD_PROJECT_DATABASE_IP_RESTRICTION_IP_TEST") } // Checks that the environment variables needed for the /cloud/project/{projectId}/ip/failover acceptance tests diff --git a/ovh/resource_cloud_project_database.go b/ovh/resource_cloud_project_database.go index b27861286..a8ec97d27 100644 --- a/ovh/resource_cloud_project_database.go +++ b/ovh/resource_cloud_project_database.go @@ -111,19 +111,16 @@ func resourceCloudProjectDatabase() *schema.Resource { "path": { Type: schema.TypeString, Description: "Path of the endpoint", - Optional: true, Computed: true, }, "port": { Type: schema.TypeInt, Description: "Connection port for the endpoint", - Optional: true, Computed: true, }, "scheme": { Type: schema.TypeString, Description: "Scheme used to generate the URI", - Optional: true, Computed: true, }, "ssl": { @@ -134,13 +131,11 @@ func resourceCloudProjectDatabase() *schema.Resource { "ssl_mode": { Type: schema.TypeString, Description: "SSL mode used to connect to the service if the SSL is enabled", - Optional: true, Computed: true, }, "uri": { Type: schema.TypeString, Description: "URI of the endpoint", - Optional: true, Computed: true, }, }, @@ -361,7 +356,7 @@ func waitForCloudProjectDatabaseDeleted(client *ovh.Client, serviceName, engine Target: []string{"DELETED"}, Refresh: func() (interface{}, string, error) { res := &CloudProjectDatabaseResponse{} - endpoint := fmt.Sprintf("/cloud/project/%s/%s/%s", + endpoint := fmt.Sprintf("/cloud/project/%s/database/%s/%s", url.PathEscape(serviceName), url.PathEscape(engine), url.PathEscape(databaseId), diff --git a/ovh/resource_cloud_project_database_ip_restriction.go b/ovh/resource_cloud_project_database_ip_restriction.go new file mode 100644 index 000000000..42ca974c5 --- /dev/null +++ b/ovh/resource_cloud_project_database_ip_restriction.go @@ -0,0 +1,189 @@ +package ovh + +import ( + "fmt" + "log" + "net/url" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/ovh/terraform-provider-ovh/ovh/helpers" + "github.com/ovh/terraform-provider-ovh/ovh/helpers/hashcode" +) + +func resourceCloudProjectDatabaseIpRestriction() *schema.Resource { + return &schema.Resource{ + Create: resourceCloudProjectDatabaseIpRestrictionCreate, + Read: resourceCloudProjectDatabaseIpRestrictionRead, + Delete: resourceCloudProjectDatabaseIpRestrictionDelete, + Update: resourceCloudProjectDatabaseIpRestrictionUpdate, + + Importer: &schema.ResourceImporter{ + State: resourceCloudProjectDatabaseIpRestrictionImportState, + }, + + Schema: map[string]*schema.Schema{ + "service_name": { + Type: schema.TypeString, + ForceNew: true, + Required: true, + DefaultFunc: schema.EnvDefaultFunc("OVH_CLOUD_PROJECT_SERVICE", nil), + }, + "engine": { + Type: schema.TypeString, + Description: "Name of the engine of the service", + ForceNew: true, + Required: true, + }, + "cluster_id": { + Type: schema.TypeString, + Description: "Id of the database cluster", + ForceNew: true, + Required: true, + }, + "ip": { + Type: schema.TypeString, + Description: "Authorized IP", + ForceNew: true, + Required: true, + }, + "description": { + Type: schema.TypeString, + Description: "Description of the ip restriction", + Optional: true, + }, + + //Computed + "status": { + Type: schema.TypeString, + Description: "Current status of the ip restriction", + Computed: true, + }, + }, + } +} + +func resourceCloudProjectDatabaseIpRestrictionImportState(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + givenId := d.Id() + n := 4 + splitId := strings.SplitN(givenId, "/", n) + if len(splitId) != n { + return nil, fmt.Errorf("Import Id is not service_name/engine/cluster_id/ip formatted") + } + serviceName := splitId[0] + engine := splitId[1] + clusterId := splitId[2] + ip := splitId[3] + d.SetId(hashcode.Strings([]string{ip})) + d.Set("engine", engine) + d.Set("service_name", serviceName) + d.Set("cluster_id", clusterId) + d.Set("ip", ip) + + results := make([]*schema.ResourceData, 1) + results[0] = d + return results, nil +} + +func resourceCloudProjectDatabaseIpRestrictionCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + serviceName := d.Get("service_name").(string) + engine := d.Get("engine").(string) + clusterId := d.Get("cluster_id").(string) + + endpoint := fmt.Sprintf("/cloud/project/%s/database/%s/%s/ipRestriction", + url.PathEscape(serviceName), + url.PathEscape(engine), + url.PathEscape(clusterId), + ) + params := (&CloudProjectDatabaseIpRestrictionCreateOpts{}).FromResource(d) + res := &CloudProjectDatabaseIpRestrictionResponse{} + + log.Printf("[DEBUG] Will create ip restriction: %+v for cluster %s from project %s", params, clusterId, serviceName) + err := config.OVHClient.Post(endpoint, params, res) + if err != nil { + return fmt.Errorf("calling Post %s with params %s:\n\t %q", endpoint, params, err) + } + + d.SetId(hashcode.Strings([]string{res.Ip})) + + return resourceCloudProjectDatabaseIpRestrictionRead(d, meta) +} + +func resourceCloudProjectDatabaseIpRestrictionRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + serviceName := d.Get("service_name").(string) + engine := d.Get("engine").(string) + clusterId := d.Get("cluster_id").(string) + ip := d.Get("ip").(string) + + endpoint := fmt.Sprintf("/cloud/project/%s/database/%s/%s/ipRestriction/%s", + url.PathEscape(serviceName), + url.PathEscape(engine), + url.PathEscape(clusterId), + url.PathEscape(ip), + ) + res := &CloudProjectDatabaseIpRestrictionResponse{} + + log.Printf("[DEBUG] Will read ip restriction %s from cluster %s from project %s", ip, clusterId, serviceName) + if err := config.OVHClient.Get(endpoint, res); err != nil { + return helpers.CheckDeleted(d, err, endpoint) + } + + d.SetId(hashcode.Strings([]string{res.Ip})) + for k, v := range res.ToMap() { + d.Set(k, v) + } + + log.Printf("[DEBUG] Read ip restriction %+v", res) + return nil +} + +func resourceCloudProjectDatabaseIpRestrictionUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + serviceName := d.Get("service_name").(string) + engine := d.Get("engine").(string) + clusterId := d.Get("cluster_id").(string) + ip := d.Get("ip").(string) + + endpoint := fmt.Sprintf("/cloud/project/%s/database/%s/%s/ipRestriction/%s", + url.PathEscape(serviceName), + url.PathEscape(engine), + url.PathEscape(clusterId), + url.PathEscape(ip), + ) + params := (&CloudProjectDatabaseIpRestrictionUpdateOpts{}).FromResource(d) + + log.Printf("[DEBUG] Will update ip restriction: %+v from cluster %s from project %s", params, clusterId, serviceName) + err := config.OVHClient.Put(endpoint, params, nil) + if err != nil { + return fmt.Errorf("calling Put %s with params %v:\n\t %q", endpoint, params, err) + } + + return resourceCloudProjectDatabaseIpRestrictionRead(d, meta) +} + +func resourceCloudProjectDatabaseIpRestrictionDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + serviceName := d.Get("service_name").(string) + engine := d.Get("engine").(string) + clusterId := d.Get("cluster_id").(string) + ip := d.Get("ip").(string) + + endpoint := fmt.Sprintf("/cloud/project/%s/database/%s/%s/ipRestriction/%s", + url.PathEscape(serviceName), + url.PathEscape(engine), + url.PathEscape(clusterId), + url.PathEscape(ip), + ) + + log.Printf("[DEBUG] Will delete ip restriction %s from cluster %s from project %s", ip, clusterId, serviceName) + err := config.OVHClient.Delete(endpoint, nil) + if err != nil { + return helpers.CheckDeleted(d, err, endpoint) + } + + d.SetId("") + + return nil +} diff --git a/ovh/resource_cloud_project_database_ip_restriction_test.go b/ovh/resource_cloud_project_database_ip_restriction_test.go new file mode 100644 index 000000000..1d326e541 --- /dev/null +++ b/ovh/resource_cloud_project_database_ip_restriction_test.go @@ -0,0 +1,76 @@ +package ovh + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +const testAccCloudProjectDatabaseIpRestrictionConfig = ` +resource "ovh_cloud_project_database" "db" { + service_name = "%s" + engine = "%s" + version = "%s" + plan = "essential" + nodes { + region = "%s" + } + flavor = "%s" +} + +resource "ovh_cloud_project_database_ip_restriction" "ip" { + service_name = ovh_cloud_project_database.db.service_name + engine = ovh_cloud_project_database.db.engine + cluster_id = ovh_cloud_project_database.db.id + ip = "%s" + description = "%s" +} +` + +func TestAccCloudProjectDatabaseIpRestriction_basic(t *testing.T) { + serviceName := os.Getenv("OVH_CLOUD_PROJECT_SERVICE_TEST") + engine := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_ENGINE_TEST") + version := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_VERSION_TEST") + region := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_REGION_TEST") + flavor := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_FLAVOR_TEST") + ip := os.Getenv("OVH_CLOUD_PROJECT_DATABASE_IP_RESTRICTION_IP_TEST") + description := acctest.RandomWithPrefix(test_prefix) + + config := fmt.Sprintf( + testAccCloudProjectDatabaseIpRestrictionConfig, + serviceName, + engine, + version, + region, + flavor, + ip, + description, + ) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheckCloudDatabaseIpRestriction(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ovh_cloud_project_database_ip_restriction.ip", + "description", description, + ), + resource.TestCheckResourceAttr( + "ovh_cloud_project_database_ip_restriction.ip", + "ip", ip, + ), + resource.TestCheckResourceAttrSet( + "ovh_cloud_project_database_ip_restriction.ip", + "status", + ), + ), + }, + }, + }) +} diff --git a/ovh/resource_cloud_project_database_test.go b/ovh/resource_cloud_project_database_test.go index 5082459d6..f57d4e123 100644 --- a/ovh/resource_cloud_project_database_test.go +++ b/ovh/resource_cloud_project_database_test.go @@ -98,11 +98,7 @@ func TestAccCloudProjectDatabase_basic(t *testing.T) { ) resource.Test(t, resource.TestCase{ - PreCheck: func() { - testAccPreCheckCloud(t) - testAccCheckCloudProjectExists(t) - testAccPreCheckCloudDatabase(t) - }, + PreCheck: func() { testAccPreCheckCloudDatabase(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ { @@ -112,6 +108,18 @@ func TestAccCloudProjectDatabase_basic(t *testing.T) { "ovh_cloud_project_database.db", "backup_time"), resource.TestCheckResourceAttrSet( "ovh_cloud_project_database.db", "created_at"), + resource.TestCheckResourceAttr( + "ovh_cloud_project_database.db", "description", description), + resource.TestCheckResourceAttrSet( + "ovh_cloud_project_database.db", "endpoints.#"), + resource.TestCheckResourceAttrSet( + "ovh_cloud_project_database.db", "endpoints.0.component"), + resource.TestCheckResourceAttrSet( + "ovh_cloud_project_database.db", "endpoints.0.domain"), + resource.TestCheckResourceAttrSet( + "ovh_cloud_project_database.db", "endpoints.0.ssl"), + resource.TestCheckResourceAttrSet( + "ovh_cloud_project_database.db", "endpoints.0.ssl_mode"), resource.TestCheckResourceAttr( "ovh_cloud_project_database.db", "engine", engine), resource.TestCheckResourceAttr( @@ -122,6 +130,10 @@ func TestAccCloudProjectDatabase_basic(t *testing.T) { "ovh_cloud_project_database.db", "maintenance_time"), resource.TestCheckResourceAttrSet( "ovh_cloud_project_database.db", "network_type"), + resource.TestCheckResourceAttrSet( + "ovh_cloud_project_database.db", "nodes.#"), + resource.TestCheckResourceAttr( + "ovh_cloud_project_database.db", "nodes.0.region", region), resource.TestCheckResourceAttr( "ovh_cloud_project_database.db", "plan", "essential"), resource.TestCheckResourceAttr( diff --git a/ovh/types_cloud_project_database.go b/ovh/types_cloud_project_database.go index 3db9ca39a..ce967c5c2 100644 --- a/ovh/types_cloud_project_database.go +++ b/ovh/types_cloud_project_database.go @@ -3,6 +3,7 @@ package ovh import ( "errors" "fmt" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/ovh/terraform-provider-ovh/ovh/helpers" ) @@ -247,3 +248,48 @@ func checkNodesEquality(nodes []CloudProjectDatabaseNodes) error { } return nil } + +type CloudProjectDatabaseIpRestrictionResponse struct { + Description string `json:"description"` + Ip string `json:"ip"` + Status string `json:"status"` +} + +func (p *CloudProjectDatabaseIpRestrictionResponse) String() string { + return fmt.Sprintf( + "IP: %s, Status: %s, Description: %s", + p.Ip, + p.Status, + p.Description, + ) +} + +func (v CloudProjectDatabaseIpRestrictionResponse) ToMap() map[string]interface{} { + obj := make(map[string]interface{}) + + obj["description"] = v.Description + obj["ip"] = v.Ip + obj["status"] = v.Status + + return obj +} + +type CloudProjectDatabaseIpRestrictionCreateOpts struct { + Description string `json:"description"` + Ip string `json:"ip"` +} + +func (opts *CloudProjectDatabaseIpRestrictionCreateOpts) FromResource(d *schema.ResourceData) *CloudProjectDatabaseIpRestrictionCreateOpts { + opts.Description = d.Get("description").(string) + opts.Ip = d.Get("ip").(string) + return opts +} + +type CloudProjectDatabaseIpRestrictionUpdateOpts struct { + Description string `json:"description"` +} + +func (opts *CloudProjectDatabaseIpRestrictionUpdateOpts) FromResource(d *schema.ResourceData) *CloudProjectDatabaseIpRestrictionUpdateOpts { + opts.Description = d.Get("description").(string) + return opts +} diff --git a/website/docs/d/cloud_project_database.html.markdown b/website/docs/d/cloud_project_database.html.markdown new file mode 100644 index 000000000..2cf1dd858 --- /dev/null +++ b/website/docs/d/cloud_project_database.html.markdown @@ -0,0 +1,62 @@ +--- +layout: "ovh" +page_title: "OVH: cloud_project_database" +sidebar_current: "docs-ovh-datasource-cloud-project-database-x" +description: |- + Get information about a managed database cluster in a public cloud project. +--- + +# cloud_project_database (Data Source) + +Use this data source to get the managed database of a public cloud project. + +## Example Usage + +To get information of a database cluster service: +```hcl +data "ovh_cloud_project_database" "db" { + service_name = "XXXXXX" + engine = "YYYY" + cluster_id = "ZZZZ" +} +``` + +## Argument Reference + + +* `service_name` - The id of the public cloud project. If omitted, + the `OVH_CLOUD_PROJECT_SERVICE` environment variable is used. + +* `engine` - The database engine you want to get information. To get a full list of available engine visit. +[public documentation](https://docs.ovh.com/gb/en/publiccloud/databases). + +* `cluster_id` - Cluster ID + + +## Attributes Reference + + +The following attributes are exported: + +* `id` - Public Cloud Database Service ID +* `service_name` - See Argument Reference above. +* `backup_time` - Time on which backups start every day. +* `created_at` - Date of the creation of the cluster. +* `description` - See Argument Reference above. +* `endpoints` - List of all endpoints objects of the service. + * `component` - Type of component the URI relates to. + * `domain` - Domain of the cluster. + * `path` - Path of the endpoint. + * `port` - Connection port for the endpoint. + * `scheme` - Scheme used to generate the URI. + * `ssl` - Defines whether the endpoint uses SSL. + * `ssl_mode` - SSL mode used to connect to the service if the SSL is enabled. + * `uri` - URI of the endpoint. +* `engine` - See Argument Reference above. +* `flavor` - See Argument Reference above. +* `maintenance_time` - Time on which maintenances can start every day. +* `network_type` - Type of network of the cluster. +* `nodes` - See Argument Reference above. +* `plan` - See Argument Reference above. +* `status` - Current status of the cluster. +* `version` - See Argument Reference above. diff --git a/website/docs/d/cloud_project_database_ip_restrictions.html.markdown b/website/docs/d/cloud_project_database_ip_restrictions.html.markdown new file mode 100644 index 000000000..fa88f9e06 --- /dev/null +++ b/website/docs/d/cloud_project_database_ip_restrictions.html.markdown @@ -0,0 +1,40 @@ +--- +layout: "ovh" +page_title: "OVH: cloud_project_database_ip_restrictions" +sidebar_current: "docs-ovh-datasource-cloud-project-database-ip-restrictions" +description: |- + Get the list of ip restrictions associated with a public cloud project. +--- + +# ovh_cloud_project_databases (Data Source) + +Use the list of ip restrictions associated with a public cloud project. + +## Example Usage + +To get list ip restriction on a database cluster service: +```hcl +data "ovh_cloud_project_database_ip_restrictions" "iprestrictions" { + service_name = "XXXXXX" + engine = "YYYY" + cluster_id = "ZZZZ" +} +``` + +## Argument Reference + +* `service_name` - The id of the public cloud project. If omitted, + the `OVH_CLOUD_PROJECT_SERVICE` environment variable is used. + +* `engine` - The engine of the database cluster you want to list ip restrictions. To get a full list of available engine visit. +[public documentation](https://docs.ovh.com/gb/en/publiccloud/databases). + +* `cluster_id` - Cluster ID + + +## Attributes Reference + +`id` is set to the md5 sum of the list of all ip restrictions. In addition, +the following attributes are exported: + +* `result` - The list of ip restriction of the database associated with the project. diff --git a/website/docs/d/cloud_project_databases.html.markdown b/website/docs/d/cloud_project_databases.html.markdown new file mode 100644 index 000000000..5e7500125 --- /dev/null +++ b/website/docs/d/cloud_project_databases.html.markdown @@ -0,0 +1,38 @@ +--- +layout: "ovh" +page_title: "OVH: cloud_project_databases" +sidebar_current: "docs-ovh-datasource-cloud-project-databases" +description: |- + Get the list of managed database cluster associated with a public cloud project. +--- + +# ovh_cloud_project_databases (Data Source) + +Use this data source to get the list of managed databases of a public cloud project. + +## Example Usage + +To get list of database clusters service: +```hcl +data "ovh_cloud_project_databases" "dbs" { + service_name = "XXXXXX" + engine = "YYYY" +} +``` + +## Argument Reference + + +* `service_name` - The id of the public cloud project. If omitted, + the `OVH_CLOUD_PROJECT_SERVICE` environment variable is used. + +* `engine` - The database engine you want to list. To get a full list of available engine visit. +[public documentation](https://docs.ovh.com/gb/en/publiccloud/databases). + + +## Attributes Reference + +`id` is set to the md5 sum of the list of all databases ids. In addition, +the following attributes are exported: + +* `result` - The list of managed databases ids of the project. diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index 3588cefbc..3f2f3e697 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -129,6 +129,8 @@ variables must also be set: * `OVH_CLOUD_PROJECT_DATABASE_FLAVOR_TEST` - The node flavor of the database service to test. +* `OVH_CLOUD_PROJECT_DATABASE_IP_RESTRICTION_IP_TEST` - The ip restriction to test. + * `OVH_CLOUD_PROJECT_FAILOVER_IP_TEST` - The ip address of your public cloud failover ip. * `OVH_CLOUD_PROJECT_FAILOVER_IP_ROUTED_TO_1_TEST` - The GUID of an instance to which failover IP addresses can be attached diff --git a/website/docs/r/cloud_project_database.html.markdown b/website/docs/r/cloud_project_database.html.markdown index a3cfed473..ff91c7e57 100644 --- a/website/docs/r/cloud_project_database.html.markdown +++ b/website/docs/r/cloud_project_database.html.markdown @@ -3,7 +3,7 @@ layout: "ovh" page_title: "OVH: cloud_project_database" sidebar_current: "docs-ovh-resource-cloud-project-database-x" description: |- -Creates a managed database in a public cloud project. + Creates a managed database cluster in a public cloud project. --- # ovh_cloud_project_database @@ -45,9 +45,9 @@ resource "ovh_cloud_project_database" "postgresql" { To deploy an enterprise MongoDB service with three nodes on private network: ```hcl -resource "ovh_cloud_project_database" "postgresql" { +resource "ovh_cloud_project_database" "mongodb" { service_name = var.openstack_infos.project_id - description = "my-first-postgresql" + description = "my-first-mongodb" engine = "mongodb" version = "5.0" plan = "enterprise" diff --git a/website/docs/r/cloud_project_database_ip_restriction.html.markdown b/website/docs/r/cloud_project_database_ip_restriction.html.markdown new file mode 100644 index 000000000..73c0cfadf --- /dev/null +++ b/website/docs/r/cloud_project_database_ip_restriction.html.markdown @@ -0,0 +1,50 @@ +--- +layout: "ovh" +page_title: "OVH: cloud_project_database_ip_restriction" +sidebar_current: "docs-ovh-resource-cloud-project-database-ip-restriction" +description: |- + Creates an ip restriction for a database cluster associated with a public cloud project. +--- + +# ovh_cloud_project_database_ip_restriction + +Creates an ip restriction for a database cluster associated with a public cloud project. + +## Example Usage + +```hcl +data "ovh_cloud_project_database" "db" { + service_name = "XXXX" + engine = "YYYY" + cluster_id = "ZZZZ" +} + +resource "ovh_cloud_project_database_ip_restriction" "iprestriction" { + service_name = ovh_cloud_project_database.db.service_name + engine = ovh_cloud_project_database.database.engine + cluster_id = ovh_cloud_project_database.db.cluster_id + ip = "111.222.233.244/8" +} +``` + +## Argument Reference + +* `service_name` - The id of the public cloud project. If omitted, + the `OVH_CLOUD_PROJECT_SERVICE` environment variable is used. + +* `engine` - The engine of the database cluster you want to add an Ip restriction. To get a full list of available engine visit. +[public documentation](https://docs.ovh.com/gb/en/publiccloud/databases). + +* `cluster_id` - Cluster ID. + +* `ip` - Authorized IP. + +`description` - (Optional) Description of the ip restriction. + +## Attributes Reference + +The following attributes are exported: + +* `description` - See Argument Reference above. +* `ip` - See Argument Reference above. +* `status` - Current status of the ip restriction.