diff --git a/docs/data-sources/gcore_storage_s3.md b/docs/data-sources/gcore_storage_s3.md new file mode 100644 index 0000000..a53c69b --- /dev/null +++ b/docs/data-sources/gcore_storage_s3.md @@ -0,0 +1,47 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "gcore_storage_s3 Data Source - terraform-provider-gcorelabs" +subcategory: "" +description: |- + Represent s3 storage resource. https://storage.gcorelabs.com/storage/list +--- + +# gcore_storage_s3 (Data Source) + +Represent s3 storage resource. https://storage.gcorelabs.com/storage/list + +## Example Usage + +```terraform +provider gcore { + user_name = "test" + password = "test" + permanent_api_token="123$321" // https://support.gcorelabs.com/hc/en-us/articles/360018625617-API-tokens + ignore_creds_auth_error=true // if you want to manage storage resource only and provide permanent_api_token without user_name & password + gcore_platform = "https://api.gcdn.co" + gcore_storage_api = "https://storage.gcorelabs.com/api" +} + +data "gcore_storage_s3" "example_s3" { + name = "example" +} +``` + + +## Schema + +### Optional + +- **id** (String) The ID of this resource. +- **name** (String) A name of new storage resource. +- **storage_id** (Number) An id of new storage resource. + +### Read-Only + +- **client_id** (Number) An client id of new storage resource. +- **generated_endpoint** (String) A s3 entry point for new storage resource. +- **generated_http_endpoint** (String) A http s3 entry point for new storage resource. +- **generated_s3_endpoint** (String) A s3 endpoint for new storage resource. +- **location** (String) A location of new storage resource. One of (s-ed1, s-darz1, s-ws1) + + diff --git a/docs/data-sources/gcore_storage_sftp.md b/docs/data-sources/gcore_storage_sftp.md new file mode 100644 index 0000000..19c7791 --- /dev/null +++ b/docs/data-sources/gcore_storage_sftp.md @@ -0,0 +1,49 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "gcore_storage_sftp Data Source - terraform-provider-gcorelabs" +subcategory: "" +description: |- + Represent sftp storage resource. https://storage.gcorelabs.com/storage/list +--- + +# gcore_storage_sftp (Data Source) + +Represent sftp storage resource. https://storage.gcorelabs.com/storage/list + +## Example Usage + +```terraform +provider gcore { + user_name = "test" + password = "test" + permanent_api_token="123$321" // https://support.gcorelabs.com/hc/en-us/articles/360018625617-API-tokens + ignore_creds_auth_error=true // if you want to manage storage resource only and provide permanent_api_token without user_name & password + gcore_platform = "https://api.gcdn.co" + gcore_storage_api = "https://storage.gcorelabs.com/api" +} + +data "gcore_storage_sftp" "example_sftp" { + name = "example" +} +``` + + +## Schema + +### Optional + +- **id** (String) The ID of this resource. +- **name** (String) A name of storage resource. +- **storage_id** (Number) An id of storage resource. + +### Read-Only + +- **client_id** (Number) An client id of storage resource. +- **generated_http_endpoint** (String) A http sftp entry point for new storage resource. +- **generated_sftp_endpoint** (String) A ssh sftp entry point for new storage resource. +- **http_expires_header_value** (String) A expires date of storage resource. +- **http_servername_alias** (String) An alias of storage resource. +- **location** (String) A location of new storage resource. One of (ams, sin, fra, mia) +- **ssh_key_id** (List of Number) An ssh keys IDs to link with new sftp storage resource only. https://storage.gcorelabs.com/ssh-key/list + + diff --git a/docs/data-sources/gcore_storage_sftp_key.md b/docs/data-sources/gcore_storage_sftp_key.md new file mode 100644 index 0000000..610304e --- /dev/null +++ b/docs/data-sources/gcore_storage_sftp_key.md @@ -0,0 +1,45 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "gcore_storage_sftp_key Data Source - terraform-provider-gcorelabs" +subcategory: "" +description: |- + Represent storage key resource. https://storage.gcorelabs.com/ssh-key/list +--- + +# gcore_storage_sftp_key (Data Source) + +Represent storage key resource. https://storage.gcorelabs.com/ssh-key/list + +## Example Usage + +```terraform +provider gcore { + user_name = "test" + password = "test" + permanent_api_token="123$321" // https://support.gcorelabs.com/hc/en-us/articles/360018625617-API-tokens + ignore_creds_auth_error=true // if you want to manage storage resource only and provide permanent_api_token without user_name & password + gcore_platform = "https://api.gcdn.co" + gcore_storage_api = "https://storage.gcorelabs.com/api" +} + +data "gcore_storage_sftp_key" "example_key" { + name = "example" +} +``` + + +## Schema + +### Required + +- **name** (String) A name of storage key resource. + +### Optional + +- **id** (String) The ID of this resource. + +### Read-Only + +- **key_id** (Number) An id of of storage key resource. + + diff --git a/docs/resources/gcore_storage_s3.md b/docs/resources/gcore_storage_s3.md index b2f7c96..259d858 100644 --- a/docs/resources/gcore_storage_s3.md +++ b/docs/resources/gcore_storage_s3.md @@ -41,6 +41,8 @@ resource "gcore_storage_s3" "example_s3" { - **client_id** (Number) An client id of new storage resource. - **generated_access_key** (String) A s3 access key for new storage resource. - **generated_endpoint** (String) A s3 entry point for new storage resource. +- **generated_http_endpoint** (String) A http s3 entry point for new storage resource. +- **generated_s3_endpoint** (String) A s3 endpoint for new storage resource. - **generated_secret_key** (String) A s3 secret key for new storage resource. - **id** (String) The ID of this resource. - **storage_id** (Number) An id of new storage resource. diff --git a/docs/resources/gcore_storage_sftp.md b/docs/resources/gcore_storage_sftp.md index 9d74aaf..5edcb65 100644 --- a/docs/resources/gcore_storage_sftp.md +++ b/docs/resources/gcore_storage_sftp.md @@ -40,13 +40,15 @@ resource "gcore_storage_sftp" "example_sftp" { ### Optional - **client_id** (Number) An client id of new storage resource. -- **generated_endpoint** (String) A sftp entry point for new storage resource. +- **generated_http_endpoint** (String) A http sftp entry point for new storage resource. - **generated_password** (Boolean) An auto generated sftp password for new storage resource. +- **generated_sftp_endpoint** (String) A ssh sftp entry point for new storage resource. - **http_expires_header_value** (String) A expires date of storage resource. - **http_servername_alias** (String) An alias of storage resource. - **id** (String) The ID of this resource. - **password** (String) A sftp password for new storage resource. - **ssh_key_id** (List of Number) An ssh keys IDs to link with new sftp storage resource only. https://storage.gcorelabs.com/ssh-key/list - **storage_id** (Number) An id of new storage resource. +- **update_after_create** (Boolean) A temporary flag. An internal cheat, to skip update ssh keys. Skip it. diff --git a/examples/data-sources/gcore_storage_s3/data-source.tf b/examples/data-sources/gcore_storage_s3/data-source.tf new file mode 100644 index 0000000..d867bba --- /dev/null +++ b/examples/data-sources/gcore_storage_s3/data-source.tf @@ -0,0 +1,12 @@ +provider gcore { + user_name = "test" + password = "test" + permanent_api_token="123$321" // https://support.gcorelabs.com/hc/en-us/articles/360018625617-API-tokens + ignore_creds_auth_error=true // if you want to manage storage resource only and provide permanent_api_token without user_name & password + gcore_platform = "https://api.gcdn.co" + gcore_storage_api = "https://storage.gcorelabs.com/api" +} + +data "gcore_storage_s3" "example_s3" { + name = "example" +} diff --git a/examples/data-sources/gcore_storage_sftp/data-source.tf b/examples/data-sources/gcore_storage_sftp/data-source.tf new file mode 100644 index 0000000..c409a99 --- /dev/null +++ b/examples/data-sources/gcore_storage_sftp/data-source.tf @@ -0,0 +1,12 @@ +provider gcore { + user_name = "test" + password = "test" + permanent_api_token="123$321" // https://support.gcorelabs.com/hc/en-us/articles/360018625617-API-tokens + ignore_creds_auth_error=true // if you want to manage storage resource only and provide permanent_api_token without user_name & password + gcore_platform = "https://api.gcdn.co" + gcore_storage_api = "https://storage.gcorelabs.com/api" +} + +data "gcore_storage_sftp" "example_sftp" { + name = "example" +} diff --git a/examples/data-sources/gcore_storage_sftp_key/data-source.tf b/examples/data-sources/gcore_storage_sftp_key/data-source.tf new file mode 100644 index 0000000..4591d75 --- /dev/null +++ b/examples/data-sources/gcore_storage_sftp_key/data-source.tf @@ -0,0 +1,12 @@ +provider gcore { + user_name = "test" + password = "test" + permanent_api_token="123$321" // https://support.gcorelabs.com/hc/en-us/articles/360018625617-API-tokens + ignore_creds_auth_error=true // if you want to manage storage resource only and provide permanent_api_token without user_name & password + gcore_platform = "https://api.gcdn.co" + gcore_storage_api = "https://storage.gcorelabs.com/api" +} + +data "gcore_storage_sftp_key" "example_key" { + name = "example" +} diff --git a/gcore/data_source_gcore_storage_s3.go b/gcore/data_source_gcore_storage_s3.go new file mode 100644 index 0000000..46592d6 --- /dev/null +++ b/gcore/data_source_gcore_storage_s3.go @@ -0,0 +1,67 @@ +package gcore + +import ( + "github.com/hashicorp/go-cty/cty" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "regexp" +) + +func dataSourceStorageS3() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + StorageSchemaId: { + Type: schema.TypeInt, + Optional: true, + AtLeastOneOf: []string{ + StorageSchemaId, + StorageSchemaName, + }, + Description: "An id of new storage resource.", + }, + StorageSchemaClientId: { + Type: schema.TypeInt, + Computed: true, + Description: "An client id of new storage resource.", + }, + StorageSchemaName: { + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: func(i interface{}, path cty.Path) diag.Diagnostics { + storageName := i.(string) + if !regexp.MustCompile(`^[\w\-]+$`).MatchString(storageName) || len(storageName) > 255 { + return diag.Errorf("storage name can't be empty and can have only letters, numbers, dashes and underscores, it also should be less than 256 symbols") + } + return nil + }, + AtLeastOneOf: []string{ + StorageSchemaId, + StorageSchemaName, + }, + Description: "A name of new storage resource.", + }, + StorageSchemaLocation: { + Type: schema.TypeString, + Computed: true, + Description: "A location of new storage resource. One of (s-ed1, s-darz1, s-ws1)", + }, + StorageSchemaGenerateHTTPEndpoint: { + Type: schema.TypeString, + Computed: true, + Description: "A http s3 entry point for new storage resource.", + }, + StorageSchemaGenerateS3Endpoint: { + Type: schema.TypeString, + Computed: true, + Description: "A s3 endpoint for new storage resource.", + }, + StorageSchemaGenerateEndpoint: { + Type: schema.TypeString, + Computed: true, + Description: "A s3 entry point for new storage resource.", + }, + }, + ReadContext: resourceStorageS3Read, + Description: "Represent s3 storage resource. https://storage.gcorelabs.com/storage/list", + } +} diff --git a/gcore/data_source_gcore_storage_s3_test.go b/gcore/data_source_gcore_storage_s3_test.go new file mode 100644 index 0000000..54e6b1e --- /dev/null +++ b/gcore/data_source_gcore_storage_s3_test.go @@ -0,0 +1,83 @@ +package gcore + +import ( + "context" + "fmt" + "github.com/G-Core/gcorelabs-storage-sdk-go/swagger/client/storage" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "testing" + "time" +) + +func TestStorageS3DataSource(t *testing.T) { + random := time.Now().Nanosecond() + resourceName := fmt.Sprintf("gcore_storage_s3.terraformtest%d_s3", random) + dataSourceName := fmt.Sprintf("data.gcore_storage_s3.terraformtest%d_s3_data", random) + + templateCreate := func() string { + return fmt.Sprintf(` +resource "gcore_storage_s3" "terraformtest%d_s3" { + name = "terraformtest%d" + location = "s-ed1" +} + `, random, random) + } + + templateRead := func() string { + return fmt.Sprintf(` +data "gcore_storage_s3" "terraformtest%d_s3_data" { + name = "terraformtest%d" +} + `, random, random) + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheckVars(t, GCORE_USERNAME_VAR, GCORE_PASSWORD_VAR, GCORE_STORAGE_URL_VAR) + }, + CheckDestroy: func(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + for _, rs := range s.RootModule().Resources { + if rs.Type != "gcore_storage_s3" { + continue + } + opts := []func(opt *storage.StorageListHTTPV2Params){ + func(opt *storage.StorageListHTTPV2Params) { opt.Context = ctx }, + func(opt *storage.StorageListHTTPV2Params) { opt.ID = &rs.Primary.ID }, + } + storages, err := config.StorageClient.StoragesList(opts...) + if err != nil { + return fmt.Errorf("find storage: %w", err) + } + if len(storages) == 0 { + return nil + } + if storages[0].ProvisioningStatus == "ok" { + return fmt.Errorf("storage #%s wasn't deleted correctrly", rs.Primary.ID) + } + } + return nil + }, + ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: templateCreate(), + Check: resource.ComposeTestCheckFunc( + testAccCheckResourceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, StorageSchemaLocation, "s-ed1"), + ), + }, + { + Config: templateRead(), + Check: resource.ComposeTestCheckFunc( + testAccCheckResourceExists(dataSourceName), + resource.TestCheckResourceAttr(dataSourceName, StorageSchemaLocation, "s-ed1"), + ), + }, + }, + }) +} diff --git a/gcore/data_source_gcore_storage_sftp.go b/gcore/data_source_gcore_storage_sftp.go new file mode 100644 index 0000000..8a64344 --- /dev/null +++ b/gcore/data_source_gcore_storage_sftp.go @@ -0,0 +1,80 @@ +package gcore + +import ( + "github.com/hashicorp/go-cty/cty" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "regexp" +) + +func dataSourceStorageSFTP() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + StorageSchemaId: { + Type: schema.TypeInt, + Optional: true, + AtLeastOneOf: []string{ + StorageSchemaId, + StorageSchemaName, + }, + Description: "An id of storage resource.", + }, + StorageSchemaClientId: { + Type: schema.TypeInt, + Computed: true, + Description: "An client id of storage resource.", + }, + StorageSchemaName: { + Type: schema.TypeString, + Optional: true, + AtLeastOneOf: []string{ + StorageSchemaId, + StorageSchemaName, + }, + ValidateDiagFunc: func(i interface{}, path cty.Path) diag.Diagnostics { + storageName := i.(string) + if !regexp.MustCompile(`^[a-z0-9\-]+$`).MatchString(storageName) || len(storageName) > 26 { + return diag.Errorf("sftp storage name can't be empty and can have only lowercase letters, numbers and dashes; it also must be less than 27 characters length") + } + return nil + }, + Description: "A name of storage resource.", + }, + StorageSFTPSchemaServerAlias: { + Type: schema.TypeString, + Computed: true, + Description: "An alias of storage resource.", + }, + StorageSFTPSchemaExpires: { + Type: schema.TypeString, + Computed: true, + Description: "A expires date of storage resource.", + }, + StorageSchemaLocation: { + Type: schema.TypeString, + Computed: true, + Description: "A location of new storage resource. One of (ams, sin, fra, mia)", + }, + StorageSFTPSchemaKeyId: { + Type: schema.TypeList, + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + Computed: true, + Description: "An ssh keys IDs to link with new sftp storage resource only. https://storage.gcorelabs.com/ssh-key/list", + }, + StorageSchemaGenerateHTTPEndpoint: { + Type: schema.TypeString, + Computed: true, + Description: "A http sftp entry point for new storage resource.", + }, + StorageSchemaGenerateSFTPEndpoint: { + Type: schema.TypeString, + Computed: true, + Description: "A ssh sftp entry point for new storage resource.", + }, + }, + ReadContext: resourceStorageSFTPRead, + Description: "Represent sftp storage resource. https://storage.gcorelabs.com/storage/list", + } +} diff --git a/gcore/data_source_gcore_storage_sftp_key.go b/gcore/data_source_gcore_storage_sftp_key.go new file mode 100644 index 0000000..815e62e --- /dev/null +++ b/gcore/data_source_gcore_storage_sftp_key.go @@ -0,0 +1,34 @@ +package gcore + +import ( + "github.com/hashicorp/go-cty/cty" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "regexp" +) + +func dataSourceStorageSFTPKey() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + StorageKeySchemaName: { + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: func(i interface{}, path cty.Path) diag.Diagnostics { + name := i.(string) + if !regexp.MustCompile(`^[\w\-]+$`).MatchString(name) || len(name) > 127 { + return diag.Errorf("key name can't be empty and can have only letters, numbers, dashes and underscores, it also should be less than 128 symbols") + } + return nil + }, + Description: "A name of storage key resource.", + }, + StorageKeySchemaId: { + Type: schema.TypeInt, + Computed: true, + Description: "An id of of storage key resource.", + }, + }, + ReadContext: resourceStorageSFTPKeyRead, + Description: "Represent storage key resource. https://storage.gcorelabs.com/ssh-key/list", + } +} diff --git a/gcore/data_source_gcore_storage_sftp_key_test.go b/gcore/data_source_gcore_storage_sftp_key_test.go new file mode 100644 index 0000000..8afca13 --- /dev/null +++ b/gcore/data_source_gcore_storage_sftp_key_test.go @@ -0,0 +1,72 @@ +package gcore + +import ( + "context" + "fmt" + key2 "github.com/G-Core/gcorelabs-storage-sdk-go/swagger/client/key" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "testing" + "time" +) + +func TestStorageSFTPKeyDataSource(t *testing.T) { + random := time.Now().Nanosecond() + name := fmt.Sprintf("terraformtestsftpkey%d", random) + + dataSourceName := fmt.Sprintf("data.gcore_storage_sftp_key.%s_data", name) + key := `ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSUGPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XAt3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/EnmZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbxNrRFi9wrf+M7Q== schacon@mylaptop.local` + + cfg, err := createTestConfig() + if err != nil { + t.Fatal("create conf", err) + } + opts := []func(params *key2.KeyCreateHTTPParams){ + func(params *key2.KeyCreateHTTPParams) { + params.Context = context.Background() + params.Body.Name = name + params.Body.Key = key + }, + } + k, err := cfg.StorageClient.CreateKey(opts...) + if err != nil { + t.Fatal("create key", err) + } + + templateRead := func() string { + return fmt.Sprintf(` +data "gcore_storage_sftp_key" "%s_data" { + name = "%s" +} + `, name, name) + } + + defer func() { + opts := []func(params *key2.KeyDeleteHTTPParams){ + func(params *key2.KeyDeleteHTTPParams) { + params.Context = context.Background() + params.ID = k.ID + }, + } + err = cfg.StorageClient.DeleteKey(opts...) + if err != nil { + t.Fatal("delete key", err) + } + }() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheckVars(t, GCORE_USERNAME_VAR, GCORE_PASSWORD_VAR, GCORE_STORAGE_URL_VAR) + }, + ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: templateRead(), + Check: resource.ComposeTestCheckFunc( + testAccCheckResourceExists(dataSourceName), + resource.TestCheckResourceAttr(dataSourceName, StorageKeySchemaName, name), + resource.TestCheckResourceAttr(dataSourceName, StorageKeySchemaId, fmt.Sprint(k.ID)), + ), + }, + }, + }) +} diff --git a/gcore/data_source_gcore_storage_sftp_test.go b/gcore/data_source_gcore_storage_sftp_test.go new file mode 100644 index 0000000..237a089 --- /dev/null +++ b/gcore/data_source_gcore_storage_sftp_test.go @@ -0,0 +1,86 @@ +package gcore + +import ( + "context" + "fmt" + "github.com/G-Core/gcorelabs-storage-sdk-go/swagger/client/storage" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "testing" + "time" +) + +func TestStorageSFTPDataSource(t *testing.T) { + random := time.Now().Nanosecond() + name := fmt.Sprintf("terraformtestsftp%d", random) + location := "mia" + + resourceName := fmt.Sprintf("gcore_storage_sftp.%s_sftp", name) + dataSourceName := fmt.Sprintf("data.gcore_storage_sftp.%s_sftp_data", name) + + templateCreate := func() string { + return fmt.Sprintf(` +resource "gcore_storage_sftp" "%s_sftp" { + name = "%s" + location = "%s" +} + `, name, name, location) + } + + templateRead := func() string { + return fmt.Sprintf(` +data "gcore_storage_sftp" "%s_sftp_data" { + name = "%s" +} + `, name, name) + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheckVars(t, GCORE_USERNAME_VAR, GCORE_PASSWORD_VAR, GCORE_STORAGE_URL_VAR) + }, + CheckDestroy: func(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + for _, rs := range s.RootModule().Resources { + if rs.Type != "gcore_storage_sftp" { + continue + } + opts := []func(opt *storage.StorageListHTTPV2Params){ + func(opt *storage.StorageListHTTPV2Params) { opt.Context = ctx }, + func(opt *storage.StorageListHTTPV2Params) { opt.ID = &rs.Primary.ID }, + } + storages, err := config.StorageClient.StoragesList(opts...) + if err != nil { + return fmt.Errorf("find storage: %w", err) + } + if len(storages) == 0 { + return nil + } + if storages[0].ProvisioningStatus == "ok" { + return fmt.Errorf("storage #%s wasn't deleted correctrly", rs.Primary.ID) + } + } + return nil + }, + ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: templateCreate(), + Check: resource.ComposeTestCheckFunc( + testAccCheckResourceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, StorageSchemaLocation, location), + ), + }, + { + Config: templateRead(), + Check: resource.ComposeTestCheckFunc( + testAccCheckResourceExists(dataSourceName), + resource.TestCheckResourceAttr(dataSourceName, StorageSchemaLocation, location), + ), + }, + }, + }) +} diff --git a/gcore/provider.go b/gcore/provider.go index 84319c4..d10037c 100644 --- a/gcore/provider.go +++ b/gcore/provider.go @@ -103,21 +103,24 @@ func Provider() *schema.Provider { "gcore_cdn_sslcert": resourceCDNCert(), }, DataSourcesMap: map[string]*schema.Resource{ - "gcore_project": dataSourceProject(), - "gcore_region": dataSourceRegion(), - "gcore_securitygroup": dataSourceSecurityGroup(), - "gcore_image": dataSourceImage(), - "gcore_volume": dataSourceVolume(), - "gcore_network": dataSourceNetwork(), - "gcore_subnet": dataSourceSubnet(), - "gcore_router": dataSourceRouter(), - "gcore_loadbalancer": dataSourceLoadBalancer(), - "gcore_lblistener": dataSourceLBListener(), - "gcore_lbpool": dataSourceLBPool(), - "gcore_instance": dataSourceInstance(), - "gcore_floatingip": dataSourceFloatingIP(), - "gcore_reservedfixedip": dataSourceReservedFixedIP(), - "gcore_servergroup": dataSourceServerGroup(), + "gcore_project": dataSourceProject(), + "gcore_region": dataSourceRegion(), + "gcore_securitygroup": dataSourceSecurityGroup(), + "gcore_image": dataSourceImage(), + "gcore_volume": dataSourceVolume(), + "gcore_network": dataSourceNetwork(), + "gcore_subnet": dataSourceSubnet(), + "gcore_router": dataSourceRouter(), + "gcore_loadbalancer": dataSourceLoadBalancer(), + "gcore_lblistener": dataSourceLBListener(), + "gcore_lbpool": dataSourceLBPool(), + "gcore_instance": dataSourceInstance(), + "gcore_floatingip": dataSourceFloatingIP(), + "gcore_storage_s3": dataSourceStorageS3(), + "gcore_storage_sftp": dataSourceStorageSFTP(), + "gcore_storage_sftp_key": dataSourceStorageSFTPKey(), + "gcore_reservedfixedip": dataSourceReservedFixedIP(), + "gcore_servergroup": dataSourceServerGroup(), }, ConfigureContextFunc: providerConfigure, } diff --git a/gcore/provider_test.go b/gcore/provider_test.go index a817ce6..003dbd5 100644 --- a/gcore/provider_test.go +++ b/gcore/provider_test.go @@ -2,6 +2,7 @@ package gcore import ( "fmt" + storageSDK "github.com/G-Core/gcorelabs-storage-sdk-go" "net/http" "os" "strconv" @@ -284,9 +285,17 @@ func createTestConfig() (*Config, error) { })) cdnService := gcdn.NewService(cdnProvider) + storageAPI := GCORE_STORAGE_API + stHost, stPath, err := ExtractHosAndPath(storageAPI) + var storageClient *storageSDK.SDK + if err == nil { + storageClient = storageSDK.NewSDK(stHost, stPath, storageSDK.WithBearerAuth(provider.AccessToken)) + } + config := Config{ - Provider: provider, - CDNClient: cdnService, + Provider: provider, + CDNClient: cdnService, + StorageClient: storageClient, } return &config, err diff --git a/gcore/resource_gcore_storage_s3.go b/gcore/resource_gcore_storage_s3.go index 3fd0823..81bccf9 100644 --- a/gcore/resource_gcore_storage_s3.go +++ b/gcore/resource_gcore_storage_s3.go @@ -15,14 +15,16 @@ import ( ) const ( - StorageS3SchemaGenerateAccessKey = "generated_access_key" - StorageS3SchemaGenerateSecretKey = "generated_secret_key" - - StorageSchemaGenerateEndpoint = "generated_endpoint" - StorageSchemaLocation = "location" - StorageSchemaName = "name" - StorageSchemaId = "storage_id" - StorageSchemaClientId = "client_id" + StorageS3SchemaGenerateAccessKey = "generated_access_key" + StorageS3SchemaGenerateSecretKey = "generated_secret_key" + StorageSchemaGenerateHTTPEndpoint = "generated_http_endpoint" + StorageSchemaGenerateS3Endpoint = "generated_s3_endpoint" + StorageSchemaGenerateEndpoint = "generated_endpoint" + + StorageSchemaLocation = "location" + StorageSchemaName = "name" + StorageSchemaId = "storage_id" + StorageSchemaClientId = "client_id" ) func resourceStorageS3() *schema.Resource { @@ -81,6 +83,18 @@ func resourceStorageS3() *schema.Resource { Computed: true, Description: "A s3 secret key for new storage resource.", }, + StorageSchemaGenerateHTTPEndpoint: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "A http s3 entry point for new storage resource.", + }, + StorageSchemaGenerateS3Endpoint: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "A s3 endpoint for new storage resource.", + }, StorageSchemaGenerateEndpoint: { Type: schema.TypeString, Optional: true, @@ -128,6 +142,8 @@ func resourceStorageS3Create(ctx context.Context, d *schema.ResourceData, m inte _ = d.Set(StorageS3SchemaGenerateSecretKey, result.Credentials.S3.SecretKey) } _ = d.Set(StorageSchemaGenerateEndpoint, fmt.Sprintf("%s.cloud.gcore.lu/%s", result.Location, result.Name)) + _ = d.Set(StorageSchemaGenerateHTTPEndpoint, fmt.Sprintf("https://%s.cloud.gcore.lu/{bucket_name}", result.Location)) + _ = d.Set(StorageSchemaGenerateS3Endpoint, fmt.Sprintf("https://%s.cloud.gcore.lu", result.Location)) return resourceStorageS3Read(ctx, d, m) } @@ -136,26 +152,36 @@ func resourceStorageS3Read(ctx context.Context, d *schema.ResourceData, m interf resourceId := storageResourceID(d) log.Printf("[DEBUG] Start S3 Storage Resource reading (id=%s)\n", resourceId) defer log.Println("[DEBUG] Finish S3 Storage Resource reading") - if resourceId == "" { - return diag.Errorf("get storage: empty storage id") - } config := m.(*Config) client := config.StorageClient opts := []func(opt *storage.StorageListHTTPV2Params){ func(opt *storage.StorageListHTTPV2Params) { opt.Context = ctx }, - func(opt *storage.StorageListHTTPV2Params) { opt.ID = &resourceId }, + func(opt *storage.StorageListHTTPV2Params) { opt.ShowDeleted = new(bool) }, + } + if resourceId != "" { + opts = append(opts, func(opt *storage.StorageListHTTPV2Params) { opt.ID = &resourceId }) + } + name := d.Get(StorageSchemaName).(string) + if name != "" { + opts = append(opts, func(opt *storage.StorageListHTTPV2Params) { opt.Name = &name }) + } + if resourceId == "" && name == "" { + return diag.Errorf("get storage: empty storage id/name") } + result, err := client.StoragesList(opts...) if err != nil { return diag.FromErr(fmt.Errorf("storages list: %w", err)) } - if len(result) != 1 { + + if (len(result) == 0) || (name == "" && len(result) != 1) { return diag.Errorf("get storage: wrong length of search result (%d), want 1", len(result)) } st := result[0] + d.SetId(fmt.Sprint(st.ID)) nameParts := strings.Split(st.Name, "-") if len(nameParts) > 1 { clientID, _ := strconv.ParseInt(nameParts[0], 10, 64) @@ -202,7 +228,10 @@ func resourceStorageS3Delete(ctx context.Context, d *schema.ResourceData, m inte func storageResourceID(d *schema.ResourceData) string { resourceID := d.Id() if resourceID == "" { - resourceID = fmt.Sprint(d.Get(StorageSchemaId).(int)) + id := d.Get(StorageSchemaId).(int) + if id > 0 { + resourceID = fmt.Sprint(id) + } } return resourceID } diff --git a/gcore/resource_gcore_storage_sftp.go b/gcore/resource_gcore_storage_sftp.go index 089505c..52db0f0 100644 --- a/gcore/resource_gcore_storage_sftp.go +++ b/gcore/resource_gcore_storage_sftp.go @@ -3,6 +3,8 @@ package gcore import ( "context" "fmt" + gstorage "github.com/G-Core/gcorelabs-storage-sdk-go" + "github.com/G-Core/gcorelabs-storage-sdk-go/swagger/client/key" "log" "regexp" "strconv" @@ -16,10 +18,13 @@ import ( const ( StorageSFTPSchemaGenerateSftpPassword = "generated_password" + StorageSchemaGenerateSFTPEndpoint = "generated_sftp_endpoint" StorageSFTPSchemaSftpPassword = "password" StorageSFTPSchemaKeyId = "ssh_key_id" StorageSFTPSchemaExpires = "http_expires_header_value" StorageSFTPSchemaServerAlias = "http_servername_alias" + + StorageSFTPSchemaUpdateAfterCreate = "update_after_create" ) func resourceStorageSFTP() *schema.Resource { @@ -31,6 +36,12 @@ func resourceStorageSFTP() *schema.Resource { Computed: true, Description: "An id of new storage resource.", }, + StorageSFTPSchemaUpdateAfterCreate: { + Type: schema.TypeBool, + Optional: true, + Computed: true, + Description: "A temporary flag. An internal cheat, to skip update ssh keys. Skip it.", + }, StorageSchemaClientId: { Type: schema.TypeInt, Optional: true, @@ -56,8 +67,17 @@ func resourceStorageSFTP() *schema.Resource { Description: "An alias of storage resource.", }, StorageSFTPSchemaExpires: { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: func(i interface{}, path cty.Path) diag.Diagnostics { + v := i.(string) + if !regexp.MustCompile(`^(\d+\s(years))?\s?(\d+\s(months))?\s?(\d+\s(weeks))?\s?(\d+\s(days))?\s?(\d+\s(hours))?\s?(\d+\s(minutes))?\s?(\d+\s(seconds))?$`).MatchString(v) || len(v) > 255 { + return diag.Errorf("storage expires must be matched by " + + "^([0-9]+\\s(years|months|weeks|days|hours|minutes|seconds)[\\s]?)+$ regexp, " + + "it also should be less than 256 symbols") + } + return nil + }, Description: "A expires date of storage resource.", }, StorageSchemaLocation: { @@ -77,8 +97,15 @@ func resourceStorageSFTP() *schema.Resource { Description: "A location of new storage resource. One of (ams, sin, fra, mia)", }, StorageSFTPSchemaSftpPassword: { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: func(i interface{}, path cty.Path) diag.Diagnostics { + v := i.(string) + if len(v) > 63 || len(v) < 8 { + return diag.Errorf("storage password should be more than 8 and less than 64 symbols") + } + return nil + }, Description: "A sftp password for new storage resource.", }, StorageSFTPSchemaGenerateSftpPassword: { @@ -94,11 +121,17 @@ func resourceStorageSFTP() *schema.Resource { Optional: true, Description: "An ssh keys IDs to link with new sftp storage resource only. https://storage.gcorelabs.com/ssh-key/list", }, - StorageSchemaGenerateEndpoint: { + StorageSchemaGenerateHTTPEndpoint: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "A http sftp entry point for new storage resource.", + }, + StorageSchemaGenerateSFTPEndpoint: { Type: schema.TypeString, Optional: true, Computed: true, - Description: "A sftp entry point for new storage resource.", + Description: "A ssh sftp entry point for new storage resource.", }, }, CreateContext: resourceStorageSFTPCreate, @@ -109,13 +142,112 @@ func resourceStorageSFTP() *schema.Resource { } } -func resourceStorageSFTPCreate(ctx context.Context, d *schema.ResourceData, m interface{}) (dErr diag.Diagnostics) { +func resourceStorageValidateKeys(ctx context.Context, sdk *gstorage.SDK, d *schema.ResourceData) error { + keyIds := d.Get(StorageSFTPSchemaKeyId).([]interface{}) + if len(keyIds) == 0 { + return nil + } + for _, v := range keyIds { + id, ok := v.(int) + keyID := fmt.Sprint(id) + if !ok { + return fmt.Errorf("key %v is not int", v) + } + opts := []func(opt *key.KeyListHTTPV2Params){ + func(opt *key.KeyListHTTPV2Params) { opt.Context = ctx }, + func(opt *key.KeyListHTTPV2Params) { opt.ID = &keyID }, + } + result, err := sdk.KeysList(opts...) + if err != nil { + return fmt.Errorf("problems with key %v: %w", v, err) + } + if len(result) == 0 { + return fmt.Errorf("key %v is not found", v) + } + } + return nil +} + +func resourceStorageLinkKeys(ctx context.Context, sdk *gstorage.SDK, d *schema.ResourceData, storageID int64) error { + keyIds := d.Get(StorageSFTPSchemaKeyId).([]interface{}) + if len(keyIds) == 0 { + return nil + } + for _, v := range keyIds { + keyId, ok := v.(int) + if !ok { + log.Printf("[ERROR] ssh key id should be int: %+v is %T\n", v, v) + continue + } + keyOpts := []func(opt *storage.KeyLinkHTTPParams){ + func(opt *storage.KeyLinkHTTPParams) { opt.Context = ctx }, + func(opt *storage.KeyLinkHTTPParams) { opt.ID = storageID; opt.KeyID = int64(keyId) }, + } + err := sdk.LinkKeyToStorage(keyOpts...) + if err != nil { + return fmt.Errorf("link key #%d to storage: %w", keyId, err) + } + } + return nil +} + +func resourceStorageRelinkKeys(ctx context.Context, sdk *gstorage.SDK, d *schema.ResourceData, storageID int64) error { + if !d.HasChange(StorageSFTPSchemaKeyId) { + return nil + } + oldKeys, newKeys := d.GetChange(StorageSFTPSchemaKeyId) + oldIDs, newIDs := oldKeys.([]interface{}), newKeys.([]interface{}) + decision := map[interface{}]int{} + for _, v := range oldIDs { + decision[v]-- + } + for _, v := range newIDs { + decision[v]++ + } + unlink, link := make([]int, 0), make([]int, 0) + for id, v := range decision { + if v > 0 { + link = append(link, id.(int)) + } + if v < 0 { + unlink = append(unlink, id.(int)) + } + } + for _, keyId := range link { + keyOpts := []func(opt *storage.KeyLinkHTTPParams){ + func(opt *storage.KeyLinkHTTPParams) { opt.Context = ctx }, + func(opt *storage.KeyLinkHTTPParams) { opt.ID = storageID; opt.KeyID = int64(keyId) }, + } + err := sdk.LinkKeyToStorage(keyOpts...) + if err != nil { + return fmt.Errorf("link key #%d to storage: %w", keyId, err) + } + } + for _, keyId := range unlink { + keyOpts := []func(opt *storage.KeyUnlinkHTTPParams){ + func(opt *storage.KeyUnlinkHTTPParams) { opt.Context = ctx }, + func(opt *storage.KeyUnlinkHTTPParams) { opt.ID = storageID; opt.KeyID = int64(keyId) }, + } + err := sdk.UnlinkKeyFromStorage(keyOpts...) + if err != nil { + return fmt.Errorf("unlink key #%d to storage: %w", keyId, err) + } + } + return nil +} + +func resourceStorageSFTPCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { id := new(int) log.Println("[DEBUG] Start SFTP Storage Resource creating") defer log.Printf("[DEBUG] Finish SFTP Storage Resource creating (id=%d)\n", *id) config := m.(*Config) client := config.StorageClient + err := resourceStorageValidateKeys(ctx, client, d) + if err != nil { + return diag.FromErr(err) + } + opts := []func(opt *storage.StorageCreateHTTPParams){ func(opt *storage.StorageCreateHTTPParams) { opt.Context = ctx }, func(opt *storage.StorageCreateHTTPParams) { opt.Body.Type = "sftp" }, @@ -141,62 +273,63 @@ func resourceStorageSFTPCreate(ctx context.Context, d *schema.ResourceData, m in return diag.FromErr(fmt.Errorf("create storage: %v", err)) } d.SetId(fmt.Sprintf("%d", result.ID)) - defer func() { - dErr = resourceStorageSFTPRead(ctx, d, m) - }() *id = int(result.ID) if result.Credentials.SftpPassword != "" { _ = d.Set(StorageSFTPSchemaSftpPassword, result.Credentials.SftpPassword) } - _ = d.Set(StorageSchemaGenerateEndpoint, fmt.Sprintf("%s.%s.origin.gcdn.co", result.Name, result.Location)) + _ = d.Set(StorageSchemaGenerateHTTPEndpoint, + fmt.Sprintf("http://%s.%s.origin.gcdn.co", result.Name, result.Location)) + _ = d.Set(StorageSchemaGenerateSFTPEndpoint, + fmt.Sprintf("ssh://%s@%s.origin.gcdn.co:2200", result.Name, result.Location)) - keyIds := d.Get(StorageSFTPSchemaKeyId).([]interface{}) - if len(keyIds) == 0 { - return dErr + err = resourceStorageLinkKeys(ctx, client, d, result.ID) + if err != nil { + return diag.FromErr(err) } - for _, v := range keyIds { - keyId, ok := v.(int) - if !ok { - log.Printf("[ERROR] ssh key id should be int: %+v is %T\n", v, v) - continue - } - keyOpts := []func(opt *storage.KeyLinkHTTPParams){ - func(opt *storage.KeyLinkHTTPParams) { opt.Context = ctx }, - func(opt *storage.KeyLinkHTTPParams) { opt.ID = result.ID; opt.KeyID = int64(keyId) }, - } - err = client.LinkKeyToStorage(keyOpts...) - if err != nil { - return diag.FromErr(fmt.Errorf("link key #%d to storage: %w", keyId, err)) - } + + if strings.TrimSpace(d.Get(StorageSFTPSchemaExpires).(string)) != "" || + strings.TrimSpace(d.Get(StorageSFTPSchemaServerAlias).(string)) != "" { + _ = d.Set(StorageSFTPSchemaUpdateAfterCreate, true) + return resourceStorageSFTPUpdate(ctx, d, m) } - return dErr + return resourceStorageSFTPRead(ctx, d, m) } func resourceStorageSFTPRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { resourceId := storageResourceID(d) log.Printf("[DEBUG] Start SFTP Storage Resource reading (id=%s)\n", resourceId) defer log.Println("[DEBUG] Finish SFTP Storage Resource reading") - if resourceId == "" { - return diag.Errorf("get storage: empty storage id") - } config := m.(*Config) client := config.StorageClient opts := []func(opt *storage.StorageListHTTPV2Params){ func(opt *storage.StorageListHTTPV2Params) { opt.Context = ctx }, - func(opt *storage.StorageListHTTPV2Params) { opt.ID = &resourceId }, + func(opt *storage.StorageListHTTPV2Params) { opt.ShowDeleted = new(bool) }, + } + if resourceId != "" { + opts = append(opts, func(opt *storage.StorageListHTTPV2Params) { opt.ID = &resourceId }) + } + name := d.Get(StorageSchemaName).(string) + if name != "" { + opts = append(opts, func(opt *storage.StorageListHTTPV2Params) { opt.Name = &name }) } + if resourceId == "" && name == "" { + return diag.Errorf("get storage: empty storage id/name") + } + result, err := client.StoragesList(opts...) if err != nil { return diag.FromErr(fmt.Errorf("storages list: %w", err)) } - if len(result) != 1 { + + if (len(result) == 0) || (name == "" && len(result) != 1) { return diag.Errorf("get storage: wrong length of search result (%d), want 1", len(result)) } st := result[0] + d.SetId(fmt.Sprint(st.ID)) nameParts := strings.Split(st.Name, "-") if len(nameParts) > 1 { clientID, _ := strconv.ParseInt(nameParts[0], 10, 64) @@ -205,6 +338,16 @@ func resourceStorageSFTPRead(ctx context.Context, d *schema.ResourceData, m inte } else { _ = d.Set(StorageSchemaName, st.Name) } + if len(st.Credentials.Keys) > 0 { + keys := make([]int, 0, len(st.Credentials.Keys)) + for _, k := range st.Credentials.Keys { + if k == nil { + continue + } + keys = append(keys, int(k.ID)) + } + _ = d.Set(StorageKeySchemaId, keys) + } _ = d.Set(StorageSFTPSchemaServerAlias, st.ServerAlias) _ = d.Set(StorageSFTPSchemaExpires, st.Expires) _ = d.Set(StorageSchemaId, st.ID) @@ -244,6 +387,33 @@ func resourceStorageSFTPUpdate(ctx context.Context, d *schema.ResourceData, m in if err != nil { return diag.FromErr(fmt.Errorf("update storage: %w", err)) } + if d.Get(StorageSFTPSchemaUpdateAfterCreate).(bool) { + _ = d.Set(StorageSFTPSchemaUpdateAfterCreate, false) + return nil + } + if d.HasChange(StorageSFTPSchemaSftpPassword) { + pass := d.Get(StorageSFTPSchemaSftpPassword).(string) + deletePass := false + if pass == "" { + deletePass = true + } + passOpts := []func(*storage.StorageUpdateCredentialsHTTPParams){ + func(params *storage.StorageUpdateCredentialsHTTPParams) { + params.ID = id + params.Context = ctx + params.Body.SftpPassword = pass + params.Body.DeleteSftpPassword = deletePass + }, + } + _, err = client.UpdateStorageCredentials(passOpts...) + if err != nil { + return diag.FromErr(fmt.Errorf("update creds: %w", err)) + } + } + err = resourceStorageRelinkKeys(ctx, client, d, id) + if err != nil { + return diag.FromErr(fmt.Errorf("update keys: %w", err)) + } return resourceStorageSFTPRead(ctx, d, m) } diff --git a/gcore/resource_gcore_storage_sftp_key.go b/gcore/resource_gcore_storage_sftp_key.go index aff0d02..219521a 100644 --- a/gcore/resource_gcore_storage_sftp_key.go +++ b/gcore/resource_gcore_storage_sftp_key.go @@ -3,7 +3,9 @@ package gcore import ( "context" "fmt" + "github.com/hashicorp/go-cty/cty" "log" + "regexp" "strconv" "strings" @@ -22,9 +24,16 @@ func resourceStorageSFTPKey() *schema.Resource { return &schema.Resource{ Schema: map[string]*schema.Schema{ StorageKeySchemaName: { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateDiagFunc: func(i interface{}, path cty.Path) diag.Diagnostics { + name := i.(string) + if !regexp.MustCompile(`^[\w\-]+$`).MatchString(name) || len(name) > 127 { + return diag.Errorf("key name can't be empty and can have only letters, numbers, dashes and underscores, it also should be less than 128 symbols") + } + return nil + }, Description: "A name of new storage key resource.", }, StorageKeySchemaKey: { @@ -79,21 +88,23 @@ func resourceStorageSFTPKeyRead(ctx context.Context, d *schema.ResourceData, m i resourceId := storageKeyResourceID(d) log.Printf("[DEBUG] Start Storage Key Resource reading (id=%s)\n", resourceId) defer log.Println("[DEBUG] Finish Storage Key Resource reading") - if resourceId == "" { - return diag.Errorf("get storage: empty storage id") - } config := m.(*Config) client := config.StorageClient opts := []func(opt *key.KeyListHTTPV2Params){ func(opt *key.KeyListHTTPV2Params) { opt.Context = ctx }, - func(opt *key.KeyListHTTPV2Params) { opt.ID = &resourceId }, + } + if resourceId != "" { + opts = append(opts, func(opt *key.KeyListHTTPV2Params) { opt.ID = &resourceId }) } name := strings.TrimSpace(d.Get(StorageKeySchemaName).(string)) if name != "" { opts = append(opts, func(opt *key.KeyListHTTPV2Params) { opt.Name = &name }) } + if resourceId == "" && name == "" { + return diag.Errorf("get storage: empty storage id/name") + } result, err := client.KeysList(opts...) if err != nil { return diag.FromErr(err) @@ -103,6 +114,7 @@ func resourceStorageSFTPKeyRead(ctx context.Context, d *schema.ResourceData, m i } st := result[0] + d.SetId(fmt.Sprint(st.ID)) _ = d.Set(StorageKeySchemaId, st.ID) _ = d.Set(StorageKeySchemaName, st.Name) @@ -141,7 +153,10 @@ func resourceStorageSFTPKeyDelete(ctx context.Context, d *schema.ResourceData, m func storageKeyResourceID(d *schema.ResourceData) string { resourceID := d.Id() if resourceID == "" { - resourceID = fmt.Sprint(d.Get(StorageKeySchemaId).(int)) + id := d.Get(StorageKeySchemaId).(int) + if id > 0 { + resourceID = fmt.Sprint(id) + } } return resourceID } diff --git a/go.mod b/go.mod index 2a5db9e..bd4de4a 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/terraform-providers/terraform-provider-gcorelabs go 1.14 require ( - github.com/G-Core/gcorelabs-storage-sdk-go v0.0.8 + github.com/G-Core/gcorelabs-storage-sdk-go v0.0.9 github.com/G-Core/gcorelabscdn-go v0.0.0-20210503173228-b4ac8b2402ff github.com/G-Core/gcorelabscloud-go v0.4.6 github.com/google/uuid v1.1.2 // indirect diff --git a/go.sum b/go.sum index 7155d89..f580f76 100644 --- a/go.sum +++ b/go.sum @@ -41,8 +41,8 @@ github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6L github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/G-Core/gcorelabs-storage-sdk-go v0.0.8 h1:+HF1Jv8vR8LSJ0VYiJBeYXj1Qu4d85BoizLLMReq9zk= -github.com/G-Core/gcorelabs-storage-sdk-go v0.0.8/go.mod h1:BZef79y4G28n8ic3x6iQWbW+mtpHPSUyJRfIRSkeAJw= +github.com/G-Core/gcorelabs-storage-sdk-go v0.0.9 h1:6uyKbknI8Q2pIJApPBf6JA0CN5O8bSDU5hBAyoqre8w= +github.com/G-Core/gcorelabs-storage-sdk-go v0.0.9/go.mod h1:BZef79y4G28n8ic3x6iQWbW+mtpHPSUyJRfIRSkeAJw= github.com/G-Core/gcorelabscdn-go v0.0.0-20210503173228-b4ac8b2402ff h1:kIH66Shwb0Y9kvBgykpzmQn2soiHDTCJ/Rr5cQQ1cOk= github.com/G-Core/gcorelabscdn-go v0.0.0-20210503173228-b4ac8b2402ff/go.mod h1:iSGXaTvZBzDHQW+rKFS918BgFVpONcyLEijwh8WsXpE= github.com/G-Core/gcorelabscloud-go v0.4.6 h1:+pNeTKWuhR52Qavnzt+r6rCDJWumymkJTjKQV4+Tl5Y=