├── .semgrepignore ├── version └── version.go ├── .trivyignore.yml ├── .gitignore ├── .github ├── CODE_OF_CONDUCT.md ├── SUPPORT.md ├── .github │ └── PULL_REQUEST_TEMPLATE.md ├── workflows │ ├── acceptance-tests.yml │ ├── verify.yml │ ├── release.yml │ └── secure.yml └── ISSUE_TEMPLATE.md ├── scripts ├── golangci_lint_check.sh └── changelog-links.sh ├── selectel ├── schema_selectel_dbaas_mysql_database_v1.go ├── service_types.go ├── schema_selectel_dbaas_kafka_datastore_v1.go ├── internal │ ├── hashcode │ │ ├── hashcode.go │ │ └── hashcode_test.go │ ├── httptest │ │ └── client.go │ ├── mutexkv │ │ ├── mutexkv_test.go │ │ └── mutexkv.go │ └── reflect │ │ ├── map.go │ │ └── map_test.go ├── schema_selectel_dbaas_prometheus_metric_token_v1.go ├── regions_test.go ├── messages.go ├── schemas │ └── dbaas │ │ └── schema_selectel_dbaas_firewall_v1.go ├── schema_selectel_dbaas_postgresql_database_v1.go ├── kube_options.go ├── import_selectel_vpc_subnet_v2_test.go ├── schema_selectel_dbaas_kafka_topic_v1.go ├── import_selectel_vpc_license_v2_test.go ├── schema_selectel_dbaas_user_v1.go ├── import_selectel_vpc_floatingip_v2_test.go ├── schema_selectel_dbaas_grant_v1.go ├── import_selectel_domains_domain_v1_test.go ├── schema_selectel_dbaas_postgresql_extension_v1.go ├── import_selectel_iam_user_v1_test.go ├── schema_selectel_dbaas_postgresql_logical_replication_slot_v1.go ├── import_selectel_vpc_project_v2_test.go ├── import_selectel_craas_registry_v1_test.go ├── import_selectel_dbaas_datastore_v1_test.go ├── import_selectel_iam_serviceuser_v1_test.go ├── import_selectel_dbaas_prometheus_metric_token_v1_test.go ├── import_selectel_dbaas_postgresql_datastore_v1_test.go ├── project_test.go ├── regions.go ├── import_selectel_dbaas_redis_datastore_v1_test.go ├── backups.go ├── import_selectel_dbaas_grant_v1_test.go ├── import_selectel_dbaas_user_v1_test.go ├── import_selectel_dbaas_database_v1_test.go ├── import_selectel_mks_nodegroup_v1_test.go ├── import_selectel_dbaas_extension_v1_test.go ├── dbaas_test.go ├── data_source_selectel_domains_domain_v1.go ├── craas_test.go ├── import_selectel_dbaas_postgresql_logical_replication_slot_v1_test.go ├── schema_selectel_dbaas_kafka_acl_v1.go ├── import_selectel_vpc_keypair_v2_test.go ├── schema_selectel_dbaas_mysql_datastore_v1.go ├── data_source_selectel_domains_zone_v2_test.go ├── import_selectel_domains_record_v1_test.go ├── waiters │ ├── dedicated │ │ ├── boot.go │ │ └── server.go │ ├── dbaas │ │ ├── acl.go │ │ ├── grant.go │ │ ├── user.go │ │ ├── topic.go │ │ ├── extension.go │ │ ├── database.go │ │ ├── datastore.go │ │ └── logical_replication_slot.go │ └── cloudbackup │ │ └── plan.go ├── data_source_selectel_cloudbackup_plan_v2_test.go ├── messages_test.go ├── data_source_selectel_cloudbackup_checkpoint_v2_test.go ├── networking.go ├── domains_test.go ├── import_selectel_domains_zone_v2_test.go ├── data_source_selectel_domains_domain_v1_test.go ├── data_source_selectel_domains_zone_v2.go ├── dbaas_redis_utils.go ├── import_selectel_dbaas_mysql_datastore_v1_test.go ├── data_source_selectel_mks_kube_versions_v1.go ├── schema_selectel_dbaas_postgresql_datastore_v1.go ├── data_source_selectel_mks_kube_versions_v1_test.go ├── import_selectel_mks_cluster_v1_test.go ├── schema_selectel_dbaas_redis_datastore_v1.go ├── schema_selectel_dbaas_datastore_v1.go ├── data_source_selectel_domains_rrset_v2.go ├── data_source_selectel_domains_rrset_v2_test.go ├── data_source_selectel_mks_kubeconfig_v1.go ├── domains.go ├── data_source_selectel_dbaas_prometheus_metric_token_v1_test.go ├── data_source_selectel_dedicated_location_v1_test.go ├── config.go ├── import_selectel_secretsmanager_secret_v1_test.go ├── secretsmanager.go ├── data_source_selectel_dedicated_os_v1_test.go ├── dbaas_postgresql_utils.go ├── data_source_selectel_dbaas_available_extension_v1_test.go ├── resource_selectel_craas_token_v1_test.go ├── resource_selectel_dbaas_firewall_v1_test.go ├── data_source_selectel_dedicated_configuration_v1_test.go ├── data_source_selectel_mks_kubeconfig_v1_test.go └── networking_test.go ├── main.go ├── examples └── project-with-floating-ips │ ├── README.md │ ├── outputs.tf │ └── main.tf ├── website └── docs │ ├── d │ ├── domains_domain_v1.html.markdown │ ├── dedicated_location_v1.html.markdown │ ├── mks_feature_gates_v1.html.markdown │ ├── mks_admission_controllers_v1.html.markdown │ ├── mks_kube_versions_v1.html.markdown │ ├── domains_zone_v2.html.markdown │ ├── domains_rrset_v2.html.markdown │ ├── dbaas_available_extension_v1.html.markdown │ ├── dedicated_public_subnet_v1.html.markdown │ ├── cloudbackup_plan_v2.html.markdown │ ├── dedicated_configuration_v1.html.markdown │ ├── dbaas_prometheus_metric_token_v1.html.markdown │ ├── cloudbackup_checkpoint_v2.html.markdown │ └── mks_kubeconfig_v1.html.markdown │ ├── r │ ├── iam_group_membership_v1.html.markdown │ ├── craas_token_v1.html.markdown │ ├── secretsmanager_secret_v1.html.markdown │ ├── dbaas_kafka_acl_v1.html.markdown │ └── domains_domain_v1.html.markdown │ └── guides │ └── upgrading_to_version_4.html.markdown ├── .golangci.yml ├── .goreleaser.yml └── GNUmakefile /.semgrepignore: -------------------------------------------------------------------------------- 1 | website/ 2 | *_test.go 3 | -------------------------------------------------------------------------------- /version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | var Version = "dev" 4 | 5 | const ProviderName = "terraform-provider-selectel" 6 | -------------------------------------------------------------------------------- /.trivyignore.yml: -------------------------------------------------------------------------------- 1 | secrets: 2 | - id: private-key 3 | statement: false-positive in description field 4 | paths: 5 | - selectel/resourse_selectel_secretsmanager_certificate_v1.go 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.tf 2 | *.tfstate 3 | *.tfstate.backup 4 | *.tfstate.lock.info 5 | *.terraform.lock.hcl 6 | *.log 7 | *.json 8 | *.yaml 9 | .terraform/ 10 | terraform-provider-selectel 11 | .idea 12 | .DS_Store 13 | dist/ 14 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | HashiCorp Community Guidelines apply to you when interacting with the community here on GitHub and contributing code. 4 | 5 | Please read the full text at https://www.hashicorp.com/community-guidelines 6 | -------------------------------------------------------------------------------- /.github/SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | Terraform is a mature project with a growing community. There are active, dedicated people willing to help you through various mediums. 4 | 5 | Take a look at those mediums listed at https://www.terraform.io/community.html 6 | -------------------------------------------------------------------------------- /scripts/golangci_lint_check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "==> Running golangci-lint..." 4 | golangci-lint run ./... 5 | if [[ $? -ne 0 ]]; then 6 | echo "" 7 | echo "Golangci-lint found suspicious constructs." 8 | exit 1 9 | fi 10 | 11 | exit 0 12 | -------------------------------------------------------------------------------- /selectel/schema_selectel_dbaas_mysql_database_v1.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 4 | 5 | func resourceDBaaSMySQLDatabaseV1Schema() map[string]*schema.Schema { 6 | return resourceDBaaSDatabaseV1BaseSchema() 7 | } 8 | -------------------------------------------------------------------------------- /selectel/service_types.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | const ( 4 | DBaaS = "managed-database" 5 | MKS = "managed-kubernetes" 6 | CRaaS = "container-registry" 7 | IAM = "iam" 8 | SecretsManager = "secrets-manager" 9 | CertificateManager = "certificate-manager" 10 | DNSv2 = "dnsv2" 11 | CRaaSV2 = "container-registry-v2" 12 | DataProtectV2 = "data-protectv2" 13 | ) 14 | -------------------------------------------------------------------------------- /selectel/schema_selectel_dbaas_kafka_datastore_v1.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 4 | 5 | func resourceDBaaSKafkaDatastoreV1Schema() map[string]*schema.Schema { 6 | datastoreSchema := resourceDBaaSDatastoreV1BaseSchema() 7 | datastoreSchema["logs"] = &schema.Schema{ 8 | Type: schema.TypeString, 9 | Optional: true, 10 | Description: "Name of Logs group.", 11 | } 12 | 13 | return datastoreSchema 14 | } 15 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | "github.com/hashicorp/terraform-plugin-sdk/v2/plugin" 6 | "github.com/terraform-providers/terraform-provider-selectel/selectel" 7 | "github.com/terraform-providers/terraform-provider-selectel/version" 8 | ) 9 | 10 | func main() { 11 | plugin.Serve(&plugin.ServeOpts{ 12 | ProviderFunc: func() *schema.Provider { 13 | return selectel.Provider(version.Version) 14 | }, 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /selectel/internal/hashcode/hashcode.go: -------------------------------------------------------------------------------- 1 | package hashcode 2 | 3 | import ( 4 | "hash/crc32" 5 | ) 6 | 7 | // String hashes a string to a unique hashcode. 8 | // 9 | // This implementation is copied from v1 Terraform SDK since it was removed 10 | // from v2 SDK. 11 | // 12 | // crc32 returns a uint32, but for our use we need 13 | // and non negative integer. Here we cast to an integer 14 | // and invert it if the result is negative. 15 | func String(s string) int { 16 | v := int(crc32.ChecksumIEEE([]byte(s))) 17 | if v >= 0 { 18 | return v 19 | } 20 | if -v >= 0 { 21 | return -v 22 | } 23 | // v == MinInt 24 | return 0 25 | } 26 | -------------------------------------------------------------------------------- /selectel/schema_selectel_dbaas_prometheus_metric_token_v1.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 4 | 5 | func resourceDBaaSPostgreSQLPrometheusMetricTokenV1Schema() map[string]*schema.Schema { 6 | return map[string]*schema.Schema{ 7 | "project_id": { 8 | Type: schema.TypeString, 9 | Required: true, 10 | }, 11 | "region": { 12 | Type: schema.TypeString, 13 | Required: true, 14 | }, 15 | "name": { 16 | Type: schema.TypeString, 17 | Required: true, 18 | }, 19 | "value": { 20 | Type: schema.TypeString, 21 | Computed: true, 22 | }, 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /selectel/regions_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | const ( 11 | testRu3Region = "ru-3" 12 | ) 13 | 14 | func TestExpandVPCV2Regions(t *testing.T) { 15 | r := resourceVPCKeypairV2() 16 | d := r.TestResourceData() 17 | d.SetId("1") 18 | regions := []interface{}{"ru-1", "ru-2", "ru-3"} 19 | d.Set("regions", regions) 20 | 21 | expected := []string{"ru-1", "ru-2", "ru-3"} 22 | 23 | actual := expandVPCV2Regions(d.Get("regions").(*schema.Set)) 24 | 25 | assert.ElementsMatch(t, expected, actual) 26 | } 27 | -------------------------------------------------------------------------------- /selectel/internal/hashcode/hashcode_test.go: -------------------------------------------------------------------------------- 1 | package hashcode 2 | 3 | import "testing" 4 | 5 | func TestString(t *testing.T) { 6 | v := "hello, world" 7 | expected := String(v) 8 | for i := 0; i < 100; i++ { 9 | actual := String(v) 10 | if actual != expected { 11 | t.Fatalf("bad: %#v\n\t%#v", actual, expected) 12 | } 13 | } 14 | } 15 | 16 | func TestString_positiveIndex(t *testing.T) { 17 | // "2338615298" hashes to uint32(2147483648) which is math.MinInt32 18 | ips := []string{"192.168.1.3", "192.168.1.5", "2338615298"} 19 | for _, ip := range ips { 20 | if index := String(ip); index < 0 { 21 | t.Fatalf("Bad Index %#v for ip %s", index, ip) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.github/.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 4 | ### Description 5 | 8 | 9 | 10 | ### Relations 11 | 20 | 21 | Closes #0000 22 | 23 | ### References 24 | 27 | -------------------------------------------------------------------------------- /selectel/messages.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import "fmt" 4 | 5 | func msgCreate(object string, options interface{}) string { 6 | return fmt.Sprintf("[DEBUG] Creating %s with options: %+v", object, options) 7 | } 8 | 9 | func msgGet(object, id string) string { 10 | return fmt.Sprintf("[DEBUG] Getting %s '%s'", object, id) 11 | } 12 | 13 | func msgUpdate(object, id string, options interface{}) string { 14 | return fmt.Sprintf("[DEBUG] Updating %s '%s' with options: %+v", object, id, options) 15 | } 16 | 17 | func msgDelete(object, id string) string { 18 | return fmt.Sprintf("[DEBUG] Deleting %s '%s'", object, id) 19 | } 20 | 21 | func msgImport(object, id string) string { 22 | return fmt.Sprintf("[DEBUG] Importing %s '%s'", object, id) 23 | } 24 | -------------------------------------------------------------------------------- /selectel/schemas/dbaas/schema_selectel_dbaas_firewall_v1.go: -------------------------------------------------------------------------------- 1 | package schemas 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 4 | 5 | func ResourceDBaaSFirewallV1Schema() map[string]*schema.Schema { 6 | return map[string]*schema.Schema{ 7 | "project_id": { 8 | Type: schema.TypeString, 9 | Required: true, 10 | ForceNew: true, 11 | }, 12 | "region": { 13 | Type: schema.TypeString, 14 | Required: true, 15 | ForceNew: true, 16 | }, 17 | "datastore_id": { 18 | Type: schema.TypeString, 19 | Required: true, 20 | ForceNew: true, 21 | }, 22 | "ips": { 23 | Type: schema.TypeList, 24 | Required: true, 25 | Elem: &schema.Schema{ 26 | Type: schema.TypeString, 27 | }, 28 | }, 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /selectel/schema_selectel_dbaas_postgresql_database_v1.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | ) 6 | 7 | func resourceDBaaSPostgreSQLDatabaseV1Schema() map[string]*schema.Schema { 8 | databaseSchema := resourceDBaaSDatabaseV1BaseSchema() 9 | databaseSchema["owner_id"] = &schema.Schema{ 10 | Type: schema.TypeString, 11 | Optional: true, 12 | } 13 | databaseSchema["lc_collate"] = &schema.Schema{ 14 | Type: schema.TypeString, 15 | Optional: true, 16 | ForceNew: true, 17 | Default: "C", 18 | } 19 | databaseSchema["lc_ctype"] = &schema.Schema{ 20 | Type: schema.TypeString, 21 | Optional: true, 22 | ForceNew: true, 23 | Default: "C", 24 | } 25 | 26 | return databaseSchema 27 | } 28 | -------------------------------------------------------------------------------- /selectel/kube_options.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 7 | ) 8 | 9 | const ( 10 | featureGatesKey = "feature_gates" 11 | admissionControllersKey = "admission_controllers" 12 | ) 13 | 14 | func getSetAsStrings(d *schema.ResourceData, key string) ([]string, error) { 15 | val, ok := d.GetOk(key) 16 | if !ok { 17 | return []string{}, nil 18 | } 19 | 20 | set, ok := val.(*schema.Set) 21 | if !ok { 22 | return nil, fmt.Errorf("%q is not 'Set' at schema", key) 23 | } 24 | 25 | list := set.List() 26 | result := make([]string, len(list)) 27 | for i, item := range list { 28 | val, ok := item.(string) 29 | if !ok { 30 | return nil, fmt.Errorf("%q item '%v' is not a string", key, item) 31 | } 32 | result[i] = val 33 | } 34 | 35 | return result, nil 36 | } 37 | -------------------------------------------------------------------------------- /.github/workflows/acceptance-tests.yml: -------------------------------------------------------------------------------- 1 | name: Acceptance Tests 2 | on: 3 | push: 4 | branches: 5 | - master 6 | schedule: 7 | - cron: "0 0 * * *" 8 | 9 | jobs: 10 | acceptance-test: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | fail-fast: false 14 | 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v3 18 | 19 | - name: Set up Go 20 | uses: actions/setup-go@v5 21 | with: 22 | go-version: "1.23" 23 | 24 | - name: Set up Terraform 25 | uses: hashicorp/setup-terraform@v2 26 | with: 27 | terraform_wrapper: false 28 | 29 | - name: Run test 30 | run: make testacc 31 | env: 32 | OS_DOMAIN_NAME: ${{ secrets.OS_DOMAIN_NAME }} 33 | OS_USERNAME: ${{ secrets.OS_USERNAME }} 34 | OS_PASSWORD: ${{ secrets.OS_PASSWORD }} 35 | -------------------------------------------------------------------------------- /selectel/import_selectel_vpc_subnet_v2_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 8 | ) 9 | 10 | func TestAccVPCV2SubnetImportBasic(t *testing.T) { 11 | resourceName := "selectel_vpc_subnet_v2.subnet_tf_acc_test_1" 12 | projectName := acctest.RandomWithPrefix("tf-acc") 13 | 14 | resource.Test(t, resource.TestCase{ 15 | PreCheck: func() { testAccSelectelPreCheck(t) }, 16 | ProviderFactories: testAccProviders, 17 | CheckDestroy: testAccCheckVPCV2SubnetDestroy, 18 | Steps: []resource.TestStep{ 19 | { 20 | Config: testAccVPCV2SubnetBasic(projectName), 21 | }, 22 | { 23 | ResourceName: resourceName, 24 | ImportState: true, 25 | ImportStateVerify: true, 26 | }, 27 | }, 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /selectel/schema_selectel_dbaas_kafka_topic_v1.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 4 | 5 | func resourceDBaaSKafkaTopicV1Schema() map[string]*schema.Schema { 6 | return map[string]*schema.Schema{ 7 | "datastore_id": { 8 | Type: schema.TypeString, 9 | Required: true, 10 | ForceNew: true, 11 | }, 12 | "region": { 13 | Type: schema.TypeString, 14 | Required: true, 15 | ForceNew: true, 16 | }, 17 | "name": { 18 | Type: schema.TypeString, 19 | Required: true, 20 | ForceNew: true, 21 | }, 22 | "partitions": { 23 | Type: schema.TypeInt, 24 | Required: true, 25 | }, 26 | "status": { 27 | Type: schema.TypeString, 28 | Computed: true, 29 | }, 30 | "project_id": { 31 | Type: schema.TypeString, 32 | Required: true, 33 | ForceNew: true, 34 | }, 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /selectel/import_selectel_vpc_license_v2_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 8 | ) 9 | 10 | func TestAccVPCV2LicenseImportBasic(t *testing.T) { 11 | resourceName := "selectel_vpc_license_v2.license_tf_acc_test_1" 12 | projectName := acctest.RandomWithPrefix("tf-acc") 13 | 14 | resource.Test(t, resource.TestCase{ 15 | PreCheck: func() { testAccSelectelPreCheck(t) }, 16 | ProviderFactories: testAccProviders, 17 | CheckDestroy: testAccCheckVPCV2LicenseDestroy, 18 | Steps: []resource.TestStep{ 19 | { 20 | Config: testAccVPCV2LicenseBasic(projectName), 21 | }, 22 | { 23 | ResourceName: resourceName, 24 | ImportState: true, 25 | ImportStateVerify: true, 26 | }, 27 | }, 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /selectel/schema_selectel_dbaas_user_v1.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 4 | 5 | func resourceDBaaSUserV1Schema() map[string]*schema.Schema { 6 | return map[string]*schema.Schema{ 7 | "datastore_id": { 8 | Type: schema.TypeString, 9 | Required: true, 10 | ForceNew: true, 11 | }, 12 | "region": { 13 | Type: schema.TypeString, 14 | Required: true, 15 | ForceNew: true, 16 | }, 17 | "name": { 18 | Type: schema.TypeString, 19 | Required: true, 20 | ForceNew: true, 21 | }, 22 | "password": { 23 | Type: schema.TypeString, 24 | Required: true, 25 | Sensitive: true, 26 | }, 27 | "status": { 28 | Type: schema.TypeString, 29 | Computed: true, 30 | }, 31 | "project_id": { 32 | Type: schema.TypeString, 33 | Required: true, 34 | ForceNew: true, 35 | }, 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /selectel/import_selectel_vpc_floatingip_v2_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 8 | ) 9 | 10 | func TestAccVPCV2FloatingIPImportBasic(t *testing.T) { 11 | resourceName := "selectel_vpc_floatingip_v2.floatingip_tf_acc_test_1" 12 | projectName := acctest.RandomWithPrefix("tf-acc") 13 | 14 | resource.Test(t, resource.TestCase{ 15 | PreCheck: func() { testAccSelectelPreCheck(t) }, 16 | ProviderFactories: testAccProviders, 17 | CheckDestroy: testAccCheckVPCV2FloatingIPDestroy, 18 | Steps: []resource.TestStep{ 19 | { 20 | Config: testAccVPCV2FloatingIPBasic(projectName), 21 | }, 22 | { 23 | ResourceName: resourceName, 24 | ImportState: true, 25 | ImportStateVerify: true, 26 | }, 27 | }, 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /selectel/schema_selectel_dbaas_grant_v1.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 4 | 5 | func resourceDBaaSGrantV1Schema() map[string]*schema.Schema { 6 | return map[string]*schema.Schema{ 7 | "project_id": { 8 | Type: schema.TypeString, 9 | Required: true, 10 | ForceNew: true, 11 | }, 12 | "region": { 13 | Type: schema.TypeString, 14 | Required: true, 15 | ForceNew: true, 16 | }, 17 | "datastore_id": { 18 | Type: schema.TypeString, 19 | Required: true, 20 | ForceNew: true, 21 | }, 22 | "database_id": { 23 | Type: schema.TypeString, 24 | Required: true, 25 | ForceNew: true, 26 | }, 27 | "user_id": { 28 | Type: schema.TypeString, 29 | Required: true, 30 | ForceNew: true, 31 | }, 32 | "status": { 33 | Type: schema.TypeString, 34 | Computed: true, 35 | }, 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.github/workflows/verify.yml: -------------------------------------------------------------------------------- 1 | name: Verify 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | tests: 11 | runs-on: ubuntu-24.04 12 | steps: 13 | - uses: actions/checkout@v4 14 | - uses: actions/setup-go@v5 15 | with: 16 | go-version: "1.23" 17 | - run: make test 18 | 19 | golangci-lint: 20 | runs-on: ubuntu-24.04 21 | steps: 22 | - uses: actions/checkout@v4 23 | - uses: actions/setup-go@v5 24 | with: 25 | go-version: "1.23" 26 | - uses: golangci/golangci-lint-action@v7 27 | with: 28 | version: v2.1.6 29 | 30 | tidy: 31 | runs-on: ubuntu-24.04 32 | steps: 33 | - uses: actions/checkout@v4 34 | - uses: actions/setup-go@v5 35 | with: 36 | go-version: "1.23" 37 | - run: go mod tidy -v 38 | - run: git diff --exit-code 39 | -------------------------------------------------------------------------------- /selectel/internal/httptest/client.go: -------------------------------------------------------------------------------- 1 | package httptest 2 | 3 | import ( 4 | "io" 5 | "net/http" 6 | "strings" 7 | ) 8 | 9 | // RoundTripFunc lets us use a function as an http.RoundTripper. 10 | type RoundTripFunc func(req *http.Request) (*http.Response, error) 11 | 12 | func (f RoundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) { 13 | return f(req) 14 | } 15 | 16 | // NewFakeResponse creates a fake *http.Response with the provided status and body. 17 | func NewFakeResponse(status int, body string) *http.Response { 18 | return &http.Response{ 19 | StatusCode: status, 20 | Body: io.NopCloser(strings.NewReader(body)), 21 | } 22 | } 23 | 24 | // NewFakeTransport returns a fake transport with the given response and error. 25 | func NewFakeTransport(resp *http.Response, err error) RoundTripFunc { 26 | return RoundTripFunc(func(_ *http.Request) (*http.Response, error) { 27 | return resp, err 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /selectel/import_selectel_domains_domain_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 9 | ) 10 | 11 | func TestAccDomainsDomainV1ImportBasic(t *testing.T) { 12 | resourceName := "selectel_domains_domain_v1.domain_tf_acc_test_1" 13 | testDomainName := fmt.Sprintf("%s.xyz", acctest.RandomWithPrefix("tf-acc")) 14 | 15 | resource.Test(t, resource.TestCase{ 16 | PreCheck: func() { testAccSelectelPreCheck(t) }, 17 | ProviderFactories: testAccProviders, 18 | CheckDestroy: testAccCheckDomainsV1DomainDestroy, 19 | Steps: []resource.TestStep{ 20 | { 21 | Config: testAccDomainsDomainV1Basic(testDomainName), 22 | }, 23 | { 24 | ResourceName: resourceName, 25 | ImportState: true, 26 | ImportStateVerify: true, 27 | }, 28 | }, 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /selectel/schema_selectel_dbaas_postgresql_extension_v1.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 4 | 5 | func resourceDBaaSPostgreSQLExtensionV1Schema() map[string]*schema.Schema { 6 | return map[string]*schema.Schema{ 7 | "project_id": { 8 | Type: schema.TypeString, 9 | Required: true, 10 | ForceNew: true, 11 | }, 12 | "region": { 13 | Type: schema.TypeString, 14 | Required: true, 15 | ForceNew: true, 16 | }, 17 | "available_extension_id": { 18 | Type: schema.TypeString, 19 | Required: true, 20 | ForceNew: true, 21 | }, 22 | "datastore_id": { 23 | Type: schema.TypeString, 24 | Required: true, 25 | ForceNew: true, 26 | }, 27 | "database_id": { 28 | Type: schema.TypeString, 29 | Required: true, 30 | ForceNew: true, 31 | }, 32 | "status": { 33 | Type: schema.TypeString, 34 | Computed: true, 35 | }, 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /selectel/import_selectel_iam_user_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 8 | ) 9 | 10 | func TestAccIAMV1UserImportBasic(t *testing.T) { 11 | resourceName := "selectel_iam_user_v1.user_tf_acc_test_1" 12 | userEmail := acctest.RandomWithPrefix("tf-acc") + "@example.com" 13 | 14 | resource.Test(t, resource.TestCase{ 15 | PreCheck: func() { testAccSelectelPreCheck(t) }, 16 | ProviderFactories: testAccProviders, 17 | CheckDestroy: testAccCheckIAMV1UserDestroy, 18 | Steps: []resource.TestStep{ 19 | { 20 | Config: testAccIAMV1UserBasic(userEmail), 21 | }, 22 | { 23 | ResourceName: resourceName, 24 | ImportState: true, 25 | ImportStateVerify: true, 26 | ImportStateVerifyIgnore: []string{"email"}, 27 | }, 28 | }, 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /selectel/schema_selectel_dbaas_postgresql_logical_replication_slot_v1.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 4 | 5 | func resourceDBaaSPostgreSQLLogicalReplicationSlotV1Schema() map[string]*schema.Schema { 6 | return map[string]*schema.Schema{ 7 | "name": { 8 | Type: schema.TypeString, 9 | Required: true, 10 | ForceNew: true, 11 | }, 12 | "project_id": { 13 | Type: schema.TypeString, 14 | Required: true, 15 | ForceNew: true, 16 | }, 17 | "region": { 18 | Type: schema.TypeString, 19 | Required: true, 20 | ForceNew: true, 21 | }, 22 | "datastore_id": { 23 | Type: schema.TypeString, 24 | Required: true, 25 | ForceNew: true, 26 | }, 27 | "database_id": { 28 | Type: schema.TypeString, 29 | Required: true, 30 | ForceNew: true, 31 | }, 32 | "status": { 33 | Type: schema.TypeString, 34 | Computed: true, 35 | }, 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /selectel/import_selectel_vpc_project_v2_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 8 | ) 9 | 10 | func TestAccVPCV2ProjectImportBasic(t *testing.T) { 11 | resourceName := "selectel_vpc_project_v2.project_tf_acc_test_1" 12 | projectName := acctest.RandomWithPrefix("tf-acc") 13 | 14 | resource.Test(t, resource.TestCase{ 15 | PreCheck: func() { testAccSelectelPreCheck(t) }, 16 | ProviderFactories: testAccProviders, 17 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 18 | Steps: []resource.TestStep{ 19 | { 20 | Config: testAccVPCV2ProjectBasic(projectName), 21 | }, 22 | { 23 | ResourceName: resourceName, 24 | ImportState: true, 25 | ImportStateVerify: true, 26 | ImportStateVerifyIgnore: []string{"all_quotas"}, 27 | }, 28 | }, 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /examples/project-with-floating-ips/README.md: -------------------------------------------------------------------------------- 1 | # Basic Selectel VPC project with quotas and floating IPs in different regions 2 | 3 | This example provides a simple project with quotas in different regions. 4 | 5 | After you run `terraform apply` on this configuration, it will create a single 6 | project and output allocated floating ips in selected regions. 7 | 8 | Created project and floating IPs then can be used to create OpenStack instances. 9 | You can use [terraform-provider-openstack](https://github.com/terraform-providers/terraform-provider-openstack) 10 | to manage OpenStack instances inside the created project. 11 | 12 | To run this example you need to set `OS_DOMAIN_NAME` (your account id), `OS_USERNAME`, `OS_PASSWORD` variables with 13 | authentication info that you can get from the [service users](https://my.selectel.ru/profile/users_management/users?type=service) page. 14 | 15 | You can find additional examples in the [selectel/terraform-examples](https://github.com/selectel/terraform-examples). 16 | -------------------------------------------------------------------------------- /examples/project-with-floating-ips/outputs.tf: -------------------------------------------------------------------------------- 1 | output "project_id" { 2 | value = "${selectel_vpc_project_v2.webservice.id}" 3 | } 4 | 5 | output "webservice_floating_ip_ru1_1_id" { 6 | value = "${selectel_vpc_floatingip_v2.webservice_floating_ip_ru1_1.id}" 7 | } 8 | 9 | output "webservice_floating_ip_ru1_1_address" { 10 | value = "${selectel_vpc_floatingip_v2.webservice_floating_ip_ru1_1.floating_ip_address}" 11 | } 12 | 13 | output "webservice_floating_ip_ru1_2_id" { 14 | value = "${selectel_vpc_floatingip_v2.webservice_floating_ip_ru1_2.id}" 15 | } 16 | 17 | output "webservice_floating_ip_ru1_2_address" { 18 | value = "${selectel_vpc_floatingip_v2.webservice_floating_ip_ru1_2.floating_ip_address}" 19 | } 20 | 21 | output "webservice_floating_ip_ru2_1_id" { 22 | value = "${selectel_vpc_floatingip_v2.webservice_floating_ip_ru2_1.id}" 23 | } 24 | 25 | output "webservice_floating_ip_ru2_1_address" { 26 | value = "${selectel_vpc_floatingip_v2.webservice_floating_ip_ru2_1.floating_ip_address}" 27 | } 28 | -------------------------------------------------------------------------------- /selectel/import_selectel_craas_registry_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 8 | ) 9 | 10 | func TestAccCRaaSRegistryV1ImportBasic(t *testing.T) { 11 | resourceName := "selectel_craas_registry_v1.registry_tf_acc_test_1" 12 | projectName := acctest.RandomWithPrefix("tf-acc") 13 | registryName := acctest.RandomWithPrefix("tf-acc-reg") 14 | 15 | resource.Test(t, resource.TestCase{ 16 | PreCheck: func() { testAccSelectelPreCheck(t) }, 17 | ProviderFactories: testAccProviders, 18 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 19 | Steps: []resource.TestStep{ 20 | { 21 | Config: testAccCRaaSRegistryV1Basic(projectName, registryName), 22 | Check: testAccCheckSelectelCRaaSImportEnv(resourceName), 23 | }, 24 | { 25 | ResourceName: resourceName, 26 | ImportState: true, 27 | ImportStateVerify: true, 28 | }, 29 | }, 30 | }) 31 | } 32 | -------------------------------------------------------------------------------- /selectel/import_selectel_dbaas_datastore_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 8 | ) 9 | 10 | func TestAccDBaaSDatastoreV1ImportBasic(t *testing.T) { 11 | resourceName := "selectel_dbaas_datastore_v1.datastore_tf_acc_test_1" 12 | projectName := acctest.RandomWithPrefix("tf-acc") 13 | datastoreName := acctest.RandomWithPrefix("tf-acc-ds") 14 | nodeCount := 1 15 | 16 | resource.Test(t, resource.TestCase{ 17 | PreCheck: func() { testAccSelectelPreCheck(t) }, 18 | ProviderFactories: testAccProviders, 19 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 20 | Steps: []resource.TestStep{ 21 | { 22 | Config: testAccDBaaSDatastoreV1Basic(projectName, datastoreName, nodeCount), 23 | Check: testAccCheckSelectelImportEnv(resourceName), 24 | }, 25 | { 26 | ResourceName: resourceName, 27 | ImportState: true, 28 | ImportStateVerify: true, 29 | }, 30 | }, 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /selectel/import_selectel_iam_serviceuser_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 8 | ) 9 | 10 | func TestAccIAMV1ServiceUserImportBasic(t *testing.T) { 11 | resourceName := "selectel_iam_serviceuser_v1.serviceuser_tf_acc_test_1" 12 | serviceUserName := acctest.RandomWithPrefix("tf-acc") 13 | serviceUserPassword := "A" + acctest.RandString(8) + "1" 14 | 15 | resource.Test(t, resource.TestCase{ 16 | PreCheck: func() { testAccSelectelPreCheck(t) }, 17 | ProviderFactories: testAccProviders, 18 | CheckDestroy: testAccCheckIAMV1ServiceUserDestroy, 19 | Steps: []resource.TestStep{ 20 | { 21 | Config: testAccIAMV1ServiceUserBasic(serviceUserName, serviceUserPassword), 22 | }, 23 | { 24 | ResourceName: resourceName, 25 | ImportState: true, 26 | ImportStateVerify: true, 27 | ImportStateVerifyIgnore: []string{"password"}, 28 | }, 29 | }, 30 | }) 31 | } 32 | -------------------------------------------------------------------------------- /scripts/changelog-links.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script rewrites [GH-nnnn]-style references in the CHANGELOG.md file to 4 | # be Markdown links to the given github issues. 5 | # 6 | # This is run during releases so that the issue references in all of the 7 | # released items are presented as clickable links, but we can just use the 8 | # easy [GH-nnnn] shorthand for quickly adding items to the "Unrelease" section 9 | # while merging things between releases. 10 | 11 | set -e 12 | 13 | if [[ ! -f CHANGELOG.md ]]; then 14 | echo "ERROR: CHANGELOG.md not found in pwd." 15 | echo "Please run this from the root of the terraform provider repository" 16 | exit 1 17 | fi 18 | 19 | if [[ `uname` == "Darwin" ]]; then 20 | echo "Using BSD sed" 21 | SED="sed -i.bak -E -e" 22 | else 23 | echo "Using GNU sed" 24 | SED="sed -i.bak -r -e" 25 | fi 26 | 27 | PROVIDER_URL="https:\/\/github.com\/terraform-providers\/terraform-provider-selectel\/issues" 28 | 29 | $SED "s/GH-([0-9]+)/\[#\1\]\($PROVIDER_URL\/\1\)/g" -e 's/\[\[#(.+)([0-9])\)]$/(\[#\1\2))/g' CHANGELOG.md 30 | 31 | rm CHANGELOG.md.bak 32 | -------------------------------------------------------------------------------- /selectel/import_selectel_dbaas_prometheus_metric_token_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 8 | ) 9 | 10 | func TestAccDBaaSPrometheusMetricTokenV1ImportBasic(t *testing.T) { 11 | resourceName := "selectel_dbaas_prometheus_metric_token_v1.prometheus_metric_token_tf_acc_test_1" 12 | projectName := acctest.RandomWithPrefix("tf-acc") 13 | tokenName := acctest.RandomWithPrefix("tf-acc-token") 14 | 15 | resource.Test(t, resource.TestCase{ 16 | PreCheck: func() { testAccSelectelPreCheck(t) }, 17 | ProviderFactories: testAccProviders, 18 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 19 | Steps: []resource.TestStep{ 20 | { 21 | Config: testAccDBaaSPrometheusMetricTokenV1Basic(projectName, tokenName), 22 | Check: testAccCheckSelectelImportEnv(resourceName), 23 | }, 24 | { 25 | ResourceName: resourceName, 26 | ImportState: true, 27 | ImportStateVerify: true, 28 | }, 29 | }, 30 | }) 31 | } 32 | -------------------------------------------------------------------------------- /selectel/import_selectel_dbaas_postgresql_datastore_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 8 | ) 9 | 10 | func TestAccDBaaSPostgreSQLDatastoreV1ImportBasic(t *testing.T) { 11 | resourceName := "selectel_dbaas_postgresql_datastore_v1.datastore_tf_acc_test_1" 12 | projectName := acctest.RandomWithPrefix("tf-acc") 13 | datastoreName := acctest.RandomWithPrefix("tf-acc-ds") 14 | nodeCount := 1 15 | 16 | resource.Test(t, resource.TestCase{ 17 | PreCheck: func() { testAccSelectelPreCheck(t) }, 18 | ProviderFactories: testAccProviders, 19 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 20 | Steps: []resource.TestStep{ 21 | { 22 | Config: testAccDBaaSPostgreSQLDatastoreV1Basic(projectName, datastoreName, nodeCount), 23 | Check: testAccCheckSelectelImportEnv(resourceName), 24 | }, 25 | { 26 | ResourceName: resourceName, 27 | ImportState: true, 28 | ImportStateVerify: true, 29 | }, 30 | }, 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /selectel/project_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/selectel/go-selvpcclient/v4/selvpcclient/resell/v2/projects" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestFlattenVPCProjectV2Theme(t *testing.T) { 11 | testCases := []struct { 12 | have projects.Theme 13 | want map[string]string 14 | }{ 15 | { 16 | have: projects.Theme{}, 17 | want: nil, 18 | }, 19 | { 20 | have: projects.Theme{ 21 | Color: "some_color", 22 | }, 23 | want: map[string]string{ 24 | "color": "some_color", 25 | }, 26 | }, 27 | { 28 | have: projects.Theme{ 29 | Logo: "some_logo", 30 | }, 31 | want: map[string]string{ 32 | "logo": "some_logo", 33 | }, 34 | }, 35 | { 36 | have: projects.Theme{ 37 | Color: "another_color", 38 | Logo: "another_logo", 39 | }, 40 | want: map[string]string{ 41 | "color": "another_color", 42 | "logo": "another_logo", 43 | }, 44 | }, 45 | } 46 | 47 | for _, testCase := range testCases { 48 | assert.Equal(t, testCase.want, flattenVPCProjectV2Theme(testCase.have)) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /selectel/regions.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 7 | "github.com/selectel/go-selvpcclient/v4/selvpcclient" 8 | ) 9 | 10 | func expandVPCV2Regions(rawRegions *schema.Set) []string { 11 | regions := rawRegions.List() 12 | 13 | expandedRegions := make([]string, len(regions)) 14 | 15 | for i, region := range regions { 16 | expandedRegions[i] = region.(string) 17 | } 18 | 19 | return expandedRegions 20 | } 21 | 22 | func validateRegion(selvpcClient *selvpcclient.Client, serviceType string, region string) error { 23 | endpoints, err := selvpcClient.Catalog.GetEndpoints(serviceType) 24 | if err != nil { 25 | return fmt.Errorf("can't get endpoints for %s to validate region: %w", serviceType, err) 26 | } 27 | 28 | endpointRegions := make([]string, 0) 29 | 30 | for _, endpoint := range endpoints { 31 | if endpoint.Region == region { 32 | return nil 33 | } 34 | endpointRegions = append(endpointRegions, endpoint.RegionID) 35 | } 36 | 37 | return fmt.Errorf("region value must contain one of the values: %+q", endpointRegions) 38 | } 39 | -------------------------------------------------------------------------------- /selectel/import_selectel_dbaas_redis_datastore_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 8 | ) 9 | 10 | func TestAccDBaaSRedisDatastoreV1ImportBasic(t *testing.T) { 11 | resourceName := "selectel_dbaas_redis_datastore_v1.datastore_tf_acc_test_1" 12 | projectName := acctest.RandomWithPrefix("tf-acc") 13 | datastoreName := acctest.RandomWithPrefix("tf-acc-ds") 14 | nodeCount := 1 15 | 16 | resource.Test(t, resource.TestCase{ 17 | PreCheck: func() { testAccSelectelPreCheck(t) }, 18 | ProviderFactories: testAccProviders, 19 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 20 | Steps: []resource.TestStep{ 21 | { 22 | Config: testAccDBaaSRedisDatastoreV1Basic(projectName, datastoreName, nodeCount), 23 | Check: testAccCheckSelectelImportEnv(resourceName), 24 | }, 25 | { 26 | ResourceName: resourceName, 27 | ImportState: true, 28 | ImportStateVerify: true, 29 | ImportStateVerifyIgnore: []string{"redis_password"}, 30 | }, 31 | }, 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /selectel/backups.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 8 | cloudbackup "github.com/selectel/cloudbackup-go/pkg/v2" 9 | ) 10 | 11 | func getScheduledBackupClient(d *schema.ResourceData, meta interface{}) (*cloudbackup.ServiceClient, diag.Diagnostics) { 12 | config := meta.(*Config) 13 | projectID := d.Get("project_id").(string) 14 | region := d.Get("region").(string) 15 | 16 | selvpcClient, err := config.GetSelVPCClientWithProjectScope(projectID) 17 | if err != nil { 18 | return nil, diag.FromErr(fmt.Errorf("can't get project-scope selvpc client for scheduled backup api: %w", err)) 19 | } 20 | 21 | err = validateRegion(selvpcClient, DataProtectV2, region) 22 | if err != nil { 23 | return nil, diag.FromErr(fmt.Errorf("can't validate region: %w", err)) 24 | } 25 | 26 | endpoint, err := selvpcClient.Catalog.GetEndpoint(DataProtectV2, region) 27 | if err != nil { 28 | return nil, diag.FromErr(fmt.Errorf("can't get endpoint to init client: %w", err)) 29 | } 30 | 31 | return cloudbackup.NewClientV2(selvpcClient.GetXAuthToken(), endpoint.URL), nil 32 | } 33 | -------------------------------------------------------------------------------- /selectel/import_selectel_dbaas_grant_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 8 | ) 9 | 10 | func TestAccDBaaSGrantV1ImportBasic(t *testing.T) { 11 | resourceName := "selectel_dbaas_grant_v1.grant_tf_acc_test_1" 12 | projectName := acctest.RandomWithPrefix("tf-acc") 13 | datastoreName := acctest.RandomWithPrefix("tf-acc-ds") 14 | userName := RandomWithPrefix("tf_acc_user") 15 | userPassword := acctest.RandomWithPrefix("tf-acc-pass") 16 | databaseName := RandomWithPrefix("tf_acc_db") 17 | nodeCount := 1 18 | 19 | resource.Test(t, resource.TestCase{ 20 | PreCheck: func() { testAccSelectelPreCheck(t) }, 21 | ProviderFactories: testAccProviders, 22 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 23 | Steps: []resource.TestStep{ 24 | { 25 | Config: testAccDBaaSGrantV1Basic(projectName, datastoreName, userName, userPassword, databaseName, nodeCount), 26 | Check: testAccCheckSelectelImportEnv(resourceName), 27 | }, 28 | { 29 | ResourceName: resourceName, 30 | ImportState: true, 31 | ImportStateVerify: true, 32 | }, 33 | }, 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /selectel/import_selectel_dbaas_user_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 8 | ) 9 | 10 | func TestAccDBaaSUserV1ImportBasic(t *testing.T) { 11 | resourceName := "selectel_dbaas_user_v1.user_tf_acc_test_1" 12 | projectName := acctest.RandomWithPrefix("tf-acc") 13 | datastoreName := acctest.RandomWithPrefix("tf-acc-ds") 14 | userName := RandomWithPrefix("tf_acc_user") 15 | userPassword := acctest.RandomWithPrefix("tf-acc-pass") 16 | nodeCount := 1 17 | 18 | resource.Test(t, resource.TestCase{ 19 | PreCheck: func() { testAccSelectelPreCheck(t) }, 20 | ProviderFactories: testAccProviders, 21 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 22 | Steps: []resource.TestStep{ 23 | { 24 | Config: testAccDBaaSUserV1Basic(projectName, datastoreName, userName, userPassword, nodeCount), 25 | Check: testAccCheckSelectelImportEnv(resourceName), 26 | }, 27 | { 28 | ResourceName: resourceName, 29 | ImportState: true, 30 | ImportStateVerify: true, 31 | ImportStateVerifyIgnore: []string{"password"}, 32 | }, 33 | }, 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # This GitHub action will publish assets for release when a tag is created 2 | # that matches the pattern "v*" (ie. v0.1.0). 3 | # 4 | # Based on the configuration provided at: 5 | # https://github.com/hashicorp/terraform-provider-scaffolding 6 | name: Release 7 | 8 | on: 9 | push: 10 | tags: 11 | - "v*" 12 | 13 | jobs: 14 | goreleaser: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v3 19 | 20 | - name: Unshallow 21 | run: git fetch --prune --unshallow 22 | 23 | - name: Set up Go 24 | uses: actions/setup-go@v5 25 | with: 26 | go-version: "1.23" 27 | 28 | - name: Import GPG key 29 | id: import_gpg 30 | uses: paultyng/ghaction-import-gpg@v2.1.0 31 | env: 32 | GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} 33 | PASSPHRASE: ${{ secrets.PASSPHRASE }} 34 | 35 | - name: Run GoReleaser 36 | uses: goreleaser/goreleaser-action@v2 37 | with: 38 | version: latest 39 | args: release --clean 40 | env: 41 | GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} 42 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 43 | -------------------------------------------------------------------------------- /selectel/import_selectel_dbaas_database_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 8 | ) 9 | 10 | func TestAccDBaaSDatabaseV1ImportBasic(t *testing.T) { 11 | resourceName := "selectel_dbaas_database_v1.database_tf_acc_test_1" 12 | projectName := acctest.RandomWithPrefix("tf-acc") 13 | datastoreName := acctest.RandomWithPrefix("tf-acc-ds") 14 | userName := RandomWithPrefix("tf_acc_user") 15 | userPassword := acctest.RandomWithPrefix("tf-acc-pass") 16 | databaseName := RandomWithPrefix("tf_acc_db") 17 | nodeCount := 1 18 | 19 | resource.Test(t, resource.TestCase{ 20 | PreCheck: func() { testAccSelectelPreCheck(t) }, 21 | ProviderFactories: testAccProviders, 22 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 23 | Steps: []resource.TestStep{ 24 | { 25 | Config: testAccDBaaSDatabaseV1Basic(projectName, datastoreName, userName, userPassword, databaseName, nodeCount), 26 | Check: testAccCheckSelectelImportEnv(resourceName), 27 | }, 28 | { 29 | ResourceName: resourceName, 30 | ImportState: true, 31 | ImportStateVerify: true, 32 | }, 33 | }, 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /website/docs/d/domains_domain_v1.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "selectel" 3 | page_title: "Selectel: selectel_domains_domain_v1" 4 | sidebar_current: "docs-selectel-datasource-domains-domain-v1" 5 | description: |- 6 | Provides an ID of a domain in Selectel DNS Hosting (legacy). 7 | --- 8 | 9 | # selectel\_domains\_domain_v1 10 | 11 | **WARNING**: This data source is applicable to DNS Hosting (legacy). We do not support and develop DNS Hosting (legacy), but domains and records created in DNS Hosting (legacy) continue to work until further notice. We recommend to transfer your data to DNS Hosting (actual). For more information about DNS Hosting (actual), see the [official Selectel documentation](https://docs.selectel.ru/en/networks-services/dns/about-dns/). 12 | 13 | Provides an ID of a domain in DNS Hosting (legacy). 14 | 15 | ## Example Usage 16 | 17 | ```hcl 18 | data "selectel_domains_domain_v1" "domain_1" { 19 | name = "example.com" 20 | } 21 | ``` 22 | 23 | ## Argument Reference 24 | 25 | * `name` - (Required) Domain name. 26 | 27 | ## Attributes Reference 28 | 29 | * `id` - Unique identifier of the domain. 30 | 31 | * `name` - Domain name. 32 | 33 | * `user_id` - Selectel account ID. The account ID is in the top right corner of the [Control panel](https://my.selectel.ru/). 34 | -------------------------------------------------------------------------------- /selectel/import_selectel_mks_nodegroup_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 9 | ) 10 | 11 | func TestAccMKSNodegroupV1ImportBasic(t *testing.T) { 12 | resourceName := "selectel_mks_nodegroup_v1.nodegroup_tf_acc_test_1" 13 | projectName := acctest.RandomWithPrefix("tf-acc") 14 | clusterName := acctest.RandomWithPrefix("tf-acc-cl") 15 | kubeVersion := testAccMKSClusterV1GetDefaultKubeVersion(t) 16 | maintenanceWindowStart := testAccMKSClusterV1GetMaintenanceWindowStart(12 * time.Hour) 17 | 18 | resource.Test(t, resource.TestCase{ 19 | PreCheck: func() { testAccSelectelPreCheck(t) }, 20 | ProviderFactories: testAccProviders, 21 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 22 | Steps: []resource.TestStep{ 23 | { 24 | Config: testAccMKSNodegroupV1Basic(projectName, clusterName, kubeVersion, maintenanceWindowStart), 25 | Check: testAccCheckSelectelImportEnv(resourceName), 26 | }, 27 | { 28 | ResourceName: resourceName, 29 | ImportState: true, 30 | ImportStateVerify: true, 31 | ImportStateVerifyIgnore: []string{"cpus", "ram_mb"}, 32 | }, 33 | }, 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /selectel/import_selectel_dbaas_extension_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 8 | ) 9 | 10 | func TestAccDBaaSExtensionV1ImportBasic(t *testing.T) { 11 | resourceName := "selectel_dbaas_extension_v1.extension_tf_acc_test_1" 12 | projectName := acctest.RandomWithPrefix("tf-acc") 13 | datastoreName := acctest.RandomWithPrefix("tf-acc-ds") 14 | userName := RandomWithPrefix("tf_acc_user") 15 | userPassword := acctest.RandomWithPrefix("tf-acc-pass") 16 | databaseName := RandomWithPrefix("tf_acc_db") 17 | extensionName := "hstore" 18 | nodeCount := 1 19 | 20 | resource.Test(t, resource.TestCase{ 21 | PreCheck: func() { testAccSelectelPreCheck(t) }, 22 | ProviderFactories: testAccProviders, 23 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 24 | Steps: []resource.TestStep{ 25 | { 26 | Config: testAccDBaaSExtensionV1Basic(projectName, datastoreName, userName, userPassword, databaseName, extensionName, nodeCount), 27 | Check: testAccCheckSelectelImportEnv(resourceName), 28 | }, 29 | { 30 | ResourceName: resourceName, 31 | ImportState: true, 32 | ImportStateVerify: true, 33 | }, 34 | }, 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /selectel/dbaas_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 9 | "github.com/selectel/dbaas-go" 10 | ) 11 | 12 | func newTestDBaaSClient(_ context.Context, rs *terraform.ResourceState, testAccProvider *schema.Provider) (*dbaas.API, error) { 13 | config := testAccProvider.Meta().(*Config) 14 | 15 | var projectID string 16 | var endpoint string 17 | 18 | if id, ok := rs.Primary.Attributes["project_id"]; ok { 19 | projectID = id 20 | } 21 | 22 | selvpcClient, err := config.GetSelVPCClientWithProjectScope(projectID) 23 | if err != nil { 24 | return nil, fmt.Errorf("can't get selvpc client for dbaas acc tests: %w", err) 25 | } 26 | 27 | if region, ok := rs.Primary.Attributes["region"]; ok { 28 | dbaasEndpoint, err := selvpcClient.Catalog.GetEndpoint(DBaaS, region) 29 | if err != nil { 30 | return nil, fmt.Errorf("can't get endpoint for dbaas acc tests: %w", err) 31 | } 32 | endpoint = dbaasEndpoint.URL 33 | } 34 | 35 | dbaasClient, err := dbaas.NewDBAASClient(selvpcClient.GetXAuthToken(), endpoint) 36 | if err != nil { 37 | return nil, fmt.Errorf("can't get dbaas client for dbaas acc tests: %w", err) 38 | } 39 | 40 | return dbaasClient, nil 41 | } 42 | -------------------------------------------------------------------------------- /selectel/data_source_selectel_domains_domain_v1.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "strconv" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 10 | "github.com/selectel/domains-go/pkg/v1/domain" 11 | ) 12 | 13 | func dataSourceDomainsDomainV1() *schema.Resource { 14 | return &schema.Resource{ 15 | ReadContext: dataSourceDomainsDomainV1Read, 16 | Schema: map[string]*schema.Schema{ 17 | "name": { 18 | Type: schema.TypeString, 19 | Required: true, 20 | }, 21 | "user_id": { 22 | Type: schema.TypeInt, 23 | Computed: true, 24 | }, 25 | }, 26 | } 27 | } 28 | 29 | func dataSourceDomainsDomainV1Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 30 | client, err := getDomainsClient(meta) 31 | if err != nil { 32 | return diag.FromErr(err) 33 | } 34 | domainName := d.Get("name").(string) 35 | 36 | log.Print(msgGet(objectDomain, domainName)) 37 | 38 | domainObj, _, err := domain.GetByName(ctx, client, domainName) 39 | if err != nil { 40 | return diag.FromErr(errGettingObject(objectDomain, domainName, err)) 41 | } 42 | 43 | d.SetId(strconv.Itoa(domainObj.ID)) 44 | d.Set("name", domainObj.Name) 45 | d.Set("user_id", domainObj.UserID) 46 | 47 | return nil 48 | } 49 | -------------------------------------------------------------------------------- /selectel/internal/mutexkv/mutexkv_test.go: -------------------------------------------------------------------------------- 1 | package mutexkv 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | func TestMutexKVLock(t *testing.T) { 9 | mkv := NewMutexKV() 10 | 11 | mkv.Lock("foo") 12 | 13 | doneCh := make(chan struct{}) 14 | 15 | go func() { 16 | mkv.Lock("foo") 17 | close(doneCh) 18 | }() 19 | 20 | select { 21 | case <-doneCh: 22 | t.Fatal("Second lock was able to be taken. This shouldn't happen.") 23 | case <-time.After(50 * time.Millisecond): 24 | // pass 25 | } 26 | } 27 | 28 | func TestMutexKVUnlock(t *testing.T) { 29 | mkv := NewMutexKV() 30 | 31 | mkv.Lock("foo") 32 | mkv.Unlock("foo") 33 | 34 | doneCh := make(chan struct{}) 35 | 36 | go func() { 37 | mkv.Lock("foo") 38 | close(doneCh) 39 | }() 40 | 41 | select { 42 | case <-doneCh: 43 | // pass 44 | case <-time.After(50 * time.Millisecond): 45 | t.Fatal("Second lock blocked after unlock. This shouldn't happen.") 46 | } 47 | } 48 | 49 | func TestMutexKVDifferentKeys(t *testing.T) { 50 | mkv := NewMutexKV() 51 | 52 | mkv.Lock("foo") 53 | 54 | doneCh := make(chan struct{}) 55 | 56 | go func() { 57 | mkv.Lock("bar") 58 | close(doneCh) 59 | }() 60 | 61 | select { 62 | case <-doneCh: 63 | // pass 64 | case <-time.After(50 * time.Millisecond): 65 | t.Fatal("Second lock on a different key blocked. This shouldn't happen.") 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /selectel/craas_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 9 | v1 "github.com/selectel/craas-go/pkg" 10 | clientv1 "github.com/selectel/craas-go/pkg/v1/client" 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | func newCRaaSTestClient(rs *terraform.ResourceState, testAccProvider *schema.Provider) (*clientv1.ServiceClient, error) { 15 | config := testAccProvider.Meta().(*Config) 16 | 17 | var projectID string 18 | 19 | if id, ok := rs.Primary.Attributes["project_id"]; ok { 20 | projectID = id 21 | } 22 | 23 | selvpcClient, err := config.GetSelVPCClientWithProjectScope(projectID) 24 | if err != nil { 25 | return nil, fmt.Errorf("can't get selvpc client for craas acc tests: %w", err) 26 | } 27 | 28 | craasEndpoint, err := getEndpointForCRaaS(selvpcClient, CRaaS) 29 | if err != nil { 30 | return nil, fmt.Errorf("can't get endpoint for craas acc tests: %w", err) 31 | } 32 | 33 | craasClient := v1.NewCRaaSClientV1(selvpcClient.GetXAuthToken(), craasEndpoint) 34 | 35 | return craasClient, nil 36 | } 37 | 38 | func TestGetHostNameForCRaaS(t *testing.T) { 39 | expected := "https://cr.selcloud.ru" 40 | actual, err := getHostNameForCRaaS("https://cr.selcloud.ru/api/v1") 41 | assert.NoError(t, err) 42 | assert.Equal(t, expected, actual) 43 | } 44 | -------------------------------------------------------------------------------- /selectel/import_selectel_dbaas_postgresql_logical_replication_slot_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 8 | ) 9 | 10 | func TestAccDBaaSPostgreSQLLogicalReplicationSlotV1ImportBasic(t *testing.T) { 11 | resourceName := "selectel_dbaas_postgresql_logical_replication_slot_v1.slot_tf_acc_test_1" 12 | projectName := acctest.RandomWithPrefix("tf-acc") 13 | datastoreName := acctest.RandomWithPrefix("tf-acc-ds") 14 | userName := RandomWithPrefix("tf_acc_user") 15 | userPassword := acctest.RandomWithPrefix("tf-acc-pass") 16 | databaseName := RandomWithPrefix("tf_acc_db") 17 | slotName := RandomWithPrefix("tf_acc_ds") 18 | nodeCount := 1 19 | 20 | resource.Test(t, resource.TestCase{ 21 | PreCheck: func() { testAccSelectelPreCheck(t) }, 22 | ProviderFactories: testAccProviders, 23 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 24 | Steps: []resource.TestStep{ 25 | { 26 | Config: testAccDBaaSPostgreSQLLogicalReplicationSlotV1Basic(projectName, datastoreName, userName, userPassword, databaseName, slotName, nodeCount), 27 | Check: testAccCheckSelectelImportEnv(resourceName), 28 | }, 29 | { 30 | ResourceName: resourceName, 31 | ImportState: true, 32 | ImportStateVerify: true, 33 | }, 34 | }, 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /selectel/schema_selectel_dbaas_kafka_acl_v1.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 6 | ) 7 | 8 | func resourceDBaaSKafkaACKV1Schema() map[string]*schema.Schema { 9 | return map[string]*schema.Schema{ 10 | "datastore_id": { 11 | Type: schema.TypeString, 12 | Required: true, 13 | ForceNew: true, 14 | }, 15 | "region": { 16 | Type: schema.TypeString, 17 | Required: true, 18 | ForceNew: true, 19 | }, 20 | "pattern": { 21 | Type: schema.TypeString, 22 | Optional: true, 23 | ForceNew: true, 24 | }, 25 | "pattern_type": { 26 | Type: schema.TypeString, 27 | Required: true, 28 | ForceNew: true, 29 | ValidateFunc: validation.StringInSlice([]string{ 30 | "literal", 31 | "prefixed", 32 | "all", 33 | }, false), 34 | }, 35 | "user_id": { 36 | Type: schema.TypeString, 37 | Required: true, 38 | ForceNew: true, 39 | }, 40 | "allow_read": { 41 | Type: schema.TypeBool, 42 | Required: true, 43 | }, 44 | "allow_write": { 45 | Type: schema.TypeBool, 46 | Required: true, 47 | }, 48 | "status": { 49 | Type: schema.TypeString, 50 | Computed: true, 51 | }, 52 | "project_id": { 53 | Type: schema.TypeString, 54 | Required: true, 55 | ForceNew: true, 56 | }, 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /selectel/import_selectel_vpc_keypair_v2_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 8 | ) 9 | 10 | func TestAccVPCV2KeypairImportBasic(t *testing.T) { 11 | resourceName := "selectel_vpc_keypair_v2.keypair_tf_acc_test_1" 12 | keypairName := acctest.RandomWithPrefix("tf-acc") 13 | publicKey := "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSUGPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XAt3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/EnmZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbxNrRFi9wrf+M7Q== example@example.org" 14 | userName := acctest.RandomWithPrefix("tf-acc") 15 | userPassword := acctest.RandString(8) 16 | 17 | resource.Test(t, resource.TestCase{ 18 | PreCheck: func() { testAccSelectelPreCheck(t) }, 19 | ProviderFactories: testAccProviders, 20 | CheckDestroy: testAccCheckVPCV2KeypairDestroy, 21 | Steps: []resource.TestStep{ 22 | { 23 | Config: testAccVPCV2KeypairBasic(userName, userPassword, keypairName, publicKey), 24 | }, 25 | { 26 | ResourceName: resourceName, 27 | ImportState: true, 28 | ImportStateVerify: true, 29 | ImportStateVerifyIgnore: []string{"regions"}, 30 | }, 31 | }, 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /website/docs/d/dedicated_location_v1.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "selectel" 3 | page_title: "Selectel: selectel_dedicated_location_v1" 4 | sidebar_current: "docs-selectel-datasource-dedicated-location-v1" 5 | description: |- 6 | Provides a list of available locations. 7 | --- 8 | 9 | # selectel\_dedicated\_location\_v1 10 | 11 | Provides a list of available locations. 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "selectel_dedicated_location_v1" "server_location" { 17 | project_id = selectel_vpc_project_v2.project_1.id 18 | filter { 19 | name = "SPB-2" 20 | } 21 | } 22 | ``` 23 | 24 | ## Argument Reference 25 | 26 | * `project_id` - (Required) Unique identifier of the associated project. Retrieved from the [selectel_vpc_project_v2](https://registry.terraform.io/providers/selectel/selectel/latest/docs/resources/vpc_project_v2) resource. Learn more about [Projects](https://docs.selectel.ru/en/control-panel-actions/projects/about-projects/). 27 | 28 | * `filter` - (Optional) Values to filter available locations. 29 | 30 | * `name` - (Optional) Name of the location to search. Learn more about available pools in the [Availability matrix](https://docs.selectel.ru/en/availability-matrix/#dedicated-servers). 31 | 32 | ## Attributes Reference 33 | 34 | * `locations` - List of the available locations: 35 | 36 | * `id` - Unique identifier of the location. 37 | 38 | * `name` - Location name. 39 | 40 | * `description` - Location description. 41 | 42 | * `visibility` - Location visibility. 43 | -------------------------------------------------------------------------------- /selectel/internal/mutexkv/mutexkv.go: -------------------------------------------------------------------------------- 1 | package mutexkv 2 | 3 | import ( 4 | "log" 5 | "sync" 6 | ) 7 | 8 | // MutexKV is a simple key/value store for arbitrary mutexes. It can be used to 9 | // serialize changes across arbitrary collaborators that share knowledge of the 10 | // keys they must serialize on. 11 | // 12 | // This implementation is copied from v1 Terraform SDK since it was removed 13 | // from v2 SDK. 14 | type MutexKV struct { 15 | lock sync.Mutex 16 | store map[string]*sync.Mutex 17 | } 18 | 19 | // Lock the mutex for the given key. Caller is responsible for calling Unlock 20 | // for the same key. 21 | func (m *MutexKV) Lock(key string) { 22 | log.Printf("[DEBUG] Locking %q", key) 23 | m.get(key).Lock() 24 | log.Printf("[DEBUG] Locked %q", key) 25 | } 26 | 27 | // Unlock the mutex for the given key. Caller must have called Lock for the same key first. 28 | func (m *MutexKV) Unlock(key string) { 29 | log.Printf("[DEBUG] Unlocking %q", key) 30 | m.get(key).Unlock() 31 | log.Printf("[DEBUG] Unlocked %q", key) 32 | } 33 | 34 | // Returns a mutex for the given key, no guarantee of its lock status. 35 | func (m *MutexKV) get(key string) *sync.Mutex { 36 | m.lock.Lock() 37 | defer m.lock.Unlock() 38 | mutex, ok := m.store[key] 39 | if !ok { 40 | mutex = &sync.Mutex{} 41 | m.store[key] = mutex 42 | } 43 | 44 | return mutex 45 | } 46 | 47 | // Returns a properly initialized MutexKV. 48 | func NewMutexKV() *MutexKV { 49 | return &MutexKV{ 50 | store: make(map[string]*sync.Mutex), 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /selectel/schema_selectel_dbaas_mysql_datastore_v1.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 4 | 5 | func resourceDBaaSMySQLDatastoreV1Schema() map[string]*schema.Schema { 6 | datastoreSchema := resourceDBaaSDatastoreV1BaseSchema() 7 | datastoreSchema["backup_retention_days"] = &schema.Schema{ 8 | Type: schema.TypeInt, 9 | Optional: true, 10 | Description: "Number of days to retain backups.", 11 | Default: 7, 12 | } 13 | datastoreSchema["restore"] = &schema.Schema{ 14 | Type: schema.TypeSet, 15 | Optional: true, 16 | ForceNew: true, 17 | Elem: &schema.Resource{ 18 | Schema: map[string]*schema.Schema{ 19 | "datastore_id": { 20 | Type: schema.TypeString, 21 | Optional: true, 22 | }, 23 | "target_time": { 24 | Type: schema.TypeString, 25 | Optional: true, 26 | }, 27 | }, 28 | }, 29 | } 30 | datastoreSchema["floating_ips"] = &schema.Schema{ 31 | Type: schema.TypeSet, 32 | Optional: true, 33 | Elem: &schema.Resource{ 34 | Schema: map[string]*schema.Schema{ 35 | "master": { 36 | Type: schema.TypeInt, 37 | Required: true, 38 | }, 39 | "replica": { 40 | Type: schema.TypeInt, 41 | Required: true, 42 | }, 43 | }, 44 | }, 45 | } 46 | datastoreSchema["logs"] = &schema.Schema{ 47 | Type: schema.TypeString, 48 | Optional: true, 49 | Description: "Name of Logs group.", 50 | } 51 | 52 | return datastoreSchema 53 | } 54 | -------------------------------------------------------------------------------- /selectel/data_source_selectel_domains_zone_v2_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 9 | ) 10 | 11 | func TestAccDomainsZoneV2DataSourceBasic(t *testing.T) { 12 | testProjectName := acctest.RandomWithPrefix("tf-acc") 13 | testZoneName := fmt.Sprintf("%s.ru.", acctest.RandomWithPrefix("tf-acc")) 14 | resource.Test(t, resource.TestCase{ 15 | PreCheck: func() { testAccSelectelPreCheck(t) }, 16 | ProviderFactories: testAccProviders, 17 | CheckDestroy: testAccCheckDomainsV2ZoneDestroy, 18 | Steps: []resource.TestStep{ 19 | { 20 | Config: testAccDomainsZoneV2DataSourceBasic(testProjectName, resourceZoneName, testZoneName), 21 | Check: resource.ComposeTestCheckFunc( 22 | testAccDomainsZoneV2Exists(fmt.Sprintf("data.selectel_domains_zone_v2.%[1]s", resourceZoneName)), 23 | resource.TestCheckResourceAttr(fmt.Sprintf("data.selectel_domains_zone_v2.%[1]s", resourceZoneName), "name", testZoneName), 24 | ), 25 | }, 26 | }, 27 | }) 28 | } 29 | 30 | func testAccDomainsZoneV2DataSourceBasic(projectName, resourceName, zoneName string) string { 31 | return fmt.Sprintf(` 32 | %[1]s 33 | data "selectel_domains_zone_v2" %[2]q { 34 | name = selectel_domains_zone_v2.%[2]s.name 35 | project_id = "${selectel_vpc_project_v2.project_tf_acc_test_1.id}" 36 | } 37 | `, testAccDomainsZoneV2Basic(projectName, resourceName, zoneName), resourceName, zoneName) 38 | } 39 | -------------------------------------------------------------------------------- /selectel/import_selectel_domains_record_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 9 | ) 10 | 11 | func TestAccDomainsRecordV1ImportBasic(t *testing.T) { 12 | resourceName := "selectel_domains_record_v1.record_a_tf_acc_test_1" 13 | testDomainName := fmt.Sprintf("%s.xyz", acctest.RandomWithPrefix("tf-acc")) 14 | testRecordName := fmt.Sprintf("a.%s", testDomainName) 15 | 16 | resource.Test(t, resource.TestCase{ 17 | PreCheck: func() { testAccSelectelPreCheck(t) }, 18 | ProviderFactories: testAccProviders, 19 | CheckDestroy: testAccCheckDomainsV1DomainDestroy, 20 | Steps: []resource.TestStep{ 21 | { 22 | Config: testAccDomainsRecordV1BasicSingle(testDomainName, testRecordName), 23 | }, 24 | { 25 | ResourceName: resourceName, 26 | ImportState: true, 27 | ImportStateVerify: true, 28 | ImportStateVerifyIgnore: []string{"domain_id"}, 29 | }, 30 | }, 31 | }) 32 | } 33 | 34 | func testAccDomainsRecordV1BasicSingle(domainName, recordName string) string { 35 | return fmt.Sprintf(` 36 | resource "selectel_domains_domain_v1" "domain_tf_acc_test_1" { 37 | name = "%s" 38 | } 39 | 40 | resource "selectel_domains_record_v1" "record_a_tf_acc_test_1" { 41 | domain_id = selectel_domains_domain_v1.domain_tf_acc_test_1.id 42 | name = "%s" 43 | type = "A" 44 | content = "127.0.0.1" 45 | ttl = 60 46 | } 47 | `, domainName, recordName) 48 | } 49 | -------------------------------------------------------------------------------- /website/docs/r/iam_group_membership_v1.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "selectel" 3 | page_title: "Selectel: selectel_iam_group_membership_v1" 4 | sidebar_current: "docs-selectel-resource-iam-group_membership-v1" 5 | description: |- 6 | Creates and manages group membership for Selectel products using public API v1. 7 | --- 8 | 9 | # selectel\_iam\_group_membership\_v1 10 | 11 | Manages group membership for Selectel products using public API v1. 12 | Selectel products support Identity and Access Management (IAM). 13 | For more information about groups, see the [official Selectel documentation](https://docs.selectel.ru/en/control-panel-actions/users-and-roles/groups/). 14 | 15 | ## Example Usage 16 | 17 | ```hcl 18 | resource "selectel_iam_group_membership_v1" "group_membership_1" { 19 | group_id = selectel_iam_group_v1.group_1.id 20 | 21 | user_ids = [ 22 | selectel_iam_user_v1.user_1.keystone_id, 23 | selectel_iam_serviceuser_v1.serviceuser_1.id 24 | ] 25 | } 26 | ``` 27 | 28 | ## Argument Reference 29 | 30 | * `group_id` - (Required) Unique identifier of the group. Retrieved from the [selectel_iam_group_v1](https://registry.terraform.io/providers/selectel/selectel/latest/docs/resources/iam_group_v1) resource. 31 | 32 | * `user_ids` - (Required) List of unique Keystone identifiers of users. Retrieved from the [selectel_iam_serviceuser_v1](https://registry.terraform.io/providers/selectel/selectel/latest/docs/resources/iam_serviceuser_v1) and [selectel_iam_user_v1](https://registry.terraform.io/providers/selectel/selectel/latest/docs/resources/iam_user_v1) resources. 33 | -------------------------------------------------------------------------------- /selectel/waiters/dedicated/boot.go: -------------------------------------------------------------------------------- 1 | package dedicated 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "strconv" 8 | "time" 9 | 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 11 | dedicated "github.com/selectel/dedicated-go/pkg/v2" 12 | ) 13 | 14 | func WaitForServersServerInstallNewOSV1ActiveState( 15 | ctx context.Context, client *dedicated.ServiceClient, resourceID string, timeout time.Duration, 16 | ) error { 17 | timer := time.NewTimer(30 * time.Minute) 18 | 19 | stateConf := &resource.StateChangeConf{ 20 | Pending: []string{ 21 | "1", 22 | }, 23 | Target: []string{ 24 | "0", 25 | }, 26 | Refresh: serversServerInstallNewOSV1StateRefreshFunc(ctx, client, resourceID, timer), 27 | Timeout: timeout, 28 | MinTimeout: 15 * time.Second, 29 | } 30 | 31 | _, err := stateConf.WaitForStateContext(ctx) 32 | if err != nil { 33 | return fmt.Errorf("error waiting for the server %s to become 'active': %s", resourceID, err) 34 | } 35 | 36 | return nil 37 | } 38 | 39 | func serversServerInstallNewOSV1StateRefreshFunc( 40 | ctx context.Context, client *dedicated.ServiceClient, resourceID string, timer *time.Timer, 41 | ) resource.StateRefreshFunc { 42 | return func() (interface{}, string, error) { 43 | select { 44 | case <-timer.C: 45 | log.Printf("[WARN] reinstalling the OS is taking more than 30 minutes, contact support") 46 | default: 47 | } 48 | 49 | d, _, err := client.OperatingSystemByResource(ctx, resourceID) 50 | if err != nil { 51 | return nil, "", err 52 | } 53 | 54 | return d, strconv.Itoa(d.Reinstall), nil 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | run: 3 | modules-download-mode: readonly 4 | linters: 5 | default: none 6 | enable: 7 | - asciicheck 8 | - bodyclose 9 | - copyloopvar 10 | - dogsled 11 | - errcheck 12 | - exhaustive 13 | - gocognit 14 | - goconst 15 | - gocritic 16 | - gocyclo 17 | - godot 18 | - godox 19 | - goheader 20 | - gomodguard 21 | - goprintffuncname 22 | - gosec 23 | - govet 24 | - ineffassign 25 | - misspell 26 | - nakedret 27 | - nlreturn 28 | - noctx 29 | - nolintlint 30 | - prealloc 31 | - revive 32 | - rowserrcheck 33 | - sqlclosecheck 34 | - staticcheck 35 | - unconvert 36 | - unused 37 | - whitespace 38 | settings: 39 | nlreturn: 40 | block-size: 3 41 | exclusions: 42 | generated: lax 43 | presets: 44 | - comments 45 | - common-false-positives 46 | - legacy 47 | - std-error-handling 48 | rules: 49 | - linters: 50 | - staticcheck 51 | text: 'SA1019:' 52 | - linters: 53 | - errcheck 54 | text: Error return value of `d.Set` is not checked 55 | - linters: 56 | - gosec 57 | text: 'G501:' 58 | - linters: 59 | - gosec 60 | text: 'G404:' 61 | paths: 62 | - third_party$ 63 | - builtin$ 64 | - examples$ 65 | formatters: 66 | enable: 67 | - gci 68 | - gofmt 69 | - gofumpt 70 | - goimports 71 | exclusions: 72 | generated: lax 73 | paths: 74 | - third_party$ 75 | - builtin$ 76 | - examples$ 77 | -------------------------------------------------------------------------------- /website/docs/d/mks_feature_gates_v1.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "selectel" 3 | page_title: "Selectel: selectel_mks_feature_gates_v1" 4 | sidebar_current: "docs-selectel-datasource-mks-feature-gates-v1" 5 | description: |- 6 | Provides a list of feature gates available in Selectel Managed Kubernetes. 7 | --- 8 | 9 | # selectel\_mks\_feature_gates_v1 10 | 11 | Provides a list of available feature gates. For more information about feature gates in Managed Kubernetes, see the [official Selectel documentation](https://docs.selectel.ru/en/cloud/managed-kubernetes/clusters/feature-gates/). 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "selectel_mks_feature_gates_v1" "fg" { 17 | project_id = selectel_vpc_project_v2.project_1.id 18 | region = "ru-3" 19 | } 20 | ``` 21 | 22 | ## Argument Reference 23 | 24 | * `project_id` - (Required) Unique identifier of the associated project. Retrieved from the [selectel_vpc_project_v2](https://registry.terraform.io/providers/selectel/selectel/latest/docs/resources/vpc_project_v2) resource. Learn more about [Projects](https://docs.selectel.ru/en/control-panel-actions/projects/about-projects/). 25 | 26 | * `region` - (Required) Pool where the cluster is located, for example, `ru-3`. 27 | 28 | * `filter` - (Optional) Values to filter available feature gates: 29 | 30 | * `kube_version` - (Optional) Kubernetes version for which you get available feature gates. 31 | 32 | ## Attributes Reference 33 | 34 | * `feature_gates` - List of available feature gates. 35 | 36 | * `kube_version` - Kubernetes version. 37 | 38 | * `names` - Names of the feature gates available for the specified version. -------------------------------------------------------------------------------- /examples/project-with-floating-ips/main.tf: -------------------------------------------------------------------------------- 1 | resource "selectel_vpc_project_v2" "webservice" { 2 | name = "webservice" 3 | 4 | quotas { 5 | resource_name = "compute_cores" 6 | resource_quotas { 7 | region = "ru-1" 8 | zone = "ru-1a" 9 | value = 4 10 | } 11 | resource_quotas { 12 | region = "ru-2" 13 | zone = "ru-2a" 14 | value = 6 15 | } 16 | } 17 | 18 | quotas { 19 | resource_name = "compute_ram" 20 | resource_quotas { 21 | region = "ru-1" 22 | zone = "ru-1a" 23 | value = 10240 24 | } 25 | resource_quotas { 26 | region = "ru-2" 27 | zone = "ru-2a" 28 | value = 8192 29 | } 30 | } 31 | 32 | quotas { 33 | resource_name = "volume_gigabytes_fast" 34 | resource_quotas { 35 | region = "ru-1" 36 | zone = "ru-1a" 37 | value = 10 38 | } 39 | resource_quotas { 40 | region = "ru-2" 41 | zone = "ru-2a" 42 | value = 8 43 | } 44 | } 45 | } 46 | 47 | resource "selectel_vpc_floatingip_v2" "webservice_floating_ip_ru1_1" { 48 | project_id = "${selectel_vpc_project_v2.webservice.id}" 49 | region = "ru-1" 50 | depends_on = ["selectel_vpc_project_v2.webservice"] 51 | } 52 | 53 | resource "selectel_vpc_floatingip_v2" "webservice_floating_ip_ru1_2" { 54 | project_id = "${selectel_vpc_project_v2.webservice.id}" 55 | region = "ru-1" 56 | depends_on = ["selectel_vpc_project_v2.webservice"] 57 | } 58 | 59 | resource "selectel_vpc_floatingip_v2" "webservice_floating_ip_ru2_1" { 60 | project_id = "${selectel_vpc_project_v2.webservice.id}" 61 | region = "ru-2" 62 | depends_on = ["selectel_vpc_project_v2.webservice"] 63 | } 64 | -------------------------------------------------------------------------------- /selectel/data_source_selectel_cloudbackup_plan_v2_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 9 | "github.com/selectel/go-selvpcclient/v4/selvpcclient/resell/v2/projects" 10 | ) 11 | 12 | func TestAccCloudBackupPlanV2Basic(t *testing.T) { 13 | var ( 14 | project projects.Project 15 | projectName = acctest.RandomWithPrefix("tf-acc") 16 | ) 17 | 18 | resource.Test(t, resource.TestCase{ 19 | PreCheck: func() { testAccSelectelPreCheck(t) }, 20 | ProviderFactories: testAccProviders, 21 | Steps: []resource.TestStep{ 22 | { 23 | Config: testAccCloudBackupPlanV2Basic(projectName), 24 | Check: resource.ComposeTestCheckFunc( 25 | testAccCheckVPCV2ProjectExists("selectel_vpc_project_v2.project_tf_acc_test_1", &project), 26 | resource.TestCheckResourceAttr( 27 | "data.selectel_cloudbackup_plan_v2.plans", "plans.list.#", "0", 28 | ), 29 | resource.TestCheckResourceAttr( 30 | "data.selectel_cloudbackup_plan_v2.plans", "plans.total.#", "0", 31 | ), 32 | ), 33 | }, 34 | }, 35 | }) 36 | } 37 | 38 | func testAccCloudBackupPlanV2Basic(projectName string) string { 39 | return fmt.Sprintf(` 40 | resource "selectel_vpc_project_v2" "project_tf_acc_test_1" { 41 | name = "%s" 42 | } 43 | 44 | data "selectel_cloudbackup_plan_v2" "plans" { 45 | project_id = "53c3fcf719044d1487e6a9d72d66b0a8" 46 | region = "ru-1" 47 | 48 | filter { 49 | name = "non-existent" 50 | volume_name = "non-existent-volume" 51 | status = "started" 52 | } 53 | } 54 | `, projectName) 55 | } 56 | -------------------------------------------------------------------------------- /selectel/messages_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/selectel/go-selvpcclient/v4/selvpcclient/resell/v2/keypairs" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | const ( 11 | testMsgObject = "keypair" 12 | testMsgID = "abcaae6eee494b76af4b006b882c1926/key1" 13 | ) 14 | 15 | var testMsgOptions = keypairs.KeypairOpts{ 16 | Name: "key1", 17 | PublicKey: "ssh-rsa AAABBBCCC user0@example.org", 18 | UserID: "abcaae6eee494b76af4b006b882c1926", 19 | Regions: []string{"ru-3"}, 20 | } 21 | 22 | func TestMsgCreate(t *testing.T) { 23 | expected := "[DEBUG] Creating keypair with options: {Name:key1 PublicKey:ssh-rsa AAABBBCCC user0@example.org Regions:[ru-3] UserID:abcaae6eee494b76af4b006b882c1926}" 24 | 25 | actual := msgCreate(testMsgObject, testMsgOptions) 26 | 27 | assert.Equal(t, expected, actual) 28 | } 29 | 30 | func TestMsgGet(t *testing.T) { 31 | expected := "[DEBUG] Getting keypair 'abcaae6eee494b76af4b006b882c1926/key1'" 32 | 33 | actual := msgGet(testMsgObject, testMsgID) 34 | 35 | assert.Equal(t, expected, actual) 36 | } 37 | 38 | func TestMsgUpdate(t *testing.T) { 39 | expected := "[DEBUG] Updating keypair 'abcaae6eee494b76af4b006b882c1926/key1' with options: {Name:key1 PublicKey:ssh-rsa AAABBBCCC user0@example.org Regions:[ru-3] UserID:abcaae6eee494b76af4b006b882c1926}" 40 | 41 | actual := msgUpdate(testMsgObject, testMsgID, testMsgOptions) 42 | 43 | assert.Equal(t, expected, actual) 44 | } 45 | 46 | func TestMsgDelete(t *testing.T) { 47 | expected := "[DEBUG] Deleting keypair 'abcaae6eee494b76af4b006b882c1926/key1'" 48 | 49 | actual := msgDelete(testMsgObject, testMsgID) 50 | 51 | assert.Equal(t, expected, actual) 52 | } 53 | -------------------------------------------------------------------------------- /website/docs/d/mks_admission_controllers_v1.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "selectel" 3 | page_title: "Selectel: selectel_mks_admission_controllers_v1" 4 | sidebar_current: "docs-selectel-datasource-mks-admission-controllers-v1" 5 | description: |- 6 | Provides a list of admission controllers available in Selectel Managed Kubernetes. 7 | --- 8 | 9 | # selectel\_mks\_admission_controllers_v1 10 | 11 | Provides a list of available admission controllers. For more information about admission controllers in Managed Kubernetes, see the [official Selectel documentation](https://docs.selectel.ru/en/cloud/managed-kubernetes/clusters/admission-controllers/). 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "selectel_mks_admission_controllers_v1" "admission_controllers_1" { 17 | project_id = selectel_vpc_project_v2.project_1.id 18 | region = "ru-3" 19 | } 20 | ``` 21 | 22 | ## Argument Reference 23 | 24 | * `project_id` - (Required) Unique identifier of the associated project. Retrieved from the [selectel_vpc_project_v2](https://registry.terraform.io/providers/selectel/selectel/latest/docs/resources/vpc_project_v2) resource. Learn more about [Projects](https://docs.selectel.ru/en/control-panel-actions/projects/about-projects/). 25 | 26 | * `region` - (Required) Pool where the cluster is located, for example, `ru-3`. 27 | 28 | * `filter` - (Optional) Values to filter available admission controllers: 29 | 30 | * `kube_version` - (Optional) Kubernetes version for which you get available admission controllers. 31 | 32 | ## Attributes Reference 33 | 34 | * `admission_controllers` - List of available admission controllers. 35 | 36 | * `kube_version` - Kubernetes version. 37 | 38 | * `names` - Names of the admission controllers available for the specified Kubernetes version. -------------------------------------------------------------------------------- /selectel/data_source_selectel_cloudbackup_checkpoint_v2_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 9 | "github.com/selectel/go-selvpcclient/v4/selvpcclient/resell/v2/projects" 10 | ) 11 | 12 | func TestAccCloudBackupCheckpointV2Basic(t *testing.T) { 13 | var ( 14 | project projects.Project 15 | projectName = acctest.RandomWithPrefix("tf-acc") 16 | ) 17 | 18 | resource.Test(t, resource.TestCase{ 19 | PreCheck: func() { testAccSelectelPreCheck(t) }, 20 | ProviderFactories: testAccProviders, 21 | Steps: []resource.TestStep{ 22 | { 23 | Config: testAccCloudBackupCheckpointV2Basic(projectName), 24 | Check: resource.ComposeTestCheckFunc( 25 | testAccCheckVPCV2ProjectExists("selectel_vpc_project_v2.project_tf_acc_test_1", &project), 26 | resource.TestCheckResourceAttr( 27 | "data.selectel_cloudbackup_checkpoint_v2.checkpoints", "checkpoints.list.#", "0", 28 | ), 29 | resource.TestCheckResourceAttr( 30 | "data.selectel_cloudbackup_checkpoint_v2.checkpoints", "checkpoints.total.#", "0", 31 | ), 32 | ), 33 | }, 34 | }, 35 | }) 36 | } 37 | 38 | func testAccCloudBackupCheckpointV2Basic(projectName string) string { 39 | return fmt.Sprintf(` 40 | resource "selectel_vpc_project_v2" "project_tf_acc_test_1" { 41 | name = "%s" 42 | } 43 | 44 | data "selectel_cloudbackup_checkpoint_v2" "checkpoints" { 45 | project_id = "${selectel_vpc_project_v2.project_tf_acc_test_1.id}" 46 | region = "ru-1" 47 | 48 | filter { 49 | plan_name = "non-existing-plan-name" 50 | volume_name = "non-existing-volume-name" 51 | } 52 | } 53 | `, projectName) 54 | } 55 | -------------------------------------------------------------------------------- /selectel/networking.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | 8 | "github.com/selectel/go-selvpcclient/v4/selvpcclient" 9 | "github.com/selectel/go-selvpcclient/v4/selvpcclient/resell/v2/subnets" 10 | ) 11 | 12 | func getPrefixLengthFromCIDR(cidr string) (int, error) { 13 | cidrParts := strings.Split(cidr, "/") 14 | if len(cidrParts) != 2 { 15 | return 0, fmt.Errorf("got invalid CIDR: %s", cidr) 16 | } 17 | 18 | prefixLenght, err := strconv.Atoi(cidrParts[1]) 19 | if err != nil { 20 | return 0, fmt.Errorf("error reading prefix length from '%s': %s", cidrParts[1], err) 21 | } 22 | 23 | return prefixLenght, nil 24 | } 25 | 26 | func getIPVersionFromPrefixLength(prefixLength int) string { 27 | // Any subnet with prefix length larger than 32 is a IPv6 protocol subnet 28 | // and Selectel doesn't provide any IPv6 subnets with smaller prefix lengths. 29 | if prefixLength > 32 { 30 | return string(selvpcclient.IPv6) 31 | } 32 | 33 | return string(selvpcclient.IPv4) 34 | } 35 | 36 | // subnetsMapsFromStructs converts the provided subnets.Subnet to 37 | // the slice of maps correspondingly to the resource's schema. 38 | func subnetsMapsFromStructs(subnetsStructs []subnets.Subnet) []map[string]interface{} { 39 | associatedSubnets := make([]map[string]interface{}, len(subnetsStructs)) 40 | 41 | for i, subnet := range subnetsStructs { 42 | associatedSubnets[i] = map[string]interface{}{ 43 | "network_id": subnet.NetworkID, 44 | "subnet_id": subnet.SubnetID, 45 | "region": subnet.Region, 46 | "cidr": subnet.CIDR, 47 | "vlan_id": subnet.VLANID, 48 | "project_id": subnet.ProjectID, 49 | "vtep_ip_address": subnet.VTEPIPAddress, 50 | } 51 | } 52 | 53 | return associatedSubnets 54 | } 55 | -------------------------------------------------------------------------------- /website/docs/d/mks_kube_versions_v1.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "selectel" 3 | page_title: "Selectel: selectel_mks_kube_versions_v1" 4 | sidebar_current: "docs-selectel-datasource-mks-kube-versions-v1" 5 | description: |- 6 | Provides a list of Kubernetes versions supported in a Selectel Managed Kubernetes cluster. 7 | --- 8 | 9 | # selectel\_mks\_kube_versions_v1 10 | 11 | Provides a list of supported Kubernetes versions for a Managed Kubernetes cluster. For more information about Managed Kubernetes, see the [official Selectel documentation](https://docs.selectel.ru/en/cloud/managed-kubernetes/about/about-managed-kubernetes/). 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "selectel_mks_kube_versions_v1" "versions" { 17 | project_id = selectel_vpc_project_v2.project_1.id 18 | region = "ru-3" 19 | } 20 | 21 | output "latest_version" { 22 | value = data.selectel_mks_kube_versions_v1.versions.latest_version 23 | } 24 | 25 | output "default_version" { 26 | value = data.selectel_mks_kube_versions_v1.versions.default_version 27 | } 28 | 29 | output "versions" { 30 | value = data.selectel_mks_kube_versions_v1.versions.versions 31 | } 32 | ``` 33 | 34 | ## Argument Reference 35 | 36 | * `project_id` - (Required) Unique identifier of the associated project. Retrieved from the [selectel_vpc_project_v2](https://registry.terraform.io/providers/selectel/selectel/latest/docs/resources/vpc_project_v2) resource. Learn more about [Projects](https://docs.selectel.ru/en/control-panel-actions/projects/about-projects/). 37 | 38 | * `region` - (Required) Pool where the cluster is located, for example, `ru-3`. 39 | 40 | ## Attributes Reference 41 | 42 | * `latest_version` - The most recent version. 43 | 44 | * `default_version` - Kubernetes version used by default. 45 | 46 | * `versions` - List of the supported versions. -------------------------------------------------------------------------------- /website/docs/d/domains_zone_v2.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "selectel" 3 | page_title: "Selectel: selectel_domains_zone_v2" 4 | sidebar_current: "docs-selectel-datasource-domains-zone-v2" 5 | description: |- 6 | Provides information about a zone in Selectel DNS Hosting (actual). 7 | --- 8 | 9 | # selectel\_domains\_zone_v2 10 | 11 | Provides information about a zone in Selectel DNS Hosting (actual). For more information about zones, see the [official Selectel documentation](https://docs.selectel.ru/en/networks-services/dns/zones/). 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "selectel_domains_zone_v2" "zone_1" { 17 | name = "example.com." 18 | project_id = selectel_vpc_project_v2.project_1.id 19 | } 20 | ``` 21 | 22 | ## Argument Reference 23 | 24 | * `name` - (Required) Zone name. 25 | 26 | * `project_id` - (Required) Unique identifier of the associated project. Retrieved from the [selectel_vpc_project_v2](https://registry.terraform.io/providers/selectel/selectel/latest/docs/resources/vpc_project_v2) resource. Learn more about [Projects](https://docs.selectel.ru/en/control-panel-actions/projects/about-projects/). 27 | 28 | ## Attributes Reference 29 | 30 | * `comment` - Comment for the zone. 31 | 32 | * `created_at` - Time when the zone was created in the RFC 3339 timestamp format. 33 | 34 | * `updated_at` - Time when the zone was updated in the RFC 3339 timestamp format. 35 | 36 | * `delegation_checked_at` - Time when DNS Hosting checked if the zone was delegated to Selectel NS servers in the RFC 3339 timestamp format. 37 | 38 | * `last_check_status` - Zone status retrieved during the last delegation check. 39 | 40 | * `last_delegated_at` - Equals to the `delegation_check_at` argument value when the `last_check_status` is `true`. 41 | 42 | * `disabled` - Shows if the zone is enabled or disabled. 43 | -------------------------------------------------------------------------------- /selectel/domains_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestDomainsV1ParseDomainRecordIDsPair(t *testing.T) { 10 | tableTest := []struct { 11 | input string 12 | expectedDomainID int 13 | expectedRecordID int 14 | err error 15 | }{ 16 | { 17 | input: "123/321", 18 | expectedDomainID: 123, 19 | expectedRecordID: 321, 20 | }, 21 | { 22 | input: "321", 23 | expectedDomainID: -1, 24 | expectedRecordID: -1, 25 | err: errParseDomainsDomainRecordV1IDsPair("321"), 26 | }, 27 | { 28 | input: "", 29 | expectedDomainID: -1, 30 | expectedRecordID: -1, 31 | err: errParseDomainsDomainRecordV1IDsPair(""), 32 | }, 33 | { 34 | input: "invalid/123", 35 | expectedDomainID: -1, 36 | expectedRecordID: -1, 37 | err: errParseDomainsDomainV1ID("invalid"), 38 | }, 39 | { 40 | input: "123/invalid", 41 | expectedDomainID: -1, 42 | expectedRecordID: -1, 43 | err: errParseDomainsRecordV1ID("invalid"), 44 | }, 45 | } 46 | 47 | for _, test := range tableTest { 48 | gotDomainID, gotRecordID, err := domainsV1ParseDomainRecordIDsPair(test.input) 49 | assert.Equal(t, test.err, err) 50 | assert.Equal(t, test.expectedDomainID, gotDomainID) 51 | assert.Equal(t, test.expectedRecordID, gotRecordID) 52 | } 53 | } 54 | 55 | func TestGetIntPtrOrNil(_ *testing.T) { 56 | tableTest := []struct { 57 | input interface{} 58 | expected *int 59 | }{ 60 | { 61 | input: 123, 62 | expected: intPtr(123), 63 | }, 64 | { 65 | input: nil, 66 | expected: nil, 67 | }, 68 | } 69 | 70 | for _, test := range tableTest { 71 | getIntPtrOrNil(test.input) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /selectel/import_selectel_domains_zone_v2_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "testing" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 11 | ) 12 | 13 | func TestAccDomainsZoneV2ImportBasic(t *testing.T) { 14 | projectID := os.Getenv("INFRA_PROJECT_ID") 15 | fullResourceName := fmt.Sprintf("selectel_domains_zone_v2.%[1]s", resourceZoneName) 16 | testZoneName := fmt.Sprintf("%s.xyz.", acctest.RandomWithPrefix("tf-acc")) 17 | resource.Test(t, resource.TestCase{ 18 | PreCheck: func() { testAccSelectelPreCheckWithProjectID(t) }, 19 | ProviderFactories: testAccProviders, 20 | CheckDestroy: testAccCheckDomainsV2ZoneDestroy, 21 | Steps: []resource.TestStep{ 22 | { 23 | Config: testAccDomainsZoneV2WithoutProjectBasic(projectID, resourceZoneName, testZoneName), 24 | }, 25 | { 26 | ResourceName: fullResourceName, 27 | ImportState: true, 28 | ImportStateVerify: true, 29 | ImportStateIdFunc: getTestZoneIDForImport, 30 | }, 31 | }, 32 | }) 33 | } 34 | 35 | func getTestZoneIDForImport(s *terraform.State) (string, error) { 36 | resourceZoneFullName := "selectel_domains_zone_v2.zone_tf_acc_test_1" 37 | resourceZone, ok := s.RootModule().Resources[resourceZoneFullName] 38 | if !ok { 39 | return "", fmt.Errorf("Not found zone: %s", resourceZoneFullName) 40 | } 41 | 42 | return resourceZone.Primary.Attributes["name"], nil 43 | } 44 | 45 | func testAccDomainsZoneV2WithoutProjectBasic(projectID, resourceName, zoneName string) string { 46 | return fmt.Sprintf(` 47 | resource "selectel_domains_zone_v2" %[2]q { 48 | name = %[3]q 49 | project_id = %[1]q 50 | }`, projectID, resourceName, zoneName) 51 | } 52 | -------------------------------------------------------------------------------- /selectel/internal/reflect/map.go: -------------------------------------------------------------------------------- 1 | package reflect 2 | 3 | import "reflect" 4 | 5 | func IsSetContainsSubset(subset, set map[string]interface{}) bool { 6 | for k, subsetValue := range subset { 7 | setValue, ok := set[k] 8 | if !ok { 9 | return false 10 | } 11 | 12 | switch subsetValueTyped := subsetValue.(type) { 13 | case map[string]interface{}: 14 | setValueTyped, ok := setValue.(map[string]interface{}) 15 | if !ok || !IsSetContainsSubset(subsetValueTyped, setValueTyped) { 16 | return false 17 | } 18 | 19 | case []interface{}: 20 | setValueTyped, ok := setValue.([]interface{}) 21 | if !ok { 22 | return false 23 | } 24 | if !isArrayContainsSubarray(subsetValueTyped, setValueTyped) { 25 | return false 26 | } 27 | 28 | default: 29 | if !reflect.DeepEqual(subsetValue, setValue) { 30 | return false 31 | } 32 | } 33 | } 34 | 35 | return true 36 | } 37 | 38 | func isArrayContainsSubarray(subarray, array []interface{}) bool { 39 | for _, subarrayElement := range subarray { 40 | found := false 41 | for _, arrayElement := range array { 42 | switch subarrayElementTyped := subarrayElement.(type) { 43 | case map[string]interface{}: 44 | arrayElementTyped, ok := arrayElement.(map[string]interface{}) 45 | if ok && IsSetContainsSubset(subarrayElementTyped, arrayElementTyped) { 46 | found = true 47 | break 48 | } 49 | 50 | case []interface{}: 51 | arrayElementTyped, ok := arrayElement.([]interface{}) 52 | if ok && isArrayContainsSubarray(subarrayElementTyped, arrayElementTyped) { 53 | found = true 54 | break 55 | } 56 | 57 | default: 58 | if reflect.DeepEqual(subarrayElement, arrayElement) { 59 | found = true 60 | break 61 | } 62 | } 63 | } 64 | if !found { 65 | return false 66 | } 67 | } 68 | 69 | return true 70 | } 71 | -------------------------------------------------------------------------------- /website/docs/d/domains_rrset_v2.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "selectel" 3 | page_title: "Selectel: selectel_domains_rrset_v2" 4 | sidebar_current: "docs-selectel-datasource-domains-rrset-v2" 5 | description: |- 6 | Provides information about an RRSet in Selectel DNS Hosting (actual). 7 | --- 8 | 9 | # selectel\_domains\_rrset_v2 10 | 11 | Provides information about an RRSet in DNS Hosting (actual). For more information about RRSets, see the [official Selectel documentation](https://docs.selectel.ru/en/networks-services/dns/records/). 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "selectel_domains_rrset_v2" "rrset_1" { 17 | name = "example.com." 18 | type = "A" 19 | zone_id = selectel_domains_zone_v2.zone_1.id 20 | project_id = selectel_vpc_project_v2.project_1.id 21 | } 22 | ``` 23 | 24 | ## Argument Reference 25 | 26 | * `name` - (Required) RRSet name. 27 | 28 | * `type` - (Required) RRSet type. Available types are `A`, `AAAA`, `TXT`, `CNAME`, `NS`, `MX`, `SRV`, `SSHFP`, `ALIAS`, `CAA`. 29 | 30 | * `zone_id` - (Required) Unique identifier of the zone. Retrieved from the [selectel_domains_zone_v2](https://registry.terraform.io/providers/selectel/selectel/latest/docs/resources/domains_zone_v2) resource. 31 | 32 | * `project_id` - (Required) Unique identifier of the associated project. Retrieved from the [selectel_vpc_project_v2](https://registry.terraform.io/providers/selectel/selectel/latest/docs/resources/vpc_project_v2) resource. Learn more about [Projects](https://docs.selectel.ru/en/control-panel-actions/projects/about-projects/). 33 | 34 | ## Attributes Reference 35 | 36 | * `ttl` - RRSet time-to-live in seconds. 37 | 38 | * `comment` - Comment for the RRSet. 39 | 40 | * `managed_by` - RRSet owner. 41 | 42 | * `records` - List of records in the RRSet. 43 | 44 | * `content` - Record value. 45 | 46 | * `disabled` - Shows if the record is enabled or disabled. 47 | -------------------------------------------------------------------------------- /selectel/waiters/dbaas/acl.go: -------------------------------------------------------------------------------- 1 | package waiters 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "net/http" 8 | "strconv" 9 | "time" 10 | 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 12 | "github.com/selectel/dbaas-go" 13 | ) 14 | 15 | func WaitForDBaaSACLV1ActiveState( 16 | ctx context.Context, client *dbaas.API, aclID string, timeout time.Duration, 17 | ) error { 18 | pending := []string{ 19 | string(dbaas.StatusPendingCreate), 20 | string(dbaas.StatusPendingUpdate), 21 | } 22 | target := []string{ 23 | string(dbaas.StatusActive), 24 | } 25 | 26 | stateConf := &resource.StateChangeConf{ 27 | Pending: pending, 28 | Target: target, 29 | Refresh: dbaasACLV1StateRefreshFunc(ctx, client, aclID), 30 | Timeout: timeout, 31 | Delay: 10 * time.Second, 32 | MinTimeout: 15 * time.Second, 33 | } 34 | 35 | _, err := stateConf.WaitForStateContext(ctx) 36 | if err != nil { 37 | return fmt.Errorf( 38 | "error waiting for the acl %s to become 'ACTIVE': %s", 39 | aclID, err) 40 | } 41 | 42 | return nil 43 | } 44 | 45 | func DBaaSACLV1DeleteStateRefreshFunc(ctx context.Context, client *dbaas.API, aclID string) resource.StateRefreshFunc { 46 | return func() (interface{}, string, error) { 47 | d, err := client.ACL(ctx, aclID) 48 | if err != nil { 49 | var dbaasError *dbaas.DBaaSAPIError 50 | if errors.As(err, &dbaasError) { 51 | return d, strconv.Itoa(dbaasError.StatusCode()), nil 52 | } 53 | 54 | return nil, "", err 55 | } 56 | 57 | return d, strconv.Itoa(http.StatusOK), err 58 | } 59 | } 60 | 61 | func dbaasACLV1StateRefreshFunc(ctx context.Context, client *dbaas.API, aclID string) resource.StateRefreshFunc { 62 | return func() (interface{}, string, error) { 63 | d, err := client.ACL(ctx, aclID) 64 | if err != nil { 65 | return nil, "", err 66 | } 67 | 68 | return d, string(d.Status), nil 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /selectel/waiters/dbaas/grant.go: -------------------------------------------------------------------------------- 1 | package waiters 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "strconv" 8 | "time" 9 | 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 11 | "github.com/selectel/dbaas-go" 12 | ) 13 | 14 | func WaitForDBaaSGrantV1ActiveState( 15 | ctx context.Context, client *dbaas.API, grantID string, timeout time.Duration, 16 | ) error { 17 | pending := []string{ 18 | string(dbaas.StatusPendingCreate), 19 | string(dbaas.StatusPendingUpdate), 20 | } 21 | target := []string{ 22 | string(dbaas.StatusActive), 23 | } 24 | 25 | stateConf := &resource.StateChangeConf{ 26 | Pending: pending, 27 | Target: target, 28 | Refresh: dbaasGrantV1StateRefreshFunc(ctx, client, grantID), 29 | Timeout: timeout, 30 | Delay: 10 * time.Second, 31 | MinTimeout: 10 * time.Second, 32 | } 33 | 34 | _, err := stateConf.WaitForStateContext(ctx) 35 | if err != nil { 36 | return fmt.Errorf( 37 | "error waiting for the grant %s to become 'ACTIVE': %s", 38 | grantID, err) 39 | } 40 | 41 | return nil 42 | } 43 | 44 | func DBaaSGrantV1DeleteStateRefreshFunc(ctx context.Context, client *dbaas.API, grantID string) resource.StateRefreshFunc { 45 | return func() (interface{}, string, error) { 46 | d, err := client.Grant(ctx, grantID) 47 | if err != nil { 48 | var dbaasError *dbaas.DBaaSAPIError 49 | if errors.As(err, &dbaasError) { 50 | return d, strconv.Itoa(dbaasError.StatusCode()), nil 51 | } 52 | 53 | return nil, "", err 54 | } 55 | 56 | return d, strconv.Itoa(200), err 57 | } 58 | } 59 | 60 | func dbaasGrantV1StateRefreshFunc(ctx context.Context, client *dbaas.API, grantID string) resource.StateRefreshFunc { 61 | return func() (interface{}, string, error) { 62 | d, err := client.Grant(ctx, grantID) 63 | if err != nil { 64 | return nil, "", err 65 | } 66 | 67 | return d, string(d.Status), nil 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | # Visit https://goreleaser.com for documentation on how to customize this 2 | # behavior. 3 | version: 2 4 | before: 5 | hooks: 6 | # this is just an example and not a requirement for provider building/publishing 7 | - go mod tidy 8 | builds: 9 | - env: 10 | # goreleaser does not work with CGO, it could also complicate 11 | # usage by users in CI/CD systems like Terraform Cloud where 12 | # they are unable to install libraries. 13 | - CGO_ENABLED=0 14 | mod_timestamp: '{{ .CommitTimestamp }}' 15 | flags: 16 | - -trimpath 17 | ldflags: 18 | - '-s -w -X github.com/terraform-providers/terraform-provider-selectel/version.Version={{.Version}} -X github.com/terraform-providers/terraform-provider-selectel/version.Commit={{.Commit}}' 19 | goos: 20 | - freebsd 21 | - windows 22 | - linux 23 | - darwin 24 | goarch: 25 | - amd64 26 | - '386' 27 | - arm 28 | - arm64 29 | ignore: 30 | - goos: darwin 31 | goarch: '386' 32 | binary: '{{ .ProjectName }}_v{{ .Version }}' 33 | archives: 34 | - format: zip 35 | name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}' 36 | checksum: 37 | name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS' 38 | algorithm: sha256 39 | signs: 40 | - artifacts: checksum 41 | args: 42 | # if you are using this is a GitHub action or some other automated pipeline, you 43 | # need to pass the batch flag to indicate its not interactive. 44 | - "--batch" 45 | - "--local-user" 46 | - "{{ .Env.GPG_FINGERPRINT }}" # set this environment variable for your signing key 47 | - "--output" 48 | - "${signature}" 49 | - "--detach-sign" 50 | - "${artifact}" 51 | release: 52 | # Visit your project's GitHub Releases page to publish this release. 53 | draft: true 54 | changelog: 55 | disable: true -------------------------------------------------------------------------------- /selectel/data_source_selectel_domains_domain_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "testing" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 11 | ) 12 | 13 | func TestAccDomainsDomainV1DataSourceBasic(t *testing.T) { 14 | testDomainName := fmt.Sprintf("%s.xyz", acctest.RandomWithPrefix("tf-acc")) 15 | 16 | resource.Test(t, resource.TestCase{ 17 | PreCheck: func() { testAccSelectelPreCheck(t) }, 18 | ProviderFactories: testAccProviders, 19 | CheckDestroy: testAccCheckDomainsV1DomainDestroy, 20 | Steps: []resource.TestStep{ 21 | { 22 | Config: testAccDomainsDomainV1Basic(testDomainName), 23 | }, 24 | { 25 | Config: testAccDomainsDomainV1DataSourceBasic(testDomainName), 26 | Check: resource.ComposeTestCheckFunc( 27 | testAccDomainsDomainV1DataSourceID("data.selectel_domains_domain_v1.domain_tf_acc_test_1"), 28 | resource.TestCheckResourceAttr("data.selectel_domains_domain_v1.domain_tf_acc_test_1", "name", testDomainName), 29 | ), 30 | }, 31 | }, 32 | }) 33 | } 34 | 35 | func testAccDomainsDomainV1DataSourceID(name string) resource.TestCheckFunc { 36 | return func(s *terraform.State) error { 37 | rs, ok := s.RootModule().Resources[name] 38 | if !ok { 39 | return fmt.Errorf("can't find domain data source: %s", name) 40 | } 41 | 42 | if rs.Primary.ID == "" { 43 | return errors.New("domain data source ID not set") 44 | } 45 | 46 | return nil 47 | } 48 | } 49 | 50 | func testAccDomainsDomainV1DataSourceBasic(name string) string { 51 | return fmt.Sprintf(` 52 | %s 53 | 54 | data "selectel_domains_domain_v1" "domain_tf_acc_test_1" { 55 | name = "${selectel_domains_domain_v1.domain_tf_acc_test_1.name}" 56 | } 57 | `, testAccDomainsDomainV1Basic(name)) 58 | } 59 | -------------------------------------------------------------------------------- /selectel/waiters/dbaas/user.go: -------------------------------------------------------------------------------- 1 | package waiters 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "net/http" 8 | "strconv" 9 | "time" 10 | 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 12 | "github.com/selectel/dbaas-go" 13 | ) 14 | 15 | func WaitForDBaaSUserV1ActiveState( 16 | ctx context.Context, client *dbaas.API, userID string, timeout time.Duration, 17 | ) error { 18 | pending := []string{ 19 | string(dbaas.StatusPendingCreate), 20 | string(dbaas.StatusPendingUpdate), 21 | } 22 | target := []string{ 23 | string(dbaas.StatusActive), 24 | } 25 | 26 | stateConf := &resource.StateChangeConf{ 27 | Pending: pending, 28 | Target: target, 29 | Refresh: dbaasUserV1StateRefreshFunc(ctx, client, userID), 30 | Timeout: timeout, 31 | Delay: 10 * time.Second, 32 | MinTimeout: 10 * time.Second, 33 | } 34 | 35 | _, err := stateConf.WaitForStateContext(ctx) 36 | if err != nil { 37 | return fmt.Errorf( 38 | "error waiting for the user %s to become 'ACTIVE': %s", 39 | userID, err) 40 | } 41 | 42 | return nil 43 | } 44 | 45 | func DBaaSUserV1DeleteStateRefreshFunc(ctx context.Context, client *dbaas.API, userID string) resource.StateRefreshFunc { 46 | return func() (interface{}, string, error) { 47 | d, err := client.User(ctx, userID) 48 | if err != nil { 49 | var dbaasError *dbaas.DBaaSAPIError 50 | if errors.As(err, &dbaasError) { 51 | return d, strconv.Itoa(dbaasError.StatusCode()), nil 52 | } 53 | 54 | return nil, "", err 55 | } 56 | 57 | return d, strconv.Itoa(http.StatusOK), err 58 | } 59 | } 60 | 61 | func dbaasUserV1StateRefreshFunc(ctx context.Context, client *dbaas.API, userID string) resource.StateRefreshFunc { 62 | return func() (interface{}, string, error) { 63 | d, err := client.User(ctx, userID) 64 | if err != nil { 65 | return nil, "", err 66 | } 67 | 68 | return d, string(d.Status), nil 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /selectel/data_source_selectel_domains_zone_v2.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "context" 5 | "log" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 9 | ) 10 | 11 | func dataSourceDomainsZoneV2() *schema.Resource { 12 | return &schema.Resource{ 13 | ReadContext: dataSourceDomainsZoneV2Read, 14 | Schema: map[string]*schema.Schema{ 15 | "name": { 16 | Type: schema.TypeString, 17 | Required: true, 18 | }, 19 | "project_id": { 20 | Type: schema.TypeString, 21 | Required: true, 22 | }, 23 | "comment": { 24 | Type: schema.TypeString, 25 | Computed: true, 26 | }, 27 | "created_at": { 28 | Type: schema.TypeString, 29 | Computed: true, 30 | }, 31 | "updated_at": { 32 | Type: schema.TypeString, 33 | Computed: true, 34 | }, 35 | "delegation_checked_at": { 36 | Type: schema.TypeString, 37 | Computed: true, 38 | }, 39 | "last_check_status": { 40 | Type: schema.TypeBool, 41 | Computed: true, 42 | }, 43 | "last_delegated_at": { 44 | Type: schema.TypeString, 45 | Computed: true, 46 | }, 47 | "disabled": { 48 | Type: schema.TypeBool, 49 | Computed: true, 50 | }, 51 | }, 52 | } 53 | } 54 | 55 | func dataSourceDomainsZoneV2Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 56 | client, err := getDomainsV2Client(d, meta) 57 | if err != nil { 58 | return diag.FromErr(err) 59 | } 60 | 61 | zoneName := d.Get("name").(string) 62 | 63 | log.Println(msgGet(objectZone, zoneName)) 64 | 65 | zone, err := getZoneByName(ctx, client, zoneName) 66 | if err != nil { 67 | return diag.FromErr(err) 68 | } 69 | 70 | err = setZoneToResourceData(d, zone) 71 | if err != nil { 72 | return diag.FromErr(errGettingObject(objectZone, zoneName, err)) 73 | } 74 | 75 | return nil 76 | } 77 | -------------------------------------------------------------------------------- /selectel/waiters/dbaas/topic.go: -------------------------------------------------------------------------------- 1 | package waiters 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "net/http" 8 | "strconv" 9 | "time" 10 | 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 12 | "github.com/selectel/dbaas-go" 13 | ) 14 | 15 | func WaitForDBaaSTopicV1ActiveState( 16 | ctx context.Context, client *dbaas.API, topicID string, timeout time.Duration, 17 | ) error { 18 | pending := []string{ 19 | string(dbaas.StatusPendingCreate), 20 | string(dbaas.StatusPendingUpdate), 21 | } 22 | target := []string{ 23 | string(dbaas.StatusActive), 24 | } 25 | 26 | stateConf := &resource.StateChangeConf{ 27 | Pending: pending, 28 | Target: target, 29 | Refresh: dbaasTopicV1StateRefreshFunc(ctx, client, topicID), 30 | Timeout: timeout, 31 | Delay: 10 * time.Second, 32 | MinTimeout: 20 * time.Second, 33 | } 34 | 35 | _, err := stateConf.WaitForStateContext(ctx) 36 | if err != nil { 37 | return fmt.Errorf( 38 | "error waiting for the topic %s to become 'ACTIVE': %s", 39 | topicID, err) 40 | } 41 | 42 | return nil 43 | } 44 | 45 | func DBaaSTopicV1DeleteStateRefreshFunc(ctx context.Context, client *dbaas.API, topicID string) resource.StateRefreshFunc { 46 | return func() (interface{}, string, error) { 47 | d, err := client.Topic(ctx, topicID) 48 | if err != nil { 49 | var dbaasError *dbaas.DBaaSAPIError 50 | if errors.As(err, &dbaasError) { 51 | return d, strconv.Itoa(dbaasError.StatusCode()), nil 52 | } 53 | 54 | return nil, "", err 55 | } 56 | 57 | return d, strconv.Itoa(http.StatusOK), err 58 | } 59 | } 60 | 61 | func dbaasTopicV1StateRefreshFunc(ctx context.Context, client *dbaas.API, topicID string) resource.StateRefreshFunc { 62 | return func() (interface{}, string, error) { 63 | d, err := client.Topic(ctx, topicID) 64 | if err != nil { 65 | return nil, "", err 66 | } 67 | 68 | return d, string(d.Status), nil 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /selectel/waiters/dbaas/extension.go: -------------------------------------------------------------------------------- 1 | package waiters 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "strconv" 8 | "time" 9 | 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 11 | "github.com/selectel/dbaas-go" 12 | ) 13 | 14 | func WaitForDBaaSExtensionV1ActiveState( 15 | ctx context.Context, client *dbaas.API, extensionID string, timeout time.Duration, 16 | ) error { 17 | pending := []string{ 18 | string(dbaas.StatusPendingCreate), 19 | string(dbaas.StatusPendingUpdate), 20 | } 21 | target := []string{ 22 | string(dbaas.StatusActive), 23 | } 24 | 25 | stateConf := &resource.StateChangeConf{ 26 | Pending: pending, 27 | Target: target, 28 | Refresh: dbaasExtensionV1StateRefreshFunc(ctx, client, extensionID), 29 | Timeout: timeout, 30 | Delay: 10 * time.Second, 31 | MinTimeout: 15 * time.Second, 32 | } 33 | 34 | _, err := stateConf.WaitForStateContext(ctx) 35 | if err != nil { 36 | return fmt.Errorf( 37 | "error waiting for the extension %s to become 'ACTIVE': %s", 38 | extensionID, err) 39 | } 40 | 41 | return nil 42 | } 43 | 44 | func DBaaSExtensionV1DeleteStateRefreshFunc(ctx context.Context, client *dbaas.API, extensionID string) resource.StateRefreshFunc { 45 | return func() (interface{}, string, error) { 46 | d, err := client.Extension(ctx, extensionID) 47 | if err != nil { 48 | var dbaasError *dbaas.DBaaSAPIError 49 | if errors.As(err, &dbaasError) { 50 | return d, strconv.Itoa(dbaasError.StatusCode()), nil 51 | } 52 | 53 | return nil, "", err 54 | } 55 | 56 | return d, strconv.Itoa(200), err 57 | } 58 | } 59 | 60 | func dbaasExtensionV1StateRefreshFunc(ctx context.Context, client *dbaas.API, extensionID string) resource.StateRefreshFunc { 61 | return func() (interface{}, string, error) { 62 | d, err := client.Extension(ctx, extensionID) 63 | if err != nil { 64 | return nil, "", err 65 | } 66 | 67 | return d, string(d.Status), nil 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Hi there, 2 | 3 | Thank you for opening an issue. Please note that we try to keep the Terraform issue tracker reserved for bug reports and feature requests. For general usage questions, please see: https://www.terraform.io/community.html. 4 | 5 | ### Terraform Version 6 | Run `terraform -v` to show the version. If you are not running the latest version of Terraform, please upgrade because your issue may have already been fixed. 7 | 8 | ### Affected Resource(s) 9 | Please list the resources as a list, for example: 10 | - selectel_vpc_project_v2 11 | - selectel_vpc_floatingip_v2 12 | 13 | If this issue appears to affect multiple resources, it may be an issue with Terraform's core, so please mention this. 14 | 15 | ### Terraform Configuration Files 16 | ```hcl 17 | # Copy-paste your Terraform configurations here - for large Terraform configs, 18 | # please use a service like Dropbox and share a link to the ZIP file. For 19 | # security, you can also encrypt the files using our GPG public key. 20 | ``` 21 | 22 | ### Debug Output 23 | Please provider a link to a GitHub Gist containing the complete debug output: https://www.terraform.io/docs/internals/debugging.html. Please do NOT paste the debug output in the issue; just paste a link to the Gist. 24 | 25 | ### Panic Output 26 | If Terraform produced a panic, please provide a link to a GitHub Gist containing the output of the `crash.log`. 27 | 28 | ### Expected Behavior 29 | What should have happened? 30 | 31 | ### Actual Behavior 32 | What actually happened? 33 | 34 | ### Steps to Reproduce 35 | Please list the steps required to reproduce the issue, for example: 36 | 1. `terraform apply` 37 | 38 | ### Important Factoids 39 | Are there anything atypical about your accounts that we should know? For example: Running in EC2 Classic? Custom version of OpenStack? Tight ACLs? 40 | 41 | ### References 42 | Are there any other GitHub issues (open or closed) or Pull Requests that should be linked here? For example: 43 | - GH-1234 44 | -------------------------------------------------------------------------------- /selectel/waiters/dbaas/database.go: -------------------------------------------------------------------------------- 1 | package waiters 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "net/http" 8 | "strconv" 9 | "time" 10 | 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 12 | "github.com/selectel/dbaas-go" 13 | ) 14 | 15 | func WaitForDBaaSDatabaseV1ActiveState( 16 | ctx context.Context, client *dbaas.API, databaseID string, timeout time.Duration, 17 | ) error { 18 | pending := []string{ 19 | string(dbaas.StatusPendingCreate), 20 | string(dbaas.StatusPendingUpdate), 21 | } 22 | target := []string{ 23 | string(dbaas.StatusActive), 24 | } 25 | 26 | stateConf := &resource.StateChangeConf{ 27 | Pending: pending, 28 | Target: target, 29 | Refresh: dbaasDatabaseV1StateRefreshFunc(ctx, client, databaseID), 30 | Timeout: timeout, 31 | Delay: 10 * time.Second, 32 | MinTimeout: 10 * time.Second, 33 | } 34 | 35 | _, err := stateConf.WaitForStateContext(ctx) 36 | if err != nil { 37 | return fmt.Errorf( 38 | "error waiting for the database %s to become 'ACTIVE': %s", 39 | databaseID, err) 40 | } 41 | 42 | return nil 43 | } 44 | 45 | func DBaaSDatabaseV1DeleteStateRefreshFunc(ctx context.Context, client *dbaas.API, datastoreID string) resource.StateRefreshFunc { 46 | return func() (interface{}, string, error) { 47 | d, err := client.Database(ctx, datastoreID) 48 | if err != nil { 49 | var dbaasError *dbaas.DBaaSAPIError 50 | if errors.As(err, &dbaasError) { 51 | return d, strconv.Itoa(dbaasError.StatusCode()), nil 52 | } 53 | 54 | return nil, "", err 55 | } 56 | 57 | return d, strconv.Itoa(http.StatusOK), err 58 | } 59 | } 60 | 61 | func dbaasDatabaseV1StateRefreshFunc(ctx context.Context, client *dbaas.API, databaseID string) resource.StateRefreshFunc { 62 | return func() (interface{}, string, error) { 63 | d, err := client.Database(ctx, databaseID) 64 | if err != nil { 65 | return nil, "", err 66 | } 67 | 68 | return d, string(d.Status), nil 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /selectel/dbaas_redis_utils.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "context" 5 | "log" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 8 | "github.com/selectel/dbaas-go" 9 | waiters "github.com/terraform-providers/terraform-provider-selectel/selectel/waiters/dbaas" 10 | ) 11 | 12 | func updateRedisDatastorePassword(ctx context.Context, d *schema.ResourceData, client *dbaas.API) error { 13 | passwordOpts := dbaas.DatastorePasswordOpts{ 14 | RedisPassword: d.Get("redis_password").(string), 15 | } 16 | 17 | log.Print(msgUpdate(objectDatastore, d.Id(), passwordOpts)) 18 | _, err := client.PasswordDatastore(ctx, d.Id(), passwordOpts) 19 | if err != nil { 20 | return errUpdatingObject(objectDatastore, d.Id(), err) 21 | } 22 | 23 | log.Printf("[DEBUG] waiting for datastore %s to become 'ACTIVE'", d.Id()) 24 | timeout := d.Timeout(schema.TimeoutUpdate) 25 | err = waiters.WaitForDBaaSDatastoreV1ActiveState(ctx, client, d.Id(), timeout) 26 | if err != nil { 27 | return errUpdatingObject(objectDatastore, d.Id(), err) 28 | } 29 | 30 | return nil 31 | } 32 | 33 | func resizeRedisDatastore(ctx context.Context, d *schema.ResourceData, client *dbaas.API) error { 34 | var resizeOpts dbaas.DatastoreResizeOpts 35 | nodeCount := d.Get("node_count").(int) 36 | resizeOpts.NodeCount = nodeCount 37 | 38 | flavorID := d.Get("flavor_id") 39 | 40 | resizeOpts.Flavor = nil 41 | resizeOpts.FlavorID = flavorID.(string) 42 | 43 | log.Print(msgUpdate(objectDatastore, d.Id(), resizeOpts)) 44 | _, err := client.ResizeDatastore(ctx, d.Id(), resizeOpts) 45 | if err != nil { 46 | return errUpdatingObject(objectDatastore, d.Id(), err) 47 | } 48 | 49 | log.Printf("[DEBUG] waiting for datastore %s to become 'ACTIVE'", d.Id()) 50 | timeout := d.Timeout(schema.TimeoutCreate) 51 | err = waiters.WaitForDBaaSDatastoreV1ActiveState(ctx, client, d.Id(), timeout) 52 | if err != nil { 53 | return errUpdatingObject(objectDatastore, d.Id(), err) 54 | } 55 | 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /selectel/waiters/dbaas/datastore.go: -------------------------------------------------------------------------------- 1 | package waiters 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "net/http" 8 | "strconv" 9 | "time" 10 | 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 12 | "github.com/selectel/dbaas-go" 13 | ) 14 | 15 | func WaitForDBaaSDatastoreV1ActiveState( 16 | ctx context.Context, client *dbaas.API, datastoreID string, timeout time.Duration, 17 | ) error { 18 | pending := []string{ 19 | string(dbaas.StatusPendingCreate), 20 | string(dbaas.StatusPendingUpdate), 21 | string(dbaas.StatusResizing), 22 | } 23 | target := []string{ 24 | string(dbaas.StatusActive), 25 | } 26 | 27 | stateConf := &resource.StateChangeConf{ 28 | Pending: pending, 29 | Target: target, 30 | Refresh: dbaasDatastoreV1StateRefreshFunc(ctx, client, datastoreID), 31 | Timeout: timeout, 32 | Delay: 10 * time.Second, 33 | MinTimeout: 20 * time.Second, 34 | } 35 | 36 | _, err := stateConf.WaitForState() 37 | if err != nil { 38 | return fmt.Errorf( 39 | "error waiting for the datastore %s to become 'ACTIVE': %s", 40 | datastoreID, err) 41 | } 42 | 43 | return nil 44 | } 45 | 46 | func DBaaSDatastoreV1DeleteStateRefreshFunc(ctx context.Context, client *dbaas.API, datastoreID string) resource.StateRefreshFunc { 47 | return func() (interface{}, string, error) { 48 | d, err := client.Datastore(ctx, datastoreID) 49 | if err != nil { 50 | var dbaasError *dbaas.DBaaSAPIError 51 | if errors.As(err, &dbaasError) { 52 | return d, strconv.Itoa(dbaasError.StatusCode()), nil 53 | } 54 | 55 | return nil, "", err 56 | } 57 | 58 | return d, strconv.Itoa(http.StatusOK), err 59 | } 60 | } 61 | 62 | func dbaasDatastoreV1StateRefreshFunc(ctx context.Context, client *dbaas.API, datastoreID string) resource.StateRefreshFunc { 63 | return func() (interface{}, string, error) { 64 | d, err := client.Datastore(ctx, datastoreID) 65 | if err != nil { 66 | return nil, "", err 67 | } 68 | 69 | return d, string(d.Status), nil 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /selectel/waiters/dbaas/logical_replication_slot.go: -------------------------------------------------------------------------------- 1 | package waiters 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "net/http" 8 | "strconv" 9 | "time" 10 | 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 12 | "github.com/selectel/dbaas-go" 13 | ) 14 | 15 | func WaitForDBaaSLogicalReplicationSlotV1ActiveState( 16 | ctx context.Context, client *dbaas.API, slotID string, timeout time.Duration, 17 | ) error { 18 | pending := []string{ 19 | string(dbaas.StatusPendingCreate), 20 | string(dbaas.StatusPendingUpdate), 21 | } 22 | target := []string{ 23 | string(dbaas.StatusActive), 24 | } 25 | 26 | stateConf := &resource.StateChangeConf{ 27 | Pending: pending, 28 | Target: target, 29 | Refresh: dbaasLogicalReplicationSlotV1StateRefreshFunc(ctx, client, slotID), 30 | Timeout: timeout, 31 | Delay: 10 * time.Second, 32 | MinTimeout: 15 * time.Second, 33 | } 34 | 35 | _, err := stateConf.WaitForStateContext(ctx) 36 | if err != nil { 37 | return fmt.Errorf( 38 | "error waiting for the slot %s to become 'ACTIVE': %s", 39 | slotID, err) 40 | } 41 | 42 | return nil 43 | } 44 | 45 | func DBaaSLogicalReplicationSlotV1DeleteStateRefreshFunc(ctx context.Context, client *dbaas.API, slotID string) resource.StateRefreshFunc { 46 | return func() (interface{}, string, error) { 47 | d, err := client.LogicalReplicationSlot(ctx, slotID) 48 | if err != nil { 49 | var dbaasError *dbaas.DBaaSAPIError 50 | if errors.As(err, &dbaasError) { 51 | return d, strconv.Itoa(dbaasError.StatusCode()), nil 52 | } 53 | 54 | return nil, "", err 55 | } 56 | 57 | return d, strconv.Itoa(http.StatusOK), err 58 | } 59 | } 60 | 61 | func dbaasLogicalReplicationSlotV1StateRefreshFunc(ctx context.Context, client *dbaas.API, slotID string) resource.StateRefreshFunc { 62 | return func() (interface{}, string, error) { 63 | d, err := client.LogicalReplicationSlot(ctx, slotID) 64 | if err != nil { 65 | return nil, "", err 66 | } 67 | 68 | return d, string(d.Status), nil 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /selectel/import_selectel_dbaas_mysql_datastore_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 8 | ) 9 | 10 | func TestAccDBaaSMySQLDatastoreV1ImportBasic(t *testing.T) { 11 | resourceName := "selectel_dbaas_mysql_datastore_v1.datastore_tf_acc_test_1" 12 | projectName := acctest.RandomWithPrefix("tf-acc") 13 | datastoreName := acctest.RandomWithPrefix("tf-acc-ds") 14 | nodeCount := 1 15 | datastoreTypeEngine := mySQLDatastoreType 16 | 17 | resource.Test(t, resource.TestCase{ 18 | PreCheck: func() { testAccSelectelPreCheck(t) }, 19 | ProviderFactories: testAccProviders, 20 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 21 | Steps: []resource.TestStep{ 22 | { 23 | Config: testAccDBaaSMySQLDatastoreV1Basic(projectName, datastoreName, datastoreTypeEngine, nodeCount), 24 | Check: testAccCheckSelectelImportEnv(resourceName), 25 | }, 26 | { 27 | ResourceName: resourceName, 28 | ImportState: true, 29 | ImportStateVerify: true, 30 | }, 31 | }, 32 | }) 33 | } 34 | 35 | func TestAccDBaaSMySQLNativeDatastoreV1ImportBasic(t *testing.T) { 36 | resourceName := "selectel_dbaas_mysql_datastore_v1.datastore_tf_acc_test_1" 37 | projectName := acctest.RandomWithPrefix("tf-acc") 38 | datastoreName := acctest.RandomWithPrefix("tf-acc-ds") 39 | nodeCount := 1 40 | datastoreTypeEngine := mySQLNativeDatastoreType 41 | 42 | resource.Test(t, resource.TestCase{ 43 | PreCheck: func() { testAccSelectelPreCheck(t) }, 44 | ProviderFactories: testAccProviders, 45 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 46 | Steps: []resource.TestStep{ 47 | { 48 | Config: testAccDBaaSMySQLDatastoreV1Basic(projectName, datastoreName, datastoreTypeEngine, nodeCount), 49 | Check: testAccCheckSelectelImportEnv(resourceName), 50 | }, 51 | { 52 | ResourceName: resourceName, 53 | ImportState: true, 54 | ImportStateVerify: true, 55 | }, 56 | }, 57 | }) 58 | } 59 | -------------------------------------------------------------------------------- /website/docs/d/dbaas_available_extension_v1.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "selectel" 3 | page_title: "Selectel: selectel_dbaas_available_extension_v1" 4 | sidebar_current: "docs-selectel-datasource-dbaas-available-extension-v1" 5 | description: |- 6 | Provides a list of extensions available for Selectel Managed Databases. 7 | --- 8 | 9 | # selectel\_dbaas\_available_extension_v1 10 | 11 | Provides a list of extensions available for Managed Databases. Applicable to PostgreSQL and PostgreSQL TimescaleDB. For more information about extensions, see the official Selectel documentation for [PostgreSQL](https://docs.selectel.ru/en/cloud/managed-databases/postgresql/add-extensions/) and [PostgreSQL TimescaleDB](https://docs.selectel.ru/en/cloud/managed-databases/timescaledb/add-extensions/). 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "selectel_dbaas_available_extension_v1" "available_extension_1" { 17 | project_id = selectel_vpc_project_v2.project_1.id 18 | region = "ru-3" 19 | } 20 | ``` 21 | 22 | ## Argument Reference 23 | 24 | * `project_id` - (Required) Unique identifier of the associated project. Retrieved from the [selectel_vpc_project_v2](https://registry.terraform.io/providers/selectel/selectel/latest/docs/resources/vpc_project_v2) resource. Learn more about [Projects](https://docs.selectel.ru/en/control-panel-actions/projects/about-projects/). 25 | 26 | * `region` - (Required) Pool where the database is located, for example, `ru-3`. Learn more about available pools in the [Availability matrix](https://docs.selectel.ru/en/control-panel-actions/availability-matrix/#managed-databases). 27 | 28 | * `filter` - (Optional) Values to filter available extensions. 29 | 30 | * `name` - (Optional) Name of the extension to search. 31 | 32 | ## Attributes Reference 33 | 34 | * `available_extensions` - List of the available extensions: 35 | 36 | * `id` - Unique identifier of the extension. 37 | 38 | * `name` - Extension name. 39 | 40 | * `datastore_type_ids` - List of cluster types that support the extension. 41 | 42 | * `dependency_ids` - List of extensions that depend on this extension. 43 | -------------------------------------------------------------------------------- /selectel/internal/reflect/map_test.go: -------------------------------------------------------------------------------- 1 | package reflect 2 | 3 | import ( 4 | "encoding/json" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func jsonToMap(t *testing.T, s string) map[string]interface{} { 11 | var m map[string]interface{} 12 | err := json.Unmarshal([]byte(s), &m) 13 | require.NoError(t, err) 14 | 15 | return m 16 | } 17 | 18 | func TestIsSetContainsSubset(t *testing.T) { 19 | tests := []struct { 20 | name string 21 | set string 22 | subset string 23 | want bool 24 | }{ 25 | { 26 | name: "SimpleMatch", 27 | set: `{"a": 1, "b": 2}`, 28 | subset: `{"a": 1}`, 29 | want: true, 30 | }, 31 | { 32 | name: "KeyNotFound", 33 | set: `{"a": 1}`, 34 | subset: `{"b": 2}`, 35 | want: false, 36 | }, 37 | { 38 | name: "NestedObjects", 39 | set: `{"a": {"b": 2, "c": 3}}`, 40 | subset: `{"a": {"b": 2}}`, 41 | want: true, 42 | }, 43 | { 44 | name: "Arrays", 45 | set: `{"arr": [1, 2, 3]}`, 46 | subset: `{"arr": [2, 3]}`, 47 | want: true, 48 | }, 49 | { 50 | name: "ArraysWithObjects", 51 | set: `{"arr": [{"a": 1, "b": 2}, {"a": 2}]}`, 52 | subset: `{"arr": [{"a": 1}]}`, 53 | want: true, 54 | }, 55 | { 56 | name: "ValueMismatch", 57 | set: `{"a": 1}`, 58 | subset: `{"a": 2}`, 59 | want: false, 60 | }, 61 | { 62 | name: "NestedArrays", 63 | set: `{"a": [[1,2],[3,4]]}`, 64 | subset: `{"a": [[1]]}`, 65 | want: true, 66 | }, 67 | { 68 | name: "EmptySubset", 69 | set: `{"a": 1}`, 70 | subset: `{}`, 71 | want: true, 72 | }, 73 | { 74 | name: "EmptySet", 75 | set: `{}`, 76 | subset: `{"a": 1}`, 77 | want: false, 78 | }, 79 | } 80 | 81 | for _, tt := range tests { 82 | t.Run(tt.name, func(t *testing.T) { 83 | set := jsonToMap(t, tt.set) 84 | subset := jsonToMap(t, tt.subset) 85 | got := IsSetContainsSubset(subset, set) 86 | if got != tt.want { 87 | t.Errorf("IsSetContainsSubset(%v, %v) = %v, want %v", tt.subset, tt.set, got, tt.want) 88 | } 89 | }) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /selectel/data_source_selectel_mks_kube_versions_v1.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 8 | "github.com/selectel/mks-go/pkg/v1/kubeversion" 9 | ) 10 | 11 | func dataSourceMKSKubeVersionsV1() *schema.Resource { 12 | return &schema.Resource{ 13 | ReadContext: dataSourceMKSKubeVersionsV1Read, 14 | Schema: map[string]*schema.Schema{ 15 | "project_id": { 16 | Type: schema.TypeString, 17 | Required: true, 18 | ForceNew: true, 19 | }, 20 | "region": { 21 | Type: schema.TypeString, 22 | Required: true, 23 | ForceNew: true, 24 | }, 25 | "latest_version": { 26 | Type: schema.TypeString, 27 | Computed: true, 28 | }, 29 | "default_version": { 30 | Type: schema.TypeString, 31 | Computed: true, 32 | }, 33 | "versions": { 34 | Type: schema.TypeList, 35 | Computed: true, 36 | Elem: &schema.Schema{ 37 | Type: schema.TypeString, 38 | }, 39 | }, 40 | }, 41 | } 42 | } 43 | 44 | func dataSourceMKSKubeVersionsV1Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 45 | mksClient, diagErr := getMKSClient(d, meta) 46 | if diagErr != nil { 47 | return diagErr 48 | } 49 | 50 | mksKubeVersions, _, err := kubeversion.List(ctx, mksClient) 51 | if err != nil { 52 | return diag.FromErr(errGettingObjects(objectKubeVersions, err)) 53 | } 54 | 55 | latestVersion, err := parseMKSKubeVersionsV1Latest(mksKubeVersions) 56 | if err != nil { 57 | return diag.FromErr(err) 58 | } 59 | defaultVersion := parseMKSKubeVersionsV1Default(mksKubeVersions) 60 | versions := flattenMKSKubeVersionsV1(mksKubeVersions) 61 | if err := d.Set("versions", versions); err != nil { 62 | return diag.FromErr(err) 63 | } 64 | 65 | checksum, err := stringListChecksum(versions) 66 | if err != nil { 67 | return diag.FromErr(err) 68 | } 69 | 70 | d.Set("latest_version", latestVersion) 71 | d.Set("default_version", defaultVersion) 72 | d.SetId(checksum) 73 | 74 | return nil 75 | } 76 | -------------------------------------------------------------------------------- /selectel/schema_selectel_dbaas_postgresql_datastore_v1.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 6 | ) 7 | 8 | func resourceDBaaSPostgreSQLDatastoreV1Schema() map[string]*schema.Schema { 9 | datastoreSchema := resourceDBaaSDatastoreV1BaseSchema() 10 | datastoreSchema["backup_retention_days"] = &schema.Schema{ 11 | Type: schema.TypeInt, 12 | Optional: true, 13 | Description: "Number of days to retain backups.", 14 | Default: 7, 15 | } 16 | datastoreSchema["pooler"] = &schema.Schema{ 17 | Type: schema.TypeSet, 18 | Optional: true, 19 | Elem: &schema.Resource{ 20 | Schema: map[string]*schema.Schema{ 21 | "mode": { 22 | Type: schema.TypeString, 23 | Required: true, 24 | ValidateFunc: validation.StringInSlice([]string{ 25 | "session", 26 | "transaction", 27 | "statement", 28 | }, false), 29 | }, 30 | "size": { 31 | Type: schema.TypeInt, 32 | Required: true, 33 | }, 34 | }, 35 | }, 36 | } 37 | datastoreSchema["restore"] = &schema.Schema{ 38 | Type: schema.TypeSet, 39 | Optional: true, 40 | ForceNew: true, 41 | Elem: &schema.Resource{ 42 | Schema: map[string]*schema.Schema{ 43 | "datastore_id": { 44 | Type: schema.TypeString, 45 | Optional: true, 46 | }, 47 | "target_time": { 48 | Type: schema.TypeString, 49 | Optional: true, 50 | }, 51 | }, 52 | }, 53 | } 54 | datastoreSchema["floating_ips"] = &schema.Schema{ 55 | Type: schema.TypeSet, 56 | Optional: true, 57 | Elem: &schema.Resource{ 58 | Schema: map[string]*schema.Schema{ 59 | "master": { 60 | Type: schema.TypeInt, 61 | Required: true, 62 | }, 63 | "replica": { 64 | Type: schema.TypeInt, 65 | Required: true, 66 | }, 67 | }, 68 | }, 69 | } 70 | datastoreSchema["logs"] = &schema.Schema{ 71 | Type: schema.TypeString, 72 | Optional: true, 73 | Description: "Name of Logs group.", 74 | } 75 | 76 | return datastoreSchema 77 | } 78 | -------------------------------------------------------------------------------- /selectel/data_source_selectel_mks_kube_versions_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "testing" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 11 | ) 12 | 13 | func TestAccMKSKubeVersionsV1DataSourceBasic(t *testing.T) { 14 | projectName := acctest.RandomWithPrefix("tf-acc") 15 | resource.Test(t, resource.TestCase{ 16 | PreCheck: func() { testAccSelectelPreCheck(t) }, 17 | ProviderFactories: testAccProviders, 18 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 19 | Steps: []resource.TestStep{ 20 | { 21 | Config: testAccMKSKubeVersionsV1Basic(projectName), 22 | Check: resource.ComposeTestCheckFunc( 23 | testAccCheckMKSKubeVersionsV1("data.selectel_mks_kube_versions_v1.kube_versions_tf_acc_test_1"), 24 | ), 25 | }, 26 | }, 27 | }) 28 | } 29 | 30 | func testAccCheckMKSKubeVersionsV1(name string) resource.TestCheckFunc { 31 | return func(s *terraform.State) error { 32 | rs, ok := s.RootModule().Resources[name] 33 | if !ok { 34 | return fmt.Errorf("can't find kube versions data source: %s", name) 35 | } 36 | if _, ok := rs.Primary.Attributes["latest_version"]; !ok { 37 | return errors.New("empty 'latest_version' field in kube versions data source") 38 | } 39 | if _, ok := rs.Primary.Attributes["default_version"]; !ok { 40 | return errors.New("empty 'default_version' field in kube versions data source") 41 | } 42 | if _, ok := rs.Primary.Attributes["versions.#"]; !ok { 43 | return errors.New("empty 'versions' field in kube versions data source") 44 | } 45 | 46 | return nil 47 | } 48 | } 49 | 50 | func testAccMKSKubeVersionsV1Basic(projectName string) string { 51 | return fmt.Sprintf(` 52 | resource "selectel_vpc_project_v2" "project_tf_acc_test_1" { 53 | name = "%s" 54 | } 55 | 56 | data "selectel_mks_kube_versions_v1" "kube_versions_tf_acc_test_1" { 57 | project_id = "${selectel_vpc_project_v2.project_tf_acc_test_1.id}" 58 | region = "ru-3" 59 | } 60 | `, projectName) 61 | } 62 | -------------------------------------------------------------------------------- /website/docs/guides/upgrading_to_version_4.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "selectel" 3 | page_title: "Upgrading Terraform Selectel Provider to version 4.0.0" 4 | sidebar_current: "docs-selectel-guide-upgrade-guide" 5 | description: |- 6 | How to upgrade Terraform Selectel Provider to version 4.0.0. 7 | --- 8 | 9 | # Upgrading Terraform Selectel Provider to version 4.0.0 10 | 11 | To upgrade Terraform Selectel Provider version to the new major version 4.0.0: 12 | 13 | 1. In the [Control Panel](https://my.selectel.ru/iam/users_management/users?type=service), create a service user with an Account Administrator role. Learn more [how to create a service user](https://docs.selectel.ru/en/control-panel-actions/users-and-roles/add-user/). 14 | 2. Change the authorization block. 15 | 16 | From: 17 | 18 | ```hcl 19 | provider "selectel" { 20 | token = 21 | } 22 | ``` 23 | 24 | To: 25 | 26 | ```hcl 27 | provider "selectel" { 28 | domain_name = 29 | username = 30 | password = 31 | } 32 | ``` 33 | 34 | where: 35 | 36 | * `` - (Required) Selectel account ID. The account ID is in the top right corner of the [Control panel](https://my.selectel.ru/). For import, use the value in the `OS_DOMAIN_NAME` environment variable. Learn more about [Registration](https://docs.selectel.ru/en/control-panel-actions/account/registration/). 37 | 38 | * `` - (Required) Name of the service user. To get the name, in the [Control panel](https://my.selectel.ru/iam/users_management/users?type=service), go to **Identity & Access Management** ⟶ **User management** ⟶ the **Service users** tab ⟶ copy the name of the required user. For import, use the value in the `OS_USERNAME` environment variable. Learn more about [Service users](https://docs.selectel.ru/en/control-panel-actions/users-and-roles/user-types-and-roles/) and [how to create service user](https://docs.selectel.ru/en/control-panel-actions/users-and-roles/add-user/#add-service-user). 39 | 40 | * `` - (Required, Sensitive) Password of the service user. For import, use the value in the `OS_PASSWORD` environment variable. -------------------------------------------------------------------------------- /selectel/import_selectel_mks_cluster_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 9 | ) 10 | 11 | func TestAccMKSClusterV1ImportBasic(t *testing.T) { 12 | resourceName := "selectel_mks_cluster_v1.cluster_tf_acc_test_1" 13 | projectName := acctest.RandomWithPrefix("tf-acc") 14 | clusterName := acctest.RandomWithPrefix("tf-acc-cl") 15 | kubeVersion := testAccMKSClusterV1GetDefaultKubeVersion(t) 16 | maintenanceWindowStart := testAccMKSClusterV1GetMaintenanceWindowStart(12 * time.Hour) 17 | 18 | resource.Test(t, resource.TestCase{ 19 | PreCheck: func() { testAccSelectelPreCheck(t) }, 20 | ProviderFactories: testAccProviders, 21 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 22 | Steps: []resource.TestStep{ 23 | { 24 | Config: testAccMKSClusterV1Basic(projectName, clusterName, kubeVersion, maintenanceWindowStart), 25 | Check: testAccCheckSelectelImportEnv(resourceName), 26 | }, 27 | { 28 | ResourceName: resourceName, 29 | ImportState: true, 30 | ImportStateVerify: true, 31 | }, 32 | }, 33 | }) 34 | } 35 | 36 | func TestAccMKSClusterV1ImportZonal(t *testing.T) { 37 | resourceName := "selectel_mks_cluster_v1.cluster_tf_acc_test_1" 38 | projectName := acctest.RandomWithPrefix("tf-acc") 39 | clusterName := acctest.RandomWithPrefix("tf-acc-cl") 40 | kubeVersion := testAccMKSClusterV1GetDefaultKubeVersion(t) 41 | maintenanceWindowStart := testAccMKSClusterV1GetMaintenanceWindowStart(12 * time.Hour) 42 | 43 | resource.Test(t, resource.TestCase{ 44 | PreCheck: func() { testAccSelectelPreCheck(t) }, 45 | ProviderFactories: testAccProviders, 46 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 47 | Steps: []resource.TestStep{ 48 | { 49 | Config: testAccMKSClusterV1Zonal(projectName, clusterName, kubeVersion, maintenanceWindowStart), 50 | Check: testAccCheckSelectelImportEnv(resourceName), 51 | }, 52 | { 53 | ResourceName: resourceName, 54 | ImportState: true, 55 | ImportStateVerify: true, 56 | }, 57 | }, 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /selectel/schema_selectel_dbaas_redis_datastore_v1.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 4 | 5 | func resourceDBaaSRedisDatastoreV1Schema() map[string]*schema.Schema { 6 | datastoreSchema := resourceDBaaSDatastoreV1BaseSchema() 7 | datastoreSchema["backup_retention_days"] = &schema.Schema{ 8 | Type: schema.TypeInt, 9 | Optional: true, 10 | Description: "Number of days to retain backups.", 11 | Default: 7, 12 | } 13 | datastoreSchema["restore"] = &schema.Schema{ 14 | Type: schema.TypeSet, 15 | Optional: true, 16 | ForceNew: true, 17 | Elem: &schema.Resource{ 18 | Schema: map[string]*schema.Schema{ 19 | "datastore_id": { 20 | Type: schema.TypeString, 21 | Optional: true, 22 | }, 23 | "target_time": { 24 | Type: schema.TypeString, 25 | Optional: true, 26 | }, 27 | }, 28 | }, 29 | } 30 | datastoreSchema["flavor"] = &schema.Schema{ 31 | Type: schema.TypeSet, 32 | Computed: true, 33 | Elem: &schema.Resource{ 34 | Schema: map[string]*schema.Schema{ 35 | "vcpus": { 36 | Type: schema.TypeInt, 37 | Computed: true, 38 | }, 39 | "ram": { 40 | Type: schema.TypeInt, 41 | Computed: true, 42 | }, 43 | "disk": { 44 | Type: schema.TypeInt, 45 | Computed: true, 46 | }, 47 | }, 48 | }, 49 | } 50 | datastoreSchema["flavor_id"] = &schema.Schema{ 51 | Type: schema.TypeString, 52 | Required: true, 53 | } 54 | datastoreSchema["redis_password"] = &schema.Schema{ 55 | Type: schema.TypeString, 56 | Optional: true, 57 | Sensitive: true, 58 | } 59 | datastoreSchema["floating_ips"] = &schema.Schema{ 60 | Type: schema.TypeSet, 61 | Optional: true, 62 | Elem: &schema.Resource{ 63 | Schema: map[string]*schema.Schema{ 64 | "master": { 65 | Type: schema.TypeInt, 66 | Required: true, 67 | }, 68 | "replica": { 69 | Type: schema.TypeInt, 70 | Required: true, 71 | }, 72 | }, 73 | }, 74 | } 75 | datastoreSchema["logs"] = &schema.Schema{ 76 | Type: schema.TypeString, 77 | Optional: true, 78 | Description: "Name of Logs group.", 79 | } 80 | 81 | return datastoreSchema 82 | } 83 | -------------------------------------------------------------------------------- /selectel/schema_selectel_dbaas_datastore_v1.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 6 | ) 7 | 8 | func resourceDBaaSDatastoreV1Schema() map[string]*schema.Schema { 9 | datastoreSchema := resourceDBaaSDatastoreV1BaseSchema() 10 | datastoreSchema["backup_retention_days"] = &schema.Schema{ 11 | Type: schema.TypeInt, 12 | Optional: true, 13 | Description: "Number of days to retain backups.", 14 | Default: 7, 15 | } 16 | datastoreSchema["pooler"] = &schema.Schema{ 17 | Type: schema.TypeSet, 18 | Optional: true, 19 | Elem: &schema.Resource{ 20 | Schema: map[string]*schema.Schema{ 21 | "mode": { 22 | Type: schema.TypeString, 23 | Required: true, 24 | ValidateFunc: validation.StringInSlice([]string{ 25 | "session", 26 | "transaction", 27 | "statement", 28 | }, false), 29 | }, 30 | "size": { 31 | Type: schema.TypeInt, 32 | Required: true, 33 | }, 34 | }, 35 | }, 36 | } 37 | datastoreSchema["restore"] = &schema.Schema{ 38 | Type: schema.TypeSet, 39 | Optional: true, 40 | ForceNew: true, 41 | Elem: &schema.Resource{ 42 | Schema: map[string]*schema.Schema{ 43 | "datastore_id": { 44 | Type: schema.TypeString, 45 | Optional: true, 46 | }, 47 | "target_time": { 48 | Type: schema.TypeString, 49 | Optional: true, 50 | }, 51 | }, 52 | }, 53 | } 54 | datastoreSchema["redis_password"] = &schema.Schema{ 55 | Type: schema.TypeString, 56 | Optional: true, 57 | Sensitive: true, 58 | } 59 | datastoreSchema["floating_ips"] = &schema.Schema{ 60 | Type: schema.TypeSet, 61 | Optional: true, 62 | Elem: &schema.Resource{ 63 | Schema: map[string]*schema.Schema{ 64 | "master": { 65 | Type: schema.TypeInt, 66 | Required: true, 67 | }, 68 | "replica": { 69 | Type: schema.TypeInt, 70 | Required: true, 71 | }, 72 | }, 73 | }, 74 | } 75 | datastoreSchema["logs"] = &schema.Schema{ 76 | Type: schema.TypeString, 77 | Optional: true, 78 | Description: "Name of Logs group.", 79 | } 80 | 81 | return datastoreSchema 82 | } 83 | -------------------------------------------------------------------------------- /website/docs/d/dedicated_public_subnet_v1.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "selectel" 3 | page_title: "Selectel: selectel_dedicated_public_subnet_v1" 4 | sidebar_current: "docs-selectel-datasource-dedicated-public-subnet-v1" 5 | description: |- 6 | Provides a list of available public subnets. 7 | --- 8 | 9 | # selectel\_dedicated\_public\_subnet\_v1 10 | 11 | Provides a list of available additional public subnets. Learn more about [Additional public subnets](https://docs.selectel.ru/en/dedicated/networks/ip-addresses/#add-additional-ips) 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "selectel_dedicated_public_subnet_v1" "public_subnets" { 17 | project_id = selectel_vpc_project_v2.project_1.id 18 | filter { 19 | location_id = data.selectel_dedicated_location_v1.server_location.locations[0].id 20 | subnet = "192.168.1.0/29" 21 | ip = "192.168.1.3" 22 | } 23 | } 24 | ``` 25 | 26 | ## Argument Reference 27 | 28 | * `project_id` - (Required) Unique identifier of the associated project. Retrieved from the [selectel_vpc_project_v2](https://registry.terraform.io/providers/selectel/selectel/latest/docs/resources/vpc_project_v2) resource. Learn more about [Projects](https://docs.selectel.ru/en/control-panel-actions/projects/about-projects/). 29 | 30 | * `filter` - (Optional) Values to filter available subnets. 31 | 32 | * `ip` - (Optional) IP address to search included in a subnet. 33 | * `subnet` - (Optional) Subnet in CIDR notation to search. 34 | * `location_id` - (Optional) Unique identifier of the location. Retrieved from the [selectel_dedicated_location_v1](https://registry.terraform.io/providers/selectel/selectel/latest/docs/data-sources/dedicated_location_v1) data source. Learn more about available pools in the [Availability matrix](https://docs.selectel.ru/en/availability-matrix/#dedicated-servers). 35 | 36 | ## Attributes Reference 37 | 38 | * `subnets` - List of the available subnets: 39 | 40 | * `id` - Unique identifier of the subnet. 41 | * `network_id` - Unique identifier of the network. 42 | * `subnet` - Subnet in CIDR notation. 43 | * `broadcast` - Broadcast address. 44 | * `gateway` - Gateway address. 45 | * `reserved_vrrp_ips` - List of reserved VRRP IPs. 46 | * `ip` - IP address from the filter. Can be used to pass forward. 47 | -------------------------------------------------------------------------------- /selectel/data_source_selectel_domains_rrset_v2.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 10 | ) 11 | 12 | func dataSourceDomainsRRSetV2() *schema.Resource { 13 | return &schema.Resource{ 14 | ReadContext: dataSourceDomainsRRSetV2Read, 15 | Schema: map[string]*schema.Schema{ 16 | "name": { 17 | Type: schema.TypeString, 18 | Required: true, 19 | }, 20 | "type": { 21 | Type: schema.TypeString, 22 | Required: true, 23 | }, 24 | "zone_id": { 25 | Type: schema.TypeString, 26 | Required: true, 27 | }, 28 | "project_id": { 29 | Type: schema.TypeString, 30 | Required: true, 31 | }, 32 | "comment": { 33 | Type: schema.TypeString, 34 | Computed: true, 35 | }, 36 | "managed_by": { 37 | Type: schema.TypeString, 38 | Computed: true, 39 | }, 40 | "ttl": { 41 | Type: schema.TypeInt, 42 | Computed: true, 43 | }, 44 | "records": { 45 | Type: schema.TypeSet, 46 | Computed: true, 47 | Elem: &schema.Resource{ 48 | Schema: map[string]*schema.Schema{ 49 | "content": { 50 | Type: schema.TypeString, 51 | Computed: true, 52 | }, 53 | "disabled": { 54 | Type: schema.TypeBool, 55 | Computed: true, 56 | }, 57 | }, 58 | }, 59 | }, 60 | }, 61 | } 62 | } 63 | 64 | func dataSourceDomainsRRSetV2Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 65 | client, err := getDomainsV2Client(d, meta) 66 | if err != nil { 67 | return diag.FromErr(err) 68 | } 69 | 70 | rrsetName := d.Get("name").(string) 71 | zoneID := d.Get("zone_id").(string) 72 | rrsetType := d.Get("type").(string) 73 | 74 | zoneIDWithRRSetNameAndType := fmt.Sprintf("zone_id: %s, rrset_name: %s, rrset_type: %s", zoneID, rrsetName, rrsetType) 75 | log.Println(msgGet(objectRRSet, zoneIDWithRRSetNameAndType)) 76 | 77 | rrset, err := getRRSetByNameAndType(ctx, client, zoneID, rrsetName, rrsetType) 78 | if err != nil { 79 | return diag.FromErr(err) 80 | } 81 | 82 | err = setRRSetToResourceData(d, rrset) 83 | if err != nil { 84 | return diag.FromErr(err) 85 | } 86 | 87 | return nil 88 | } 89 | -------------------------------------------------------------------------------- /selectel/data_source_selectel_domains_rrset_v2_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 9 | domainsV2 "github.com/selectel/domains-go/pkg/v2" 10 | ) 11 | 12 | func TestAccDomainsRRSetV2DataSourceBasic(t *testing.T) { 13 | testProjectName := acctest.RandomWithPrefix("tf-acc") 14 | testZoneName := fmt.Sprintf("%s.ru.", acctest.RandomWithPrefix("tf-acc")) 15 | testRRSetName := fmt.Sprintf("%[1]s.%[2]s", acctest.RandomWithPrefix("tf-acc"), testZoneName) 16 | testRRSetType := domainsV2.TXT 17 | testRRSetTTL := 60 18 | testRRSetContent := fmt.Sprintf("\"%[1]s\"", acctest.RandString(16)) 19 | dataSourceRRSetName := fmt.Sprintf("data.selectel_domains_rrset_v2.%[1]s", resourceRRSetName) 20 | resource.Test(t, resource.TestCase{ 21 | PreCheck: func() { testAccSelectelPreCheck(t) }, 22 | ProviderFactories: testAccProviders, 23 | CheckDestroy: testAccCheckDomainsV2RRSetDestroy, 24 | Steps: []resource.TestStep{ 25 | { 26 | Config: testAccDomainsRRSetV2DataSourceBasic(testProjectName, resourceRRSetName, testRRSetName, string(testRRSetType), testRRSetContent, testRRSetTTL, resourceZoneName, testZoneName), 27 | Check: resource.ComposeTestCheckFunc( 28 | testAccDomainsRRSetV2ID(dataSourceRRSetName), 29 | resource.TestCheckResourceAttr(dataSourceRRSetName, "name", testRRSetName), 30 | resource.TestCheckResourceAttr(dataSourceRRSetName, "type", string(testRRSetType)), 31 | resource.TestCheckResourceAttrSet(dataSourceRRSetName, "zone_id"), 32 | ), 33 | }, 34 | }, 35 | }) 36 | } 37 | 38 | func testAccDomainsRRSetV2DataSourceBasic(projectName, resourceRRSetName, rrsetName, rrsetType, rrsetContent string, ttl int, resourceZoneName, zoneName string) string { 39 | return fmt.Sprintf(` 40 | %[1]s 41 | data "selectel_domains_rrset_v2" %[2]q { 42 | name = selectel_domains_rrset_v2.%[2]s.name 43 | type = selectel_domains_rrset_v2.%[2]s.type 44 | zone_id = selectel_domains_zone_v2.%[3]s.id 45 | project_id = "${selectel_vpc_project_v2.project_tf_acc_test_1.id}" 46 | } 47 | `, testAccDomainsRRSetV2WithZoneBasic(projectName, resourceRRSetName, rrsetName, rrsetType, rrsetContent, ttl, resourceZoneName, zoneName), resourceRRSetName, resourceZoneName) 48 | } 49 | -------------------------------------------------------------------------------- /website/docs/r/craas_token_v1.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "selectel" 3 | page_title: "Selectel: selectel_craas_token_v1" 4 | sidebar_current: "docs-selectel-resource-craas-token-v1" 5 | description: |- 6 | Creates and manages tokens in Selectel Container Registry using public API v1. 7 | --- 8 | 9 | # selectel\_craas\_token\_v1 10 | 11 | 12 | **WARNING**: This resource is deprecated and is going to be removed soon. You should use the [selectel_craas_token_v2](https://registry.terraform.io/providers/selectel/selectel/latest/docs/resources/craas_token_v2) resource 13 | 14 | 15 | Creates and manages tokens in Container Registry using public API v1. For more information about Container Registry, see the [official Selectel documentation](https://docs.selectel.ru/en/cloud/craas/). 16 | 17 | ## Basic usage example 18 | 19 | ```hcl 20 | resource "selectel_craas_token_v1" "token_1" { 21 | project_id = selectel_vpc_project_v2.project_1.id 22 | } 23 | ``` 24 | 25 | ## Docker CLI login example 26 | 27 | ```hcl 28 | resource "selectel_craas_token_v1" "token_1" { 29 | project_id = selectel_vpc_project_v2.project_1.id 30 | } 31 | 32 | output "registry_username" { 33 | value = selectel_craas_token_v1.token_1.username 34 | sensitive = true 35 | } 36 | 37 | output "registry_token" { 38 | value = selectel_craas_token_v1.token_1.token 39 | sensitive = true 40 | } 41 | ``` 42 | 43 | ```shell 44 | REGISTRY_USERNAME=$(terraform output -raw registry_username) 45 | REGISTRY_TOKEN=$(terraform output -raw registry_token) 46 | echo $REGISTRY_TOKEN | docker login cr.selcloud.ru --username $REGISTRY_USERNAME --password-stdin 47 | ``` 48 | 49 | ## Argument Reference 50 | 51 | * `project_id` - (Required) Unique identifier of the associated project. Changing this creates a new token. Retrieved from the [selectel_vpc_project_v2](https://registry.terraform.io/providers/selectel/selectel/latest/docs/resources/vpc_project_v2) resource. Learn more about [Projects](https://docs.selectel.ru/en/control-panel-actions/projects/about-projects/). 52 | 53 | * `token_ttl` - (Optional) Token lifetime. Changing this creates a new token. Available values are `1y` for a year and `12h` for 12 hours. The default value is `1y`. 54 | 55 | ## Attributes Reference 56 | 57 | * `username` - (Sensitive) Username to access Container Registry. 58 | 59 | * `token` - (Sensitive) Token to access Container Registry. 60 | -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | TEST?=$$(go list ./...) 2 | GOFMT_FILES?=$$(find . -name '*.go') 3 | WEBSITE_REPO=github.com/hashicorp/terraform-website 4 | PKG_NAME=selectel 5 | 6 | default: build 7 | 8 | golangci-lint: 9 | @sh -c "'$(CURDIR)/scripts/golangci_lint_check.sh'" 10 | 11 | build: 12 | go build 13 | 14 | test: 15 | go test -i $(TEST) || exit 1 16 | echo $(TEST) | \ 17 | xargs -t -n4 go test $(TESTARGS) -timeout=30s -parallel=4 18 | 19 | testacc: 20 | TF_ACC=1 go test $(TEST) $(TESTARGS) -timeout 360m 21 | 22 | fmt: 23 | @echo "==> Fixing source code with gofmt..." 24 | gofmt -w $(GOFMT_FILES) 25 | 26 | test-compile: 27 | @if [ "$(TEST)" = "./..." ]; then \ 28 | echo "ERROR: Set TEST to a specific package. For example,"; \ 29 | echo " make test-compile TEST=./$(PKG_NAME)"; \ 30 | exit 1; \ 31 | fi 32 | go test -c $(TEST) $(TESTARGS) 33 | 34 | website: 35 | ifeq (,$(wildcard $(GOPATH)/src/$(WEBSITE_REPO))) 36 | echo "$(WEBSITE_REPO) not found in your GOPATH (necessary for layouts and assets), get-ting..." 37 | git clone https://$(WEBSITE_REPO) $(GOPATH)/src/$(WEBSITE_REPO) 38 | endif 39 | @$(MAKE) -C $(GOPATH)/src/$(WEBSITE_REPO) website-provider PROVIDER_PATH=$(shell pwd) PROVIDER_NAME=$(PKG_NAME) 40 | 41 | website-test: 42 | ifeq (,$(wildcard $(GOPATH)/src/$(WEBSITE_REPO))) 43 | echo "$(WEBSITE_REPO) not found in your GOPATH (necessary for layouts and assets), get-ting..." 44 | git clone https://$(WEBSITE_REPO) $(GOPATH)/src/$(WEBSITE_REPO) 45 | endif 46 | @$(MAKE) -C $(GOPATH)/src/$(WEBSITE_REPO) website-provider-test PROVIDER_PATH=$(shell pwd) PROVIDER_NAME=$(PKG_NAME) 47 | 48 | 49 | # CLI reference: 50 | # https://semgrep.dev/docs/cli-reference 51 | semgrep: 52 | docker run --rm -v ${PWD}:/app:ro -w /app semgrep/semgrep semgrep scan --error --metrics=off \ 53 | --config=p/command-injection \ 54 | --config=p/comment \ 55 | --config=p/cwe-top-25 \ 56 | --config=p/default \ 57 | --config=p/gitleaks \ 58 | --config=p/golang \ 59 | --config=p/gosec \ 60 | --config=p/insecure-transport \ 61 | --config=p/owasp-top-ten \ 62 | --config=p/r2c-best-practices \ 63 | --config=p/r2c-bug-scan \ 64 | --config=p/r2c-security-audit \ 65 | --config=p/secrets \ 66 | --config=p/security-audit \ 67 | --config=p/sql-injection \ 68 | --config=p/xss \ 69 | . 70 | 71 | .PHONY: golangci-lint build test testacc fmt test-compile semgrep website website-test 72 | -------------------------------------------------------------------------------- /selectel/data_source_selectel_mks_kubeconfig_v1.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 8 | "github.com/selectel/mks-go/pkg/v1/cluster" 9 | ) 10 | 11 | func dataSourceMKSKubeconfigV1() *schema.Resource { 12 | return &schema.Resource{ 13 | ReadContext: dataSourceMKSKubeconfigV1Read, 14 | Schema: map[string]*schema.Schema{ 15 | "project_id": { 16 | Type: schema.TypeString, 17 | Required: true, 18 | ForceNew: true, 19 | }, 20 | "cluster_id": { 21 | Type: schema.TypeString, 22 | Required: true, 23 | ForceNew: true, 24 | }, 25 | "region": { 26 | Type: schema.TypeString, 27 | Required: true, 28 | }, 29 | "raw_config": { 30 | Type: schema.TypeString, 31 | Computed: true, 32 | Sensitive: true, 33 | }, 34 | "server": { 35 | Type: schema.TypeString, 36 | Computed: true, 37 | Sensitive: true, 38 | }, 39 | "cluster_ca_cert": { 40 | Type: schema.TypeString, 41 | Computed: true, 42 | Sensitive: true, 43 | }, 44 | "client_cert": { 45 | Type: schema.TypeString, 46 | Computed: true, 47 | Sensitive: true, 48 | }, 49 | "client_key": { 50 | Type: schema.TypeString, 51 | Computed: true, 52 | Sensitive: true, 53 | }, 54 | }, 55 | } 56 | } 57 | 58 | func dataSourceMKSKubeconfigV1Read(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { 59 | mksClient, diagErr := getMKSClient(d, meta) 60 | if diagErr != nil { 61 | return diagErr 62 | } 63 | 64 | clusterID := d.Get("cluster_id").(string) 65 | 66 | mksCluster, _, err := cluster.Get(ctx, mksClient, clusterID) 67 | if err != nil { 68 | return diag.FromErr(errGettingObject(objectCluster, clusterID, err)) 69 | } 70 | 71 | parsedKubeconfig, _, err := cluster.GetParsedKubeconfig(ctx, mksClient, mksCluster.ID) 72 | if err != nil { 73 | return diag.FromErr(errGettingObject(objectKubeConfig, clusterID, err)) 74 | } 75 | 76 | d.SetId(clusterID) 77 | d.Set("raw_config", parsedKubeconfig.KubeconfigRaw) 78 | d.Set("server", parsedKubeconfig.Server) 79 | d.Set("cluster_ca_cert", parsedKubeconfig.ClusterCA) 80 | d.Set("client_cert", parsedKubeconfig.ClientCert) 81 | d.Set("client_key", parsedKubeconfig.ClientKey) 82 | 83 | return nil 84 | } 85 | -------------------------------------------------------------------------------- /selectel/domains.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | "time" 8 | 9 | "github.com/hashicorp/go-retryablehttp" 10 | domainsV1 "github.com/selectel/domains-go/pkg/v1" 11 | ) 12 | 13 | const ( 14 | domainsV1DefaultRetryWaitMin = time.Second 15 | domainsV1DefaultRetryWaitMax = 5 * time.Second 16 | domainsV1DefaultRetry = 5 17 | ) 18 | 19 | func getDomainsClient(meta interface{}) (*domainsV1.ServiceClient, error) { 20 | config := meta.(*Config) 21 | 22 | selvpcClient, err := config.GetSelVPCClient() 23 | if err != nil { 24 | return nil, fmt.Errorf("can't get selvpc client for domains: %w", err) 25 | } 26 | 27 | domainsClient := domainsV1.NewDomainsClientV1WithDefaultEndpoint(selvpcClient.GetXAuthToken()).WithOSToken() 28 | 29 | retryClient := retryablehttp.NewClient() 30 | retryClient.Logger = nil // Ignore retyablehttp client logs 31 | retryClient.RetryWaitMin = domainsV1DefaultRetryWaitMin 32 | retryClient.RetryWaitMax = domainsV1DefaultRetryWaitMax 33 | retryClient.RetryMax = domainsV1DefaultRetry 34 | domainsClient.HTTPClient = retryClient.StandardClient() 35 | 36 | return domainsClient, nil 37 | } 38 | 39 | const ( 40 | TypeRecordA string = "A" 41 | TypeRecordAAAA string = "AAAA" 42 | TypeRecordTXT string = "TXT" 43 | TypeRecordCNAME string = "CNAME" 44 | TypeRecordNS string = "NS" 45 | TypeRecordSOA string = "SOA" 46 | TypeRecordMX string = "MX" 47 | TypeRecordSRV string = "SRV" 48 | TypeRecordCAA string = "CAA" 49 | TypeRecordSSHFP string = "SSHFP" 50 | TypeRecordALIAS string = "ALIAS" 51 | ) 52 | 53 | func domainsV1ParseDomainRecordIDsPair(id string) (int, int, error) { 54 | parts := strings.Split(id, "/") 55 | if len(parts) != 2 { 56 | return -1, -1, errParseDomainsDomainRecordV1IDsPair(id) 57 | } 58 | if parts[0] == "" || parts[1] == "" { 59 | return -1, -1, errParseDomainsDomainRecordV1IDsPair(id) 60 | } 61 | 62 | domainID, err := strconv.Atoi(parts[0]) 63 | if err != nil { 64 | return -1, -1, errParseDomainsDomainV1ID(parts[0]) 65 | } 66 | 67 | recordID, err := strconv.Atoi(parts[1]) 68 | if err != nil { 69 | return -1, -1, errParseDomainsRecordV1ID(parts[1]) 70 | } 71 | 72 | return domainID, recordID, nil 73 | } 74 | 75 | func getIntPtrOrNil(v interface{}) *int { 76 | if v == nil { 77 | return nil 78 | } 79 | 80 | return intPtr(v.(int)) 81 | } 82 | 83 | func intPtr(v int) *int { 84 | return &v 85 | } 86 | -------------------------------------------------------------------------------- /website/docs/r/secretsmanager_secret_v1.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "selectel" 3 | page_title: "Selectel: selectel_secretsmanager_secret_v1" 4 | sidebar_current: "docs-selectel-resource-secretsmanager-secret-v1" 5 | description: |- 6 | Creates and manages a secret in Selectel Secrets Manager using public API v1. 7 | --- 8 | 9 | # selectel\_secretsmanager\_secret_v1 10 | 11 | Creates and manages a secret in Selectel Secrets Manager using public API v1. For more information about Secrets Manager, see the [official Selectel documentation](https://docs.selectel.ru/en/cloud/secrets-manager/secrets/). 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | resource "selectel_secretsmanager_secret_v1" "secret_1" { 17 | key = "secret" 18 | value = "verysecret" 19 | project_id = selectel_vpc_project_v2.project_1.id 20 | description = "secret from .tf" 21 | } 22 | ``` 23 | 24 | ## Argument Reference 25 | 26 | * `key` - (Required) Secret name. 27 | 28 | * `value` - (Required, Sensitive) Secret value, for example password, API key, certificate key. The limit is 65 536 characters. 29 | 30 | * `project_id` - (Required) Unique identifier of the associated project. Retrieved from the [selectel_vpc_project_v2](https://registry.terraform.io/providers/selectel/selectel/latest/docs/resources/vpc_project_v2) resource. Learn more about [Projects](https://docs.selectel.ru/en/control-panel-actions/projects/about-projects/). 31 | 32 | * `description` - (Optional) Secret description. 33 | 34 | ## Attributes Reference 35 | 36 | * `created_at` - Time when the secret was created. 37 | 38 | * `name` - Secret name, same as the secret key. 39 | 40 | ## Import 41 | 42 | You can import a secret: 43 | 44 | ```shell 45 | export INFRA_PROJECT_ID= 46 | terraform import selectel_secretsmanager_secret_v1.secret_1 / 47 | ``` 48 | 49 | where: 50 | 51 | * `` — Unique identifier of the associated project. To get the ID, in the [Control panel](https://my.selectel.ru/vpc/secrets-manager), go to **Cloud Platform** ⟶ project name ⟶ copy the ID of the required project. Learn more about [Projects](https://docs.selectel.ru/en/control-panel-actions/projects/about-projects/). 52 | 53 | * `` — Secret name. To get the secret name, in the [Control panel](https://my.selectel.ru/vpc/secrets-manager/), go to **Cloud Platform** ⟶ **Secrets Manager** ⟶ the **Secrets** tab ⟶ copy the name of the required secret. -------------------------------------------------------------------------------- /selectel/data_source_selectel_dbaas_prometheus_metric_token_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "testing" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 11 | "github.com/selectel/dbaas-go" 12 | "github.com/selectel/go-selvpcclient/v4/selvpcclient/resell/v2/projects" 13 | ) 14 | 15 | func TestAccDBaaSDataSourcePrometheusMetricTokenV1Basic(t *testing.T) { 16 | var ( 17 | dbaasTokens []dbaas.PrometheusMetricToken 18 | project projects.Project 19 | ) 20 | 21 | projectName := acctest.RandomWithPrefix("tf-acc") 22 | 23 | resource.Test(t, resource.TestCase{ 24 | PreCheck: func() { testAccSelectelPreCheck(t) }, 25 | ProviderFactories: testAccProviders, 26 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 27 | Steps: []resource.TestStep{ 28 | { 29 | Config: testAccDBaaSDataSourcePrometheusMetricTokenV1Basic(projectName), 30 | Check: resource.ComposeTestCheckFunc( 31 | testAccCheckVPCV2ProjectExists("selectel_vpc_project_v2.project_tf_acc_test_1", &project), 32 | testAccDBaaSPrometheusMetricTokensV1Exists("data.selectel_dbaas_prometheus_metric_token_v1.prometheus_metric_token_tf_acc_test_1", &dbaasTokens), 33 | ), 34 | }, 35 | }, 36 | }) 37 | } 38 | 39 | func testAccDBaaSPrometheusMetricTokensV1Exists(n string, dbaasTokens *[]dbaas.PrometheusMetricToken) resource.TestCheckFunc { 40 | return func(s *terraform.State) error { 41 | rs, ok := s.RootModule().Resources[n] 42 | if !ok { 43 | return fmt.Errorf("not found: %s", n) 44 | } 45 | 46 | ctx := context.Background() 47 | 48 | dbaasClient, err := newTestDBaaSClient(ctx, rs, testAccProvider) 49 | if err != nil { 50 | return err 51 | } 52 | 53 | tokens, err := dbaasClient.PrometheusMetricTokens(ctx) 54 | if err != nil { 55 | return err 56 | } 57 | 58 | *dbaasTokens = tokens 59 | 60 | return nil 61 | } 62 | } 63 | 64 | func testAccDBaaSDataSourcePrometheusMetricTokenV1Basic(projectName string) string { 65 | return fmt.Sprintf(` 66 | resource "selectel_vpc_project_v2" "project_tf_acc_test_1" { 67 | name = "%s" 68 | } 69 | 70 | data "selectel_dbaas_prometheus_metric_token_v1" "prometheus_metric_token_tf_acc_test_1" { 71 | project_id = "${selectel_vpc_project_v2.project_tf_acc_test_1.id}" 72 | region = "ru-3" 73 | } 74 | `, projectName) 75 | } 76 | -------------------------------------------------------------------------------- /.github/workflows/secure.yml: -------------------------------------------------------------------------------- 1 | name: Secure 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | # Sample GitHub Actions: 11 | # https://semgrep.dev/docs/semgrep-ci/sample-ci-configs#sample-github-actions-configuration-file 12 | # 13 | # CLI Reference: 14 | # https://semgrep.dev/docs/cli-reference 15 | semgrep: 16 | runs-on: ubuntu-24.04 17 | container: 18 | image: semgrep/semgrep 19 | permissions: 20 | contents: read 21 | security-events: write 22 | steps: 23 | - uses: actions/checkout@v4 24 | - run: semgrep scan --sarif --output=semgrep.sarif --error --severity=WARNING --severity=ERROR 25 | env: 26 | SEMGREP_RULES: >- 27 | p/command-injection 28 | p/comment 29 | p/cwe-top-25 30 | p/default 31 | p/gitleaks 32 | p/golang 33 | p/gosec 34 | p/insecure-transport 35 | p/owasp-top-ten 36 | p/r2c-best-practices 37 | p/r2c-bug-scan 38 | p/r2c-security-audit 39 | p/secrets 40 | p/security-audit 41 | p/sql-injection 42 | p/xss 43 | - uses: github/codeql-action/upload-sarif@v3 44 | with: 45 | sarif_file: semgrep.sarif 46 | if: always() 47 | 48 | # CLI Reference: 49 | # https://github.com/aquasecurity/trivy/blob/main/docs/docs/references/configuration/cli/trivy_filesystem.md 50 | # https://aquasecurity.github.io/trivy/latest/docs/configuration/#environment-variables 51 | trivy: 52 | runs-on: ubuntu-24.04 53 | container: 54 | image: aquasec/trivy 55 | permissions: 56 | contents: read 57 | security-events: write 58 | steps: 59 | - uses: actions/checkout@v4 60 | - run: trivy fs . 61 | env: 62 | TRIVY_FORMAT: sarif 63 | TRIVY_OUTPUT: trivy.sarif 64 | TRIVY_severity: MEDIUM,HIGH 65 | TRIVY_EXIT_CODE: 1 66 | TRIVY_IGNOREFILE: .trivyignore.yml 67 | TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db 68 | - uses: github/codeql-action/upload-sarif@v3 69 | with: 70 | sarif_file: trivy.sarif 71 | if: always() 72 | 73 | # Samples GitHub Actions: 74 | # https://github.com/golang/govulncheck-action 75 | govulncheck: 76 | runs-on: ubuntu-24.04 77 | steps: 78 | - uses: golang/govulncheck-action@v1 79 | with: 80 | go-version-file: go.mod 81 | -------------------------------------------------------------------------------- /selectel/data_source_selectel_dedicated_location_v1_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "testing" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 11 | "github.com/selectel/go-selvpcclient/v4/selvpcclient/resell/v2/projects" 12 | ) 13 | 14 | func TestAccDedicatedLocationV1Basic(t *testing.T) { 15 | var project projects.Project 16 | 17 | projectName := acctest.RandomWithPrefix("tf-acc") 18 | locationName := "MSK-2" 19 | 20 | resource.Test(t, resource.TestCase{ 21 | PreCheck: func() { testAccSelectelPreCheck(t) }, 22 | ProviderFactories: testAccProviders, 23 | CheckDestroy: testAccCheckVPCV2ProjectDestroy, 24 | Steps: []resource.TestStep{ 25 | { 26 | Config: testAccDedicatedLocationV1Basic(projectName, locationName), 27 | Check: resource.ComposeTestCheckFunc( 28 | testAccCheckVPCV2ProjectExists("selectel_vpc_project_v2.project_tf_acc_test_1", &project), 29 | testAccDedicatedLocationV1Exists("data.selectel_dedicated_location_v1.location_tf_acc_test_1", locationName), 30 | resource.TestCheckResourceAttr("data.selectel_dedicated_location_v1.location_tf_acc_test_1", "locations.0.name", locationName), 31 | ), 32 | }, 33 | }, 34 | }) 35 | } 36 | 37 | func testAccDedicatedLocationV1Exists( 38 | n string, locationName string, 39 | ) resource.TestCheckFunc { 40 | return func(s *terraform.State) error { 41 | rs, ok := s.RootModule().Resources[n] 42 | if !ok { 43 | return fmt.Errorf("not found: %s", n) 44 | } 45 | 46 | ctx := context.Background() 47 | 48 | dsClient := newTestDedicatedAPIClient(rs, testAccProvider) 49 | 50 | locationsFromAPI, _, err := dsClient.Locations(ctx) 51 | if err != nil { 52 | return err 53 | } 54 | 55 | locFromAPI := locationsFromAPI.FindOneByName(locationName) 56 | 57 | if locFromAPI == nil { 58 | return fmt.Errorf("location %s not found", locationName) 59 | } 60 | 61 | return nil 62 | } 63 | } 64 | 65 | func testAccDedicatedLocationV1Basic(projectName, locationName string) string { 66 | return fmt.Sprintf(` 67 | resource "selectel_vpc_project_v2" "project_tf_acc_test_1" { 68 | name = "%s" 69 | } 70 | 71 | data "selectel_dedicated_location_v1" "location_tf_acc_test_1" { 72 | project_id = "${selectel_vpc_project_v2.project_tf_acc_test_1.id}" 73 | filter { 74 | name = "%s" 75 | } 76 | } 77 | `, projectName, locationName) 78 | } 79 | -------------------------------------------------------------------------------- /selectel/waiters/cloudbackup/plan.go: -------------------------------------------------------------------------------- 1 | package cloudbackup 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | "time" 8 | 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 11 | cloudbackup "github.com/selectel/cloudbackup-go/pkg/v2" 12 | ) 13 | 14 | func WaitForPlanV2StartedState( 15 | ctx context.Context, client *cloudbackup.ServiceClient, id string, timeout time.Duration, 16 | ) diag.Diagnostics { 17 | stateConf := &resource.StateChangeConf{ 18 | Pending: []string{ 19 | cloudbackup.PlanStatusSuspended, 20 | }, 21 | Target: []string{ 22 | cloudbackup.PlanStatusStarted, 23 | }, 24 | Timeout: timeout, 25 | Refresh: planV2RefreshFunc(ctx, client, id), 26 | MinTimeout: 10 * time.Second, 27 | } 28 | 29 | _, err := stateConf.WaitForStateContext(ctx) 30 | if err != nil { 31 | return diag.Errorf( 32 | "error waiting for the plan %s to become '%s': %v", 33 | id, cloudbackup.PlanStatusStarted, err, 34 | ) 35 | } 36 | 37 | return nil 38 | } 39 | 40 | func planV2RefreshFunc(ctx context.Context, client *cloudbackup.ServiceClient, id string) resource.StateRefreshFunc { 41 | return func() (interface{}, string, error) { 42 | p, _, err := client.Plan(ctx, id) 43 | if err != nil { 44 | return nil, "", err 45 | } 46 | 47 | if p == nil { 48 | return nil, "", fmt.Errorf("can't find created plan %s", id) 49 | } 50 | 51 | return p, p.Status, nil 52 | } 53 | } 54 | 55 | func WaitForPlanV2Deleted( 56 | ctx context.Context, client *cloudbackup.ServiceClient, id string, timeout time.Duration, 57 | ) diag.Diagnostics { 58 | stateConf := &resource.StateChangeConf{ 59 | Pending: []string{ 60 | cloudbackup.PlanStatusStarted, 61 | cloudbackup.PlanStatusSuspended, 62 | }, 63 | Target: []string{}, 64 | Timeout: timeout, 65 | Refresh: planV2DeleteRefreshFunc(ctx, client, id), 66 | } 67 | 68 | _, err := stateConf.WaitForStateContext(ctx) 69 | if err != nil { 70 | return diag.Errorf("error waiting for the plan %s to be deleted: %v", id, err) 71 | } 72 | 73 | return nil 74 | } 75 | 76 | func planV2DeleteRefreshFunc(ctx context.Context, client *cloudbackup.ServiceClient, id string) resource.StateRefreshFunc { 77 | return func() (interface{}, string, error) { 78 | p, resp, err := client.Plan(ctx, id) 79 | switch { 80 | case resp != nil && resp.StatusCode == http.StatusNotFound: 81 | return nil, "", nil 82 | case err != nil: 83 | return nil, "", err 84 | } 85 | 86 | return p, p.Status, nil 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /website/docs/d/cloudbackup_plan_v2.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "selectel" 3 | page_title: "Selectel: selectel_cloudbackup_plan_v2" 4 | sidebar_current: "docs-selectel-datasource-cloudbackup-plan-v2" 5 | description: |- 6 | Provides a list of backup plans for Selectel Backups in the Cloud. 7 | --- 8 | 9 | # selectel\_cloudbackup\_plan\_v2 10 | 11 | Provides a list of backup plans for Selectel Backups in the Cloud. For more information about backup plans, see the [official Selectel documentation](https://docs.selectel.ru/en/cloud-servers/backups/about-backups/). 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "selectel_cloudbackup_plan_v2" "plan_1" { 17 | project_id = selectel_vpc_project_v2.project_1.id 18 | region = "ru-3" 19 | filter { 20 | name = "my-backup-plan" 21 | volume_name = "my-volume" 22 | status = "started" 23 | } 24 | } 25 | ``` 26 | 27 | ## Argument Reference 28 | 29 | * `project_id` - (Required) Unique identifier of the associated project. Retrieved from the [selectel_vpc_project_v2](https://registry.terraform.io/providers/selectel/selectel/latest/docs/resources/vpc_project_v2) resource. Learn more about [Projects](https://docs.selectel.ru/en/control-panel-actions/projects/about-projects/). 30 | 31 | * `region` - (Required) Pool where the backup plan is located, for example, `ru-3`. Learn more about available pools in the [Availability matrix](https://docs.selectel.ru/en/control-panel-actions/availability-matrix/). 32 | 33 | * `filter` - (Optional) Values to filter backup plans. 34 | 35 | * `name` - (Optional) Name of the backup plan. 36 | * `volume_name` - (Optional) Name of the volume. 37 | * `status` - (Optional) Status of the backup plan. 38 | 39 | ## Attributes Reference 40 | 41 | * `plans` - List of backup plans: 42 | 43 | * `list`- Plans list: 44 | 45 | * `id` - Unique identifier of the backup plan. 46 | * `name` - Name of the backup plan. 47 | * `status` - Status of the backup plan. 48 | * `backup_mode` - Backup mode. 49 | * `created_at` - Time when the backup plan was created. 50 | * `full_backups_amount` - Number of full backups. 51 | * `resources` - List of resources that are backed up according to the backup plan: 52 | * `id` - Unique identifier of the resource that is backed up according to the backup plan. 53 | * `name` - Resource name. 54 | * `type` - Resource type. 55 | * `schedule_pattern` - Schedule pattern for the backup plan. 56 | * `schedule_type` - Schedule type for the backup plan. 57 | 58 | * `total` - Total number of backup plans. 59 | 60 | 61 | -------------------------------------------------------------------------------- /website/docs/d/dedicated_configuration_v1.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "selectel" 3 | page_title: "Selectel: selectel_dedicated_configuration_v1" 4 | sidebar_current: "docs-selectel-datasource-dedicated-configuration-v1" 5 | description: |- 6 | Provides a list of server configurations available in Selectel. 7 | --- 8 | 9 | # selectel\_dedicated\_configuration\_v1 10 | 11 | Provides a list of server configurations available in Selectel. 12 | 13 | ## Example Usage 14 | 15 | ### Find configuration ID by name 16 | 17 | ```hcl 18 | data "selectel_dedicated_configuration_v1" "server_config" { 19 | project_id = selectel_vpc_project_v2.project_1.id 20 | deep_filter = "{\"name\":\"CL25-NVMe\"}" 21 | } 22 | ``` 23 | 24 | ### Search available configurations with additional parameters 25 | 26 | 27 | ```hcl 28 | data "selectel_dedicated_configuration_v1" "server_config" { 29 | project_id = selectel_vpc_project_v2.project_1.id 30 | deep_filter = < 40 | export OS_USERNAME= 41 | export OS_PASSWORD= 42 | terraform import selectel_domains_domain_v1.domain_1 43 | ``` 44 | 45 | where: 46 | 47 | * `` — Selectel account ID. The account ID is in the top right corner of the [Control panel](https://my.selectel.ru/). Learn more about [Registration](https://docs.selectel.ru/en/control-panel-actions/account/registration/). 48 | 49 | * `` — Name of the service user. To get the name, in the [Control panel](https://my.selectel.ru/iam/users_management/users?type=service), go to **Identity & Access Management** ⟶ **User management** ⟶ the **Service users** tab ⟶ copy the name of the required user. Learn more about [Service users](https://docs.selectel.ru/en/control-panel-actions/users-and-roles/user-types-and-roles/). 50 | 51 | * `` — Password of the service user. 52 | 53 | * `` — Unique identifier of the domain, for example, `45623`. To get the domain ID, in the [Control panel](https://my.selectel.ru/network/domains/), go to **Networks Services** ⟶ **DNS Hosting** ⟶ the domain page ⟶ copy the domain ID from the address bar. -------------------------------------------------------------------------------- /selectel/networking_test.go: -------------------------------------------------------------------------------- 1 | package selectel 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/selectel/go-selvpcclient/v4/selvpcclient" 7 | "github.com/selectel/go-selvpcclient/v4/selvpcclient/resell/v2/subnets" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestGetPrefixLengthFromCIDR(t *testing.T) { 12 | testingData := map[string]int{ 13 | "192.0.2.100/29": 29, 14 | "192.0.2.200/28": 28, 15 | "203.0.113.10/24": 24, 16 | "203.0.113.129/25": 25, 17 | } 18 | 19 | for cidr, expected := range testingData { 20 | actual, err := getPrefixLengthFromCIDR(cidr) 21 | 22 | assert.NoError(t, err) 23 | assert.Equal(t, expected, actual) 24 | } 25 | } 26 | 27 | func TestGetIPVersionFromPrefixLength(t *testing.T) { 28 | testingData := map[int]string{ 29 | 29: string(selvpcclient.IPv4), 30 | 28: string(selvpcclient.IPv4), 31 | 48: string(selvpcclient.IPv6), 32 | 64: string(selvpcclient.IPv6), 33 | 24: string(selvpcclient.IPv4), 34 | 25: string(selvpcclient.IPv4), 35 | } 36 | 37 | for prefixLength, expected := range testingData { 38 | actual := getIPVersionFromPrefixLength(prefixLength) 39 | 40 | assert.Equal(t, expected, actual) 41 | } 42 | } 43 | 44 | func TestSubnetsMapsFromStructs(t *testing.T) { 45 | subnetsStructs := []subnets.Subnet{ 46 | { 47 | NetworkID: "912bd5d0-cb11-4a7f-af7c-ea84c8e7db2e", 48 | SubnetID: "4912cca9-cad2-49c1-a69a-929cd4cf9559", 49 | Region: "ru-2", 50 | CIDR: "192.168.200.0/24", 51 | VLANID: 1003, 52 | ProjectID: "b63ab68796e34858befb8fa2a8b1e12a", 53 | VTEPIPAddress: "10.10.0.101", 54 | }, 55 | { 56 | NetworkID: "954c6ebd-f923-4471-847a-e1be04af8952", 57 | SubnetID: "4754c984-bb91-4221-820c-ae2b0f64dae0", 58 | Region: "ru-3", 59 | CIDR: "192.168.200.0/24", 60 | VLANID: 1003, 61 | ProjectID: "b63ab68796e34858befb8fa2a8b1e12a", 62 | VTEPIPAddress: "10.10.0.201", 63 | }, 64 | } 65 | expectedSubnetsMaps := []map[string]interface{}{ 66 | { 67 | "network_id": "912bd5d0-cb11-4a7f-af7c-ea84c8e7db2e", 68 | "subnet_id": "4912cca9-cad2-49c1-a69a-929cd4cf9559", 69 | "region": "ru-2", 70 | "cidr": "192.168.200.0/24", 71 | "vlan_id": 1003, 72 | "project_id": "b63ab68796e34858befb8fa2a8b1e12a", 73 | "vtep_ip_address": "10.10.0.101", 74 | }, 75 | { 76 | "network_id": "954c6ebd-f923-4471-847a-e1be04af8952", 77 | "subnet_id": "4754c984-bb91-4221-820c-ae2b0f64dae0", 78 | "region": "ru-3", 79 | "cidr": "192.168.200.0/24", 80 | "vlan_id": 1003, 81 | "project_id": "b63ab68796e34858befb8fa2a8b1e12a", 82 | "vtep_ip_address": "10.10.0.201", 83 | }, 84 | } 85 | 86 | actualSubnetsMaps := subnetsMapsFromStructs(subnetsStructs) 87 | 88 | assert.ElementsMatch(t, expectedSubnetsMaps, actualSubnetsMaps) 89 | } 90 | --------------------------------------------------------------------------------