alicloud/resource_alicloud_ots_secondary_index.go (262 lines of code) (raw):

package alicloud import ( "fmt" "strings" "time" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "github.com/aliyun/aliyun-tablestore-go-sdk/tablestore" "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" ) func resourceAlicloudOtsSecondaryIndex() *schema.Resource { return &schema.Resource{ Create: resourceAliyunOtsSecondaryIndexCreate, Read: resourceAliyunOtsSecondaryIndexRead, Delete: resourceAliyunOtsSecondaryIndexDelete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, Schema: map[string]*schema.Schema{ "instance_name": { Type: schema.TypeString, Required: true, ForceNew: true, ValidateFunc: validateOTSInstanceName, }, "table_name": { Type: schema.TypeString, Required: true, ForceNew: true, ValidateFunc: validateOTSTableName, }, "index_name": { Type: schema.TypeString, Required: true, ForceNew: true, ValidateFunc: validateOTSIndexName, }, "index_type": { Type: schema.TypeString, Required: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ string(Local), string(Global)}, false), }, "include_base_data": { Type: schema.TypeBool, Required: true, ForceNew: true, }, "primary_keys": { Type: schema.TypeList, Required: true, ForceNew: true, Elem: &schema.Schema{ Type: schema.TypeString, }, MinItems: 1, MaxItems: 4, }, "defined_columns": { Type: schema.TypeList, Optional: true, ForceNew: true, Elem: &schema.Schema{ Type: schema.TypeString, }, MaxItems: 32, }, }, } } func parseArgs(d *schema.ResourceData) *SecIndexResourceArgs { args := &SecIndexResourceArgs{ instanceName: d.Get("instance_name").(string), tableName: d.Get("table_name").(string), includeBaseData: d.Get("include_base_data").(bool), indexName: d.Get("index_name").(string), indexType: SecondaryIndexTypeString(d.Get("index_type").(string)), primaryKeys: Unique(Interface2StrSlice(d.Get("primary_keys").([]interface{}))), } if v, ok := d.GetOk("defined_columns"); ok && len(v.([]interface{})) > 0 { args.definedColumns = Unique(Interface2StrSlice(v.([]interface{}))) } return args } type SecIndexResourceArgs struct { instanceName string tableName string includeBaseData bool indexName string indexType SecondaryIndexTypeString primaryKeys []string definedColumns []string } func resourceAliyunOtsSecondaryIndexCreate(d *schema.ResourceData, meta interface{}) error { args := parseArgs(d) client := meta.(*connectivity.AliyunClient) otsService := OtsService{client} // check table exists tableResp, err := otsService.LoopWaitTable(args.instanceName, args.tableName) if err != nil { return WrapError(err) } // serverside arguments check if err := checkArgs(tableResp, args); err != nil { return err } // build request idxType, err := ConvertSecIndexTypeString(args.indexType) if err != nil { return WrapError(err) } req := &tablestore.CreateIndexRequest{ MainTableName: args.tableName, IncludeBaseData: args.includeBaseData, IndexMeta: &tablestore.IndexMeta{ IndexName: args.indexName, Primarykey: args.primaryKeys, IndexType: idxType, DefinedColumns: args.definedColumns, }, } var reqClient *tablestore.TableStoreClient if err := resource.Retry(2*time.Minute, func() *resource.RetryError { raw, err := client.WithTableStoreClient(args.instanceName, func(tableStoreClient *tablestore.TableStoreClient) (interface{}, error) { reqClient = tableStoreClient return tableStoreClient.CreateIndex(req) }) defer func() { addDebug("CreateTableSecondaryIndex", raw, reqClient, req) }() if err != nil { if IsExpectedErrors(err, OtsSecondaryIndexIsTemporarilyUnavailable) { return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }); err != nil { return WrapErrorf(err, DefaultErrorMsg, "alicloud_ots_secondary_index", "CreateIndex", AliyunTablestoreGoSdk) } d.SetId(ID(args.instanceName, args.tableName, args.indexName, string(args.indexType))) return resourceAliyunOtsSecondaryIndexRead(d, meta) } func checkArgs(tableResp *tablestore.DescribeTableResponse, args *SecIndexResourceArgs) error { dataPks := simplifyPK(tableResp.TableMeta.SchemaEntry) dataCols := simplifyCol(tableResp.TableMeta.DefinedColumns) allCards := append(dataPks, dataCols...) if !IsSubCollection(args.primaryKeys, allCards) { return WrapError(fmt.Errorf("some primary keys not exist in table: %s/%s", args.primaryKeys, args.tableName)) } if !IsSubCollection(args.definedColumns, allCards) { return WrapError(fmt.Errorf("some defined columns not exist in table: %s/%s", args.definedColumns, args.tableName)) } if args.indexName == args.tableName { return WrapError(fmt.Errorf("index name cannot be the same as table: %s/%s", args.indexName, args.tableName)) } if args.indexType == Local && args.primaryKeys[0] != dataPks[0] { return WrapError(fmt.Errorf("when using a local secondary index, the first primary key of the index must be "+ "the same as the first primary key of the data table: %s/%s", args.primaryKeys, dataPks)) } if tableResp.TableOption.TimeToAlive != -1 { return WrapError(fmt.Errorf("when creating a secondary index, the TimeToAlive of the table must be -1: %v", tableResp.TableOption.TimeToAlive)) } if tableResp.TableOption.MaxVersion != 1 { return WrapError(fmt.Errorf("when creating a secondary index, the table's MaxVersion must be 1: %v", tableResp.TableOption.MaxVersion)) } return nil } func simplifyPK(keys []*tablestore.PrimaryKeySchema) []string { var pks = make([]string, 0, len(keys)) for _, key := range keys { pks = append(pks, *key.Name) } return pks } func simplifyCol(columns []*tablestore.DefinedColumnSchema) []string { var cols = make([]string, 0, len(columns)) for _, col := range columns { cols = append(cols, col.Name) } return cols } func simplifySecIndex(indexes []*tablestore.IndexMeta) []string { var ii = make([]string, 0, len(indexes)) for _, idx := range indexes { ii = append(ii, idx.IndexName) } return ii } func resourceAliyunOtsSecondaryIndexRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AliyunClient) otsService := OtsService{client} idx, err := otsService.DescribeOtsSecondaryIndex(d.Id()) if err != nil { if NotFoundError(err) { return nil } return WrapError(err) } if idx == nil { d.SetId("") return nil } if err := d.Set("instance_name", idx.InstanceName); err != nil { return WrapError(err) } if err := d.Set("table_name", idx.TableName); err != nil { return WrapError(err) } if err := d.Set("index_name", idx.Index.IndexName); err != nil { return WrapError(err) } indexType, err := ConvertSecIndexType(idx.Index.IndexType) if err != nil { return WrapError(err) } if err := d.Set("index_type", string(indexType)); err != nil { return WrapError(err) } if err := d.Set("primary_keys", idx.Index.Primarykey); err != nil { return WrapError(err) } if err := d.Set("defined_columns", idx.Index.DefinedColumns); err != nil { return WrapError(err) } return nil } func resourceAliyunOtsSecondaryIndexDelete(d *schema.ResourceData, meta interface{}) error { instanceName, tableName, indexName, _, err := ParseIndexId(d.Id()) if err != nil { return WrapError(err) } client := meta.(*connectivity.AliyunClient) req := &tablestore.DeleteIndexRequest{ MainTableName: tableName, IndexName: indexName, } err = resource.Retry(2*time.Minute, func() *resource.RetryError { var requestInfo *tablestore.TableStoreClient raw, err := client.WithTableStoreClient(instanceName, func(tableStoreClient *tablestore.TableStoreClient) (interface{}, error) { requestInfo = tableStoreClient return tableStoreClient.DeleteIndex(req) }) defer func() { addDebug("DeleteTableSecondaryIndex", raw, requestInfo, req) }() if err != nil { if IsExpectedErrors(err, OtsTableIsTemporarilyUnavailable) { return resource.RetryableError(err) } return resource.NonRetryableError(err) } return nil }) if err != nil { if strings.HasPrefix(err.Error(), "OTSObjectNotExist") { return nil } return WrapErrorf(err, DefaultErrorMsg, d.Id(), "DeleteTableSecondaryIndex", AliyunTablestoreGoSdk) } otsService := OtsService{client} return WrapError(otsService.WaitForSecondaryIndex(instanceName, tableName, indexName, Deleted, DefaultTimeout)) }