diff --git a/go.mod b/go.mod index 84d6b7dacb..439aa04a6f 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ require ( github.com/hashicorp/errwrap v1.0.0 github.com/hashicorp/go-cleanhttp v0.5.1 github.com/hashicorp/terraform-plugin-sdk v1.13.0 - github.com/huaweicloud/golangsdk v0.0.0-20200619095000-03444f871c13 + github.com/huaweicloud/golangsdk v0.0.0-20200630015217-45223898b76a github.com/jen20/awspolicyequivalence v0.0.0-20170831201602-3d48364a137a github.com/mitchellh/go-homedir v1.1.0 github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa // indirect diff --git a/go.sum b/go.sum index 30965c85ae..5dc97e7654 100644 --- a/go.sum +++ b/go.sum @@ -135,6 +135,8 @@ github.com/huaweicloud/golangsdk v0.0.0-20200615044122-296c30220a0c h1:VLEty8RjU github.com/huaweicloud/golangsdk v0.0.0-20200615044122-296c30220a0c/go.mod h1:WQBcHRNX9shz3928lWEvstQJtAtYI7ks6XlgtRT9Tcw= github.com/huaweicloud/golangsdk v0.0.0-20200619095000-03444f871c13 h1:JomfIDZddMDb/oV84a9X+VN1m/TPJwo0SZ6+Efguy8s= github.com/huaweicloud/golangsdk v0.0.0-20200619095000-03444f871c13/go.mod h1:WQBcHRNX9shz3928lWEvstQJtAtYI7ks6XlgtRT9Tcw= +github.com/huaweicloud/golangsdk v0.0.0-20200630015217-45223898b76a h1:V3MolC7F078F1V+E/9vxWIXp6Krgl95zU1cG7vok2a0= +github.com/huaweicloud/golangsdk v0.0.0-20200630015217-45223898b76a/go.mod h1:WQBcHRNX9shz3928lWEvstQJtAtYI7ks6XlgtRT9Tcw= github.com/jen20/awspolicyequivalence v0.0.0-20170831201602-3d48364a137a h1:FyS/ubzBR5xJlnJGRTwe7GUHpJOR4ukYK3y+LFNffuA= github.com/jen20/awspolicyequivalence v0.0.0-20170831201602-3d48364a137a/go.mod h1:uoIMjNxUfXi48Ci40IXkPRbghZ1vbti6v9LCbNqRgHY= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= diff --git a/huaweicloud/config.go b/huaweicloud/config.go index 0fa2529a6b..8d22bffa87 100644 --- a/huaweicloud/config.go +++ b/huaweicloud/config.go @@ -691,6 +691,14 @@ func (c *Config) FgsV2Client(region string) (*golangsdk.ServiceClient, error) { }) } +func (c *Config) initServiceClient(srv, region, apiVersion string) (*golangsdk.ServiceClient, error) { + var eo = golangsdk.EndpointOpts{ + Name: srv, + Region: c.determineRegion(region), + } + return huaweisdk.InitServiceClientByName(c.HwClient, eo, apiVersion) +} + func (c *Config) sdkClient(region, serviceType string, level string) (*golangsdk.ServiceClient, error) { client := c.HwClient if level == serviceDomainLevel { diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go index c38c2dff91..7867599d7d 100644 --- a/huaweicloud/provider.go +++ b/huaweicloud/provider.go @@ -274,6 +274,7 @@ func Provider() terraform.ResourceProvider { "huaweicloud_rds_instance_v1": resourceRdsInstance(), "huaweicloud_rds_instance_v3": resourceRdsInstanceV3(), "huaweicloud_rds_parametergroup_v3": resourceRdsConfigurationV3(), + "huaweicloud_gaussdb_instance": resourceGaussDBInstance(), "huaweicloud_geminidb_instance": resourceGeminiDBInstanceV3(), "huaweicloud_nat_gateway_v2": resourceNatGatewayV2(), "huaweicloud_nat_snat_rule_v2": resourceNatSnatRuleV2(), diff --git a/huaweicloud/resource_huaweicloud_gaussdb_mysql_instance.go b/huaweicloud/resource_huaweicloud_gaussdb_mysql_instance.go new file mode 100644 index 0000000000..c2ef4c2d96 --- /dev/null +++ b/huaweicloud/resource_huaweicloud_gaussdb_mysql_instance.go @@ -0,0 +1,399 @@ +package huaweicloud + +import ( + "fmt" + "log" + "strconv" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/openstack/taurusdb/v3/instances" +) + +func resourceGaussDBInstance() *schema.Resource { + return &schema.Resource{ + Create: resourceGaussDBInstanceCreate, + Read: resourceGaussDBInstanceRead, + Delete: resourceGaussDBInstanceDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "flavor": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "password": { + Type: schema.TypeString, + Sensitive: true, + Required: true, + ForceNew: true, + }, + "vpc_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "subnet_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "security_group_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "enterprise_project_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "read_replicas": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + Default: 1, + }, + "time_zone": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: "UTC+08:00", + }, + "datastore": { + Type: schema.TypeList, + Optional: true, + Computed: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "engine": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + "gaussdb-mysql", + }, true), + }, + "version": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + }, + }, + "backup_strategy": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "start_time": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "keep_days": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + }, + }, + }, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "port": { + Type: schema.TypeInt, + Computed: true, + }, + "mode": { + Type: schema.TypeString, + Computed: true, + }, + "region": { + Type: schema.TypeString, + Computed: true, + }, + "private_write_ip": { + Type: schema.TypeString, + Computed: true, + }, + "db_user_name": { + Type: schema.TypeString, + Computed: true, + }, + "nodes": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "private_read_ip": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func resourceGaussDBDataStore(d *schema.ResourceData) instances.DataStoreOpt { + var db instances.DataStoreOpt + + datastoreRaw := d.Get("datastore").([]interface{}) + if len(datastoreRaw) == 1 { + datastore := datastoreRaw[0].(map[string]interface{}) + db.Type = datastore["engine"].(string) + db.Version = datastore["version"].(string) + } else { + db.Type = "gaussdb-mysql" + db.Version = "8.0" + } + return db +} + +func resourceGaussDBBackupStrategy(d *schema.ResourceData) *instances.BackupStrategyOpt { + var backupOpt instances.BackupStrategyOpt + + backupStrategyRaw := d.Get("backup_strategy").([]interface{}) + if len(backupStrategyRaw) == 1 { + strategy := backupStrategyRaw[0].(map[string]interface{}) + backupOpt.StartTime = strategy["start_time"].(string) + backupOpt.KeepDays = strconv.Itoa(strategy["keep_days"].(int)) + } else { + // set defautl backup strategy + backupOpt.StartTime = "00:00-01:00" + backupOpt.KeepDays = "7" + } + + return &backupOpt +} + +func GaussDBInstanceStateRefreshFunc(client *golangsdk.ServiceClient, instanceID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + v, err := instances.Get(client, instanceID).Extract() + if err != nil { + if _, ok := err.(golangsdk.ErrDefault404); ok { + return v, "DELETED", nil + } + return nil, "", err + } + + if v.Id == "" { + return v, "DELETED", nil + } + return v, v.Status, nil + } +} + +func resourceGaussDBInstanceCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + client, err := config.initServiceClient("gaussdb", GetRegion(d, config), "mysql/v3") + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud GaussDB client: %s ", err) + } + + createOpts := instances.CreateTaurusDBOpts{ + Name: d.Get("name").(string), + Flavor: d.Get("flavor").(string), + Password: d.Get("password").(string), + Region: GetRegion(d, config), + VpcId: d.Get("vpc_id").(string), + SubnetId: d.Get("subnet_id").(string), + SecurityGroupId: d.Get("security_group_id").(string), + EnterpriseProjectId: d.Get("enterprise_project_id").(string), + TimeZone: d.Get("time_zone").(string), + SlaveCount: d.Get("read_replicas").(int), + Mode: "Cluster", + AZMode: "single", + DataStore: resourceGaussDBDataStore(d), + BackupStrategy: resourceGaussDBBackupStrategy(d), + } + log.Printf("[DEBUG] Create Options: %#v", createOpts) + + instance, err := instances.Create(client, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating GaussDB instance : %s", err) + } + + id := instance.Instance.Id + d.SetId(id) + + // waiting for the instance to become ready + stateConf := &resource.StateChangeConf{ + Pending: []string{"BUILD", "BACKING UP"}, + Target: []string{"ACTIVE"}, + Refresh: GaussDBInstanceStateRefreshFunc(client, id), + Timeout: d.Timeout(schema.TimeoutCreate), + Delay: 180 * time.Second, + MinTimeout: 20 * time.Second, + } + + _, err = stateConf.WaitForState() + if err != nil { + // the instance has created, but the status is unnormal + deleteErr := resourceGaussDBInstanceDelete(d, meta) + if deleteErr != nil { + log.Printf("[ERROR] Error deleting GaussDB instance: %s", deleteErr) + } + + return fmt.Errorf( + "Error waiting for instance (%s) to become ready: %s", + id, err) + } + + return resourceGaussDBInstanceRead(d, meta) +} + +func resourceGaussDBInstanceRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + region := GetRegion(d, config) + client, err := config.initServiceClient("gaussdb", region, "mysql/v3") + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud GaussDB client: %s", err) + } + + instanceID := d.Id() + instance, err := instances.Get(client, instanceID).Extract() + if err != nil { + return CheckDeleted(d, err, "GaussDB instance") + } + if instance.Id == "" { + d.SetId("") + return nil + } + + log.Printf("[DEBUG] Retrieved instance %s: %#v", instanceID, instance) + + d.Set("region", region) + d.Set("name", instance.Name) + d.Set("status", instance.Status) + d.Set("mode", instance.Type) + d.Set("vpc_id", instance.VpcId) + d.Set("subnet_id", instance.SubnetId) + d.Set("security_group_id", instance.SecurityGroupId) + d.Set("db_user_name", instance.DbUserName) + d.Set("time_zone", instance.TimeZone) + + if dbPort, err := strconv.Atoi(instance.Port); err == nil { + d.Set("port", dbPort) + } + if len(instance.PrivateIps) > 0 { + d.Set("private_write_ip", instance.PrivateIps[0]) + } + + // set data store + dbList := make([]map[string]interface{}, 1) + db := map[string]interface{}{ + "version": instance.DataStore.Version, + } + // normalize engine + engine := instance.DataStore.Type + if engine == "GaussDB(for MySQL)" { + engine = "gaussdb-mysql" + } + db["engine"] = engine + dbList[0] = db + d.Set("datastore", dbList) + + // set nodes + nodesList := make([]map[string]interface{}, 0, 1) + for _, raw := range instance.Nodes { + node := map[string]interface{}{ + "id": raw.Id, + "name": raw.Name, + "status": raw.Status, + "type": raw.Type, + } + if len(raw.PrivateIps) > 0 { + node["private_read_ip"] = raw.PrivateIps[0] + } + nodesList = append(nodesList, node) + } + d.Set("nodes", nodesList) + + // set backup_strategy + backupStrategyList := make([]map[string]interface{}, 1) + backupStrategy := map[string]interface{}{ + "start_time": instance.BackupStrategy.StartTime, + } + if days, err := strconv.Atoi(instance.BackupStrategy.KeepDays); err == nil { + backupStrategy["keep_days"] = days + } + backupStrategyList[0] = backupStrategy + d.Set("backup_strategy", backupStrategyList) + + return nil +} + +func resourceGaussDBInstanceDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + client, err := config.initServiceClient("gaussdb", GetRegion(d, config), "mysql/v3") + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud GaussDB client: %s ", err) + } + + instanceId := d.Id() + result := instances.Delete(client, instanceId) + if result.Err != nil { + return CheckDeleted(d, result.Err, "GaussDB instance") + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{"ACTIVE", "BACKING UP", "FAILED"}, + Target: []string{"DELETED"}, + Refresh: GaussDBInstanceStateRefreshFunc(client, instanceId), + Timeout: d.Timeout(schema.TimeoutCreate), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + } + + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf( + "Error waiting for instance (%s) to be deleted: %s ", + instanceId, err) + } + log.Printf("[DEBUG] Successfully deleted instance %s", instanceId) + return nil +} diff --git a/huaweicloud/resource_huaweicloud_gaussdb_mysql_instance_test.go b/huaweicloud/resource_huaweicloud_gaussdb_mysql_instance_test.go new file mode 100644 index 0000000000..1af8f9cfdd --- /dev/null +++ b/huaweicloud/resource_huaweicloud_gaussdb_mysql_instance_test.go @@ -0,0 +1,101 @@ +package huaweicloud + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/huaweicloud/golangsdk/openstack/taurusdb/v3/instances" +) + +func TestGaussDBInstance_basic(t *testing.T) { + var instance instances.TaurusDBInstance + name := fmt.Sprintf("gauss-instance-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckGaussDBInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccGaussDBInstanceConfig_basic(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckGaussDBInstanceExists("huaweicloud_gaussdb_instance.instance_acc", &instance), + resource.TestCheckResourceAttr( + "huaweicloud_gaussdb_instance.instance_acc", "name", name), + ), + }, + }, + }) +} + +func testAccCheckGaussDBInstanceDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + client, err := config.initServiceClient("gaussdb", OS_REGION_NAME, "mysql/v3") + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud GaussDB client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "huaweicloud_gaussdb_instance" { + continue + } + + v, err := instances.Get(client, rs.Primary.ID).Extract() + if err == nil && v.Id == rs.Primary.ID { + return fmt.Errorf("Instance <%s> still exists.", rs.Primary.ID) + } + } + + return nil +} + +func testAccCheckGaussDBInstanceExists(n string, instance *instances.TaurusDBInstance) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s.", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set.") + } + + config := testAccProvider.Meta().(*Config) + client, err := config.initServiceClient("gaussdb", OS_REGION_NAME, "mysql/v3") + if err != nil { + return fmt.Errorf("Error creating HuaweiCloud GaussDB client: %s", err) + } + + found, err := instances.Get(client, rs.Primary.ID).Extract() + if err != nil { + return err + } + if found.Id != rs.Primary.ID { + return fmt.Errorf("Instance <%s> not found.", rs.Primary.ID) + } + instance = found + + return nil + } +} + +func testAccGaussDBInstanceConfig_basic(name string) string { + return fmt.Sprintf(` +resource "huaweicloud_networking_secgroup_v2" "secgroup_acc" { + name = "secgroup_acc" +} + +resource "huaweicloud_gaussdb_instance" "instance_acc" { + name = "%s" + password = "Test@123" + flavor = "gaussdb.mysql.4xlarge.x86.4" + vpc_id = "%s" + subnet_id = "%s" + security_group_id = huaweicloud_networking_secgroup_v2.secgroup_acc.id + enterprise_project_id = "0" +} +`, name, OS_VPC_ID, OS_NETWORK_ID) +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/client.go b/vendor/github.com/huaweicloud/golangsdk/openstack/client.go index 8c78dc534e..7c485b6fe0 100644 --- a/vendor/github.com/huaweicloud/golangsdk/openstack/client.go +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/client.go @@ -26,6 +26,9 @@ const ( // v3 represents Keystone v3. // The version can be anything from v3 to v3.x. v3 = "v3" + + // provider represents the suffix of endpoint url + provider = "myhuaweicloud.com" ) /* @@ -1119,3 +1122,18 @@ func NewGeminiDBV3(client *golangsdk.ProviderClient, eo golangsdk.EndpointOpts) return sc, nil } + +// InitServiceClientByName create a ServiceClient which was assembled by service and region name. +func InitServiceClientByName(client *golangsdk.ProviderClient, eo golangsdk.EndpointOpts, apiVersion string) (*golangsdk.ServiceClient, error) { + if eo.Name == "" || apiVersion == "" { + return nil, fmt.Errorf("must specify the service name and api version.") + } + + sc := new(golangsdk.ServiceClient) + sc.ProviderClient = client + sc.Endpoint = fmt.Sprintf("https://%s.%s.%s", eo.Name, eo.Region, provider) + sc.ResourceBase = fmt.Sprintf("%s/%s/%s/", sc.Endpoint, apiVersion, client.ProjectID) + + return sc, nil + +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/common/structs/structs.go b/vendor/github.com/huaweicloud/golangsdk/openstack/common/structs/structs.go new file mode 100644 index 0000000000..0cf460f6d7 --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/common/structs/structs.go @@ -0,0 +1,9 @@ +package structs + +type ChargeInfo struct { + ChargeMode string `json:"charge_mode" required:"true"` + PeriodType string `json:"period_type,omitempty"` + PeriodNum int `json:"period_num,omitempty"` + IsAutoRenew string `json:"is_auto_renew,omitempty"` + IsAutoPay string `json:"is_auto_pay,omitempty"` +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/taurusdb/v3/instances/requests.go b/vendor/github.com/huaweicloud/golangsdk/openstack/taurusdb/v3/instances/requests.go new file mode 100644 index 0000000000..049bf76a3c --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/taurusdb/v3/instances/requests.go @@ -0,0 +1,134 @@ +package instances + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/openstack/common/structs" + "github.com/huaweicloud/golangsdk/pagination" +) + +var requestOpts golangsdk.RequestOpts = golangsdk.RequestOpts{ + MoreHeaders: map[string]string{"Content-Type": "application/json", "X-Language": "en-us"}, +} + +type ChargeInfoOpt structs.ChargeInfo + +type DataStoreOpt struct { + Type string `json:"type" required:"true"` + Version string `json:"version" required:"true"` +} + +type BackupStrategyOpt struct { + StartTime string `json:"start_time" required:"true"` + KeepDays string `json:"keep_days" required:"true"` +} + +type CreateTaurusDBOpts struct { + Name string `json:"name" required:"true"` + Region string `json:"region" required:"true"` + Mode string `json:"mode" required:"true"` + Flavor string `json:"flavor_ref" required:"true"` + VpcId string `json:"vpc_id" required:"true"` + SubnetId string `json:"subnet_id" required:"true"` + SecurityGroupId string `json:"security_group_id" required:"true"` + Password string `json:"password" required:"true"` + TimeZone string `json:"time_zone" required:"true"` + AZMode string `json:"availability_zone_mode" required:"true"` + SlaveCount int `json:"slave_count" required:"true"` + MasterAZ string `json:"master_availability_zone,omitempty"` + ConfigurationId string `json:"configuration_id,omitempty"` + EnterpriseProjectId string `json:"enterprise_project_id,omitempty"` + DataStore DataStoreOpt `json:"datastore" required:"true"` + BackupStrategy *BackupStrategyOpt `json:"backup_strategy" required:"true"` + ChargeInfo *ChargeInfoOpt `json:"charge_info,omitempty"` +} + +type CreateTaurusDBBuilder interface { + ToInstancesCreateMap() (map[string]interface{}, error) +} + +func (opts CreateTaurusDBOpts) ToInstancesCreateMap() (map[string]interface{}, error) { + b, err := golangsdk.BuildRequestBody(opts, "") + if err != nil { + return nil, err + } + return b, nil +} + +func Create(client *golangsdk.ServiceClient, opts CreateTaurusDBBuilder) (r CreateResult) { + b, err := opts.ToInstancesCreateMap() + if err != nil { + r.Err = err + return + } + + _, r.Err = client.Post(createURL(client), b, &r.Body, &golangsdk.RequestOpts{ + OkCodes: []int{202}, + MoreHeaders: requestOpts.MoreHeaders, + }) + + return +} + +func Delete(client *golangsdk.ServiceClient, instanceId string) (r DeleteResult) { + url := deleteURL(client, instanceId) + + _, r.Err = client.Delete(url, &golangsdk.RequestOpts{ + OkCodes: []int{200, 202}, + MoreHeaders: requestOpts.MoreHeaders, + }) + + return +} + +func Get(client *golangsdk.ServiceClient, instanceId string) (r GetResult) { + url := getURL(client, instanceId) + + _, r.Err = client.Get(url, &r.Body, &golangsdk.RequestOpts{ + MoreHeaders: requestOpts.MoreHeaders, + }) + + return +} + +type ListTaurusDBInstanceOpts struct { + Id string `q:"id"` + Name string `q:"name"` + Type string `q:"type"` + DataStoreType string `q:"datastore_type"` + VpcId string `q:"vpc_id"` + SubnetId string `q:"subnet_id"` + Offset int `q:"offset"` + Limit int `q:"limit"` +} + +type ListTaurusDBBuilder interface { + ToTaurusDBListDetailQuery() (string, error) +} + +func (opts ListTaurusDBInstanceOpts) ToTaurusDBListDetailQuery() (string, error) { + q, err := golangsdk.BuildQueryString(opts) + if err != nil { + return "", err + } + return q.String(), err +} + +func List(client *golangsdk.ServiceClient, opts ListTaurusDBBuilder) pagination.Pager { + url := listURL(client) + if opts != nil { + query, err := opts.ToTaurusDBListDetailQuery() + + if err != nil { + return pagination.Pager{Err: err} + } + url += query + } + + pageList := pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { + return TaurusDBPage{pagination.SinglePageBase(r)} + }) + // Headers supplies additional HTTP headers to populate on each paged request + pageList.Headers = requestOpts.MoreHeaders + + return pageList +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/taurusdb/v3/instances/results.go b/vendor/github.com/huaweicloud/golangsdk/openstack/taurusdb/v3/instances/results.go new file mode 100644 index 0000000000..1d3fea30af --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/taurusdb/v3/instances/results.go @@ -0,0 +1,157 @@ +package instances + +import ( + "github.com/huaweicloud/golangsdk" + "github.com/huaweicloud/golangsdk/openstack/common/structs" + "github.com/huaweicloud/golangsdk/pagination" +) + +type DataStore struct { + Type string `json:"type" required:"true"` + Version string `json:"version" required:"true"` +} + +type BackupStrategy struct { + StartTime string `json:"start_time"` + KeepDays string `json:"keep_days"` +} + +type TaurusDBResponse struct { + Id string `json:"id"` + Name string `json:"name"` + Status string `json:"status"` + Region string `json:"region"` + Mode string `json:"mode"` + Port string `json:"port"` + VpcId string `json:"vpc_id"` + SubnetId string `json:"subnet_id"` + SecurityGroupId string `json:"security_group_id"` + ConfigurationId string `json:"configuration_id"` + AZMode string `json:"availability_zone_mode"` + MasterAZ string `json:"master_availability_zone"` + SlaveCount int `json:"slave_count"` + + DataStore DataStore `json:"datastore"` + BackupStrategy BackupStrategy `json:"backup_strategy"` + ChargeInfo structs.ChargeInfo `json:"charge_info"` + + EnterpriseProjectId string `json:"enterprise_project_id"` +} + +type CreateResponse struct { + Instance TaurusDBResponse `json:"instance"` + JobId string `json:"job_id"` + OrderId string `json:"order_id"` +} + +type TaurusDBInstance struct { + Id string `json:"id"` + Name string `json:"name"` + Status string `json:"status"` + Type string `json:"type"` + Port string `json:"port"` + NodeCount int `json:"node_count"` + VpcId string `json:"vpc_id"` + SubnetId string `json:"subnet_id"` + SecurityGroupId string `json:"security_group_id"` + ConfigurationId string `json:"configuration_id"` + AZMode string `json:"az_mode"` + MasterAZ string `json:"master_az_code"` + TimeZone string `json:"time_zone"` + ProjectId string `json:"project_id"` + DbUserName string `json:"db_user_name"` + PublicIps string `json:"public_ips"` + PrivateIps []string `json:"private_write_ips"` + Created string `json:"-"` + Updated string `json:"-"` + + Volume Volume `json:"volume"` + Nodes []Nodes `json:"nodes"` + DataStore DataStore `json:"datastore"` + BackupStrategy BackupStrategy `json:"backup_strategy"` + + EnterpriseProjectId string `json:"enterprise_project_id"` +} + +type Volume struct { + Type string `json:"type"` + Used string `json:"used"` +} + +type Nodes struct { + Id string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` + Status string `json:"status"` + PrivateIps []string `json:"private_read_ips"` + Port int `json:"port"` + Flavor string `json:"flavor_ref"` + Region string `json:"region_code"` + AvailabilityZone string `json:"az_code"` +} + +type commonResult struct { + golangsdk.Result +} + +type CreateResult struct { + commonResult +} + +func (r CreateResult) Extract() (*CreateResponse, error) { + var response CreateResponse + err := r.ExtractInto(&response) + return &response, err +} + +type DeleteResult struct { + commonResult +} + +type DeleteResponse struct { + JobId string `json:"job_id"` +} + +func (r DeleteResult) Extract() (*DeleteResponse, error) { + var response DeleteResponse + err := r.ExtractInto(&response) + return &response, err +} + +type GetResult struct { + commonResult +} + +func (r GetResult) Extract() (*TaurusDBInstance, error) { + var instance TaurusDBInstance + err := r.ExtractIntoStructPtr(&instance, "instance") + return &instance, err +} + +type ListTaurusDBResult struct { + commonResult +} + +type ListTaurusDBResponse struct { + Instances []TaurusDBInstance `json:"instances"` + TotalCount int `json:"total_count"` +} + +type TaurusDBPage struct { + pagination.SinglePageBase +} + +func (r TaurusDBPage) IsEmpty() (bool, error) { + data, err := ExtractTaurusDBInstances(r) + if err != nil { + return false, err + } + return len(data.Instances) == 0, err +} + +// ExtractTaurusDBInstances is a function that takes a ListResult and returns the services' information. +func ExtractTaurusDBInstances(r pagination.Page) (ListTaurusDBResponse, error) { + var s ListTaurusDBResponse + err := (r.(TaurusDBPage)).ExtractInto(&s) + return s, err +} diff --git a/vendor/github.com/huaweicloud/golangsdk/openstack/taurusdb/v3/instances/urls.go b/vendor/github.com/huaweicloud/golangsdk/openstack/taurusdb/v3/instances/urls.go new file mode 100644 index 0000000000..281da52e84 --- /dev/null +++ b/vendor/github.com/huaweicloud/golangsdk/openstack/taurusdb/v3/instances/urls.go @@ -0,0 +1,19 @@ +package instances + +import "github.com/huaweicloud/golangsdk" + +func createURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("instances") +} + +func deleteURL(c *golangsdk.ServiceClient, instanceID string) string { + return c.ServiceURL("instances", instanceID) +} + +func getURL(c *golangsdk.ServiceClient, instanceID string) string { + return c.ServiceURL("instances", instanceID) +} + +func listURL(c *golangsdk.ServiceClient) string { + return c.ServiceURL("instances") +} diff --git a/vendor/modules.txt b/vendor/modules.txt index f5b116f56f..814341736f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -182,7 +182,7 @@ github.com/hashicorp/terraform-svchost github.com/hashicorp/terraform-svchost/auth # github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d github.com/hashicorp/yamux -# github.com/huaweicloud/golangsdk v0.0.0-20200619095000-03444f871c13 +# github.com/huaweicloud/golangsdk v0.0.0-20200630015217-45223898b76a github.com/huaweicloud/golangsdk github.com/huaweicloud/golangsdk/openstack github.com/huaweicloud/golangsdk/openstack/antiddos/v1/antiddos @@ -304,6 +304,7 @@ github.com/huaweicloud/golangsdk/openstack/rts/v1/stacktemplates github.com/huaweicloud/golangsdk/openstack/sfs/v2/shares github.com/huaweicloud/golangsdk/openstack/smn/v2/subscriptions github.com/huaweicloud/golangsdk/openstack/smn/v2/topics +github.com/huaweicloud/golangsdk/openstack/taurusdb/v3/instances github.com/huaweicloud/golangsdk/openstack/vbs/v2/backups github.com/huaweicloud/golangsdk/openstack/vbs/v2/policies github.com/huaweicloud/golangsdk/openstack/vbs/v2/tags @@ -314,6 +315,7 @@ github.com/huaweicloud/golangsdk/openstack/identity/v3/services github.com/huaweicloud/golangsdk/openstack/identity/v3/tokens github.com/huaweicloud/golangsdk/openstack/utils github.com/huaweicloud/golangsdk/internal +github.com/huaweicloud/golangsdk/openstack/common/structs github.com/huaweicloud/golangsdk/openstack/identity/v2/tenants # github.com/jen20/awspolicyequivalence v0.0.0-20170831201602-3d48364a137a github.com/jen20/awspolicyequivalence diff --git a/website/docs/r/gaussdb_instance.html.markdown b/website/docs/r/gaussdb_instance.html.markdown new file mode 100644 index 0000000000..cfbc411722 --- /dev/null +++ b/website/docs/r/gaussdb_instance.html.markdown @@ -0,0 +1,139 @@ +--- +layout: "huaweicloud" +page_title: "HuaweiCloud: huaweicloud_gaussdb_instance" +sidebar_current: "docs-huaweicloud-resource-gaussdb-instance" +description: |- + GaussDB instance management +--- + +# huaweicloud\_gaussdb\_instance + +GaussDB instance management within HuaweiCoud. + +## Example Usage + +### create a basic instance + +```hcl +resource "huaweicloud_gaussdb_instance" "instance_1" { + name = "gaussdb_instance_1" + password = var.password + flavor = "gaussdb.mysql.4xlarge.x86.4" + vpc_id = var.vpc_id + subnet_id = var.subnet_id + security_group_id = var.secgroup_id +} +``` + +### create a gaussdb instance with backup strategy + +```hcl +resource "huaweicloud_gaussdb_instance" "instance_1" { + name = "gaussdb_instance_1" + password = var.password + flavor = "gaussdb.mysql.4xlarge.x86.4" + vpc_id = var.vpc_id + subnet_id = var.subnet_id + security_group_id = var.secgroup_id + + backup_strategy { + start_time = "03:00-04:00" + keep_days = 7 + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) Specifies the instance name, which can be the same + as an existing instance name. The value must be 4 to 64 characters in + length and start with a letter. It is case-sensitive and can contain + only letters, digits, hyphens (-), and underscores (_). + Changing this parameter will create a new resource. + +* `flavor` - (Required) Specifies the instance specifications. Currently, + “gaussdb.mysql.4xlarge.x86.4”, "gaussdb.mysql.8xlarge.x86.4" and "gaussdb.mysql.16xlarge.x86.4" + are available. Changing this parameter will create a new resource. + +* `password` - (Required) Specifies the database password. The value must be 8 to 32 characters + in length, including uppercase and lowercase letters, digits, and special characters, + such as ~!@#%^*-_=+? + + You are advised to enter a strong password to improve security, preventing security risks + such as brute force cracking. + Changing this parameter will create a new resource. + +* `vpc_id` - (Required) Specifies the VPC ID. + Changing this parameter will create a new resource. + +* `subnet_id` - (Required) Specifies the network ID of a subnet. + Changing this parameter will create a new resource. + +* `security_group_id` - (Required) Specifies the security group ID. + Changing this parameter will create a new resource. + +* `enterprise_project_id` - (Optional) The enterprise project id. + Changing this parameter will create a new resource. + +* `read_replicas` - (Optional) Specifies the count of read replicas. Defaults to 1. + Changing this parameter will create a new resource. + +* `time_zone` - (Optional) Specifies the time zone. Defaults to "UTC+08:00". + Changing this parameter will create a new resource. + +* `datastore` - (Optional) Specifies the database information. Structure is documented below. + Changing this parameter will create a new resource. + +* `backup_strategy` - (Optional) Specifies the advanced backup policy. Structure is documented below. + Changing this parameter will create a new resource. + +The `datastore` block supports: + +* `engine` - (Optional) Specifies the database engine. Only "gauss-mysql" is supported now. + +* `version` - (Optional) Specifies the database version. Only "8.0" is supported now. + + +The `backup_strategy` block supports: + +* `start_time` - (Required) Specifies the backup time window. Automated backups + will be triggered during the backup time window. It must be a valid value in + the "hh:mm-HH:MM" format. The current time is in the UTC format. + The HH value must be 1 greater than the hh value. The values of mm and MM + must be the same and must be set to 00. Example value: 08:00-09:00, 03:00-04:00. + +* `keep_days` - (Optional) Specifies the number of days to retain the generated + backup files. The value ranges from 0 to 35. + If this parameter is set to 0, the automated backup policy is not set. + If this parameter is not transferred, the automated backup policy is enabled by default. + Backup files are stored for seven days by default. + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + +* `status` - Indicates the DB instance status. +* `region` - Indicates the region where the DB instance is deployed. +* `port` - Indicates the database port. +* `mode` - Indicates the instance mode. +* `db_user_name` - Indicates the default username. +* `private_write_ip` - Indicates the private IP address of the DB instance. +* `nodes` - Indicates the instance nodes information. Structure is documented below. + +The `nodes` block contains: + +- `id` - Indicates the node ID. +- `name` - Indicates the node name. +- `type` - Indicates the node type: master or slave. +- `status` - Indicates the node status. +- `private_read_ip` - Indicates the private IP address of a node. + +## Import + +GaussDB instance can be imported using the `id`, e.g. + +``` +$ terraform import huaweicloud_gaussdb_instance.instance_1 ee678f40-ce8e-4d0c-8221-38dead426f06 +``` diff --git a/website/huaweicloud.erb b/website/huaweicloud.erb index 7c1fe2dff7..1dedea2643 100644 --- a/website/huaweicloud.erb +++ b/website/huaweicloud.erb @@ -543,6 +543,20 @@ +
  • + GaussDB + +
  • +
  • GeminiDB