backend/remote-state/oss: Fix state locking by using LockID as PK
This commit is contained in:
parent
b4a735779c
commit
6bb22907a1
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue