backend/remote-state/oss: Fix state locking by using LockID as PK

This commit is contained in:
Mathias Lafeldt 2020-02-18 14:45:06 +01:00
parent b4a735779c
commit 6bb22907a1
No known key found for this signature in database
GPG Key ID: 15F939C6FE84FECF
3 changed files with 17 additions and 66 deletions

View File

@ -39,28 +39,12 @@ func (b *Backend) remoteClient(name string) (*RemoteClient, error) {
otsClient: b.otsClient, otsClient: b.otsClient,
} }
if b.otsEndpoint != "" && b.otsTable != "" { if b.otsEndpoint != "" && b.otsTable != "" {
table, err := b.otsClient.DescribeTable(&tablestore.DescribeTableRequest{ _, err := b.otsClient.DescribeTable(&tablestore.DescribeTableRequest{
TableName: b.otsTable, TableName: b.otsTable,
}) })
if err != nil { if err != nil {
return client, fmt.Errorf("Error describing table store %s: %#v", b.otsTable, err) return client, fmt.Errorf("Error describing table store %s: %#v", b.otsTable, err)
} }
for _, t := range table.TableMeta.SchemaEntry {
pkMeta := TableStorePrimaryKeyMeta{
PKName: *t.Name,
}
if *t.Type == tablestore.PrimaryKeyType_INTEGER {
pkMeta.PKType = "Integer"
} else if *t.Type == tablestore.PrimaryKeyType_STRING {
pkMeta.PKType = "String"
} else if *t.Type == tablestore.PrimaryKeyType_BINARY {
pkMeta.PKType = "Binary"
} else {
return client, fmt.Errorf("Unsupported PrimaryKey type: %d.", *t.Type)
}
client.otsTabkePK = pkMeta
break
}
} }
return client, nil return client, nil

View File

@ -177,11 +177,11 @@ func deleteOSSBucket(t *testing.T, ossClient *oss.Client, bucketName string) {
} }
} }
// create the dynamoDB table, and wait until we can query it. // create the tablestore table, and wait until we can query it.
func createTablestoreTable(t *testing.T, otsClient *tablestore.TableStoreClient, tableName string) { func createTablestoreTable(t *testing.T, otsClient *tablestore.TableStoreClient, tableName string) {
tableMeta := new(tablestore.TableMeta) tableMeta := new(tablestore.TableMeta)
tableMeta.TableName = tableName tableMeta.TableName = tableName
tableMeta.AddPrimaryKeyColumn("testbackend", tablestore.PrimaryKeyType_STRING) tableMeta.AddPrimaryKeyColumn("LockID", tablestore.PrimaryKeyType_STRING)
tableOption := new(tablestore.TableOption) tableOption := new(tablestore.TableOption)
tableOption.TimeToAlive = -1 tableOption.TimeToAlive = -1

View File

@ -16,7 +16,6 @@ import (
"github.com/aliyun/aliyun-tablestore-go-sdk/tablestore" "github.com/aliyun/aliyun-tablestore-go-sdk/tablestore"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
uuid "github.com/hashicorp/go-uuid" uuid "github.com/hashicorp/go-uuid"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/state" "github.com/hashicorp/terraform/state"
"github.com/hashicorp/terraform/state/remote" "github.com/hashicorp/terraform/state/remote"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -25,7 +24,6 @@ import (
// Store the last saved serial in tablestore with this suffix for consistency checks. // Store the last saved serial in tablestore with this suffix for consistency checks.
const ( const (
stateIDSuffix = "-md5" stateIDSuffix = "-md5"
statePKValue = "terraform-remote-state-lock"
) )
var ( var (
@ -40,11 +38,6 @@ var (
// test hook called when checksums don't match // test hook called when checksums don't match
var testChecksumHook func() var testChecksumHook func()
type TableStorePrimaryKeyMeta struct {
PKName string
PKType string
}
type RemoteClient struct { type RemoteClient struct {
ossClient *oss.Client ossClient *oss.Client
otsClient *tablestore.TableStoreClient otsClient *tablestore.TableStoreClient
@ -56,7 +49,6 @@ type RemoteClient struct {
info *state.LockInfo info *state.LockInfo
mu sync.Mutex mu sync.Mutex
otsTable string otsTable string
otsTabkePK TableStorePrimaryKeyMeta
} }
func (c *RemoteClient) Get() (payload *remote.Payload, err error) { func (c *RemoteClient) Get() (payload *remote.Payload, err error) {
@ -173,16 +165,12 @@ func (c *RemoteClient) Lock(info *state.LockInfo) (string, error) {
PrimaryKey: &tablestore.PrimaryKey{ PrimaryKey: &tablestore.PrimaryKey{
PrimaryKeys: []*tablestore.PrimaryKeyColumn{ PrimaryKeys: []*tablestore.PrimaryKeyColumn{
{ {
ColumnName: c.otsTabkePK.PKName, ColumnName: "LockID",
Value: c.getPKValue(), Value: c.lockPath(),
}, },
}, },
}, },
Columns: []tablestore.AttributeColumn{ Columns: []tablestore.AttributeColumn{
{
ColumnName: "LockID",
Value: c.lockPath(),
},
{ {
ColumnName: "Info", ColumnName: "Info",
Value: string(info.Marshal()), Value: string(info.Marshal()),
@ -193,7 +181,7 @@ func (c *RemoteClient) Lock(info *state.LockInfo) (string, error) {
}, },
} }
log.Printf("[DEBUG] Recoring state lock in tablestore: %#v", putParams) log.Printf("[DEBUG] Recording state lock in tablestore: %#v", putParams)
_, err := c.otsClient.PutRow(&tablestore.PutRowRequest{ _, err := c.otsClient.PutRow(&tablestore.PutRowRequest{
PutRowChange: putParams, PutRowChange: putParams,
@ -226,8 +214,8 @@ func (c *RemoteClient) getMD5() ([]byte, error) {
PrimaryKey: &tablestore.PrimaryKey{ PrimaryKey: &tablestore.PrimaryKey{
PrimaryKeys: []*tablestore.PrimaryKeyColumn{ PrimaryKeys: []*tablestore.PrimaryKeyColumn{
{ {
ColumnName: c.otsTabkePK.PKName, ColumnName: "LockID",
Value: c.getPKValue(), Value: c.lockPath() + stateIDSuffix,
}, },
}, },
}, },
@ -273,23 +261,19 @@ func (c *RemoteClient) putMD5(sum []byte) error {
PrimaryKey: &tablestore.PrimaryKey{ PrimaryKey: &tablestore.PrimaryKey{
PrimaryKeys: []*tablestore.PrimaryKeyColumn{ PrimaryKeys: []*tablestore.PrimaryKeyColumn{
{ {
ColumnName: c.otsTabkePK.PKName, ColumnName: "LockID",
Value: c.getPKValue(), Value: c.lockPath() + stateIDSuffix,
}, },
}, },
}, },
Columns: []tablestore.AttributeColumn{ Columns: []tablestore.AttributeColumn{
{
ColumnName: "LockID",
Value: c.lockPath() + stateIDSuffix,
},
{ {
ColumnName: "Digest", ColumnName: "Digest",
Value: hex.EncodeToString(sum), Value: hex.EncodeToString(sum),
}, },
}, },
Condition: &tablestore.RowCondition{ Condition: &tablestore.RowCondition{
RowExistenceExpectation: tablestore.RowExistenceExpectation_EXPECT_NOT_EXIST, RowExistenceExpectation: tablestore.RowExistenceExpectation_IGNORE,
}, },
} }
@ -318,8 +302,8 @@ func (c *RemoteClient) deleteMD5() error {
PrimaryKey: &tablestore.PrimaryKey{ PrimaryKey: &tablestore.PrimaryKey{
PrimaryKeys: []*tablestore.PrimaryKeyColumn{ PrimaryKeys: []*tablestore.PrimaryKeyColumn{
{ {
ColumnName: c.otsTabkePK.PKName, ColumnName: "LockID",
Value: c.getPKValue(), Value: c.lockPath() + stateIDSuffix,
}, },
}, },
}, },
@ -344,8 +328,8 @@ func (c *RemoteClient) getLockInfo() (*state.LockInfo, error) {
PrimaryKey: &tablestore.PrimaryKey{ PrimaryKey: &tablestore.PrimaryKey{
PrimaryKeys: []*tablestore.PrimaryKeyColumn{ PrimaryKeys: []*tablestore.PrimaryKeyColumn{
{ {
ColumnName: c.otsTabkePK.PKName, ColumnName: "LockID",
Value: c.getPKValue(), Value: c.lockPath(),
}, },
}, },
}, },
@ -397,8 +381,8 @@ func (c *RemoteClient) Unlock(id string) error {
PrimaryKey: &tablestore.PrimaryKey{ PrimaryKey: &tablestore.PrimaryKey{
PrimaryKeys: []*tablestore.PrimaryKeyColumn{ PrimaryKeys: []*tablestore.PrimaryKeyColumn{
{ {
ColumnName: c.otsTabkePK.PKName, ColumnName: "LockID",
Value: c.getPKValue(), Value: c.lockPath(),
}, },
}, },
}, },
@ -460,23 +444,6 @@ func (c *RemoteClient) getObj() (*remote.Payload, error) {
return payload, nil return payload, nil
} }
func (c *RemoteClient) getPKValue() (value interface{}) {
value = statePKValue
if c.otsTabkePK.PKType == "Integer" {
value = hashcode.String(statePKValue)
} else if c.otsTabkePK.PKType == "Binary" {
value = stringToBin(statePKValue)
}
return
}
func stringToBin(s string) (binString string) {
for _, c := range s {
binString = fmt.Sprintf("%s%b", binString, c)
}
return
}
const errBadChecksumFmt = `state data in OSS does not have the expected content. const errBadChecksumFmt = `state data in OSS does not have the expected content.
This may be caused by unusually long delays in OSS processing a previous state This may be caused by unusually long delays in OSS processing a previous state