Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
小 白蛋
Terraform
Commits
e6cd3fca
Commit
e6cd3fca
authored
4 years ago
by
Rémi Lapeyre
Browse files
Options
Download
Email Patches
Plain Diff
backport of commit
5f444a68
parent
d76c5e6f
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
internal/backend/remote-state/consul/client.go
+72
-52
internal/backend/remote-state/consul/client.go
with
72 additions
and
52 deletions
+72
-52
internal/backend/remote-state/consul/client.go
+
72
-
52
View file @
e6cd3fca
...
...
@@ -198,72 +198,92 @@ func (c *RemoteClient) Put(data []byte) error {
verb
=
consulapi
.
KVSet
}
// If the payload is too large we first write the chunks and replace it
// 524288 is the default value, we just hope the user did not set a smaller
// one but there is really no reason for them to do so, if they changed it
// it is certainly to set a larger value.
limit
:=
524288
if
len
(
payload
)
>
limit
{
md5
:=
md5
.
Sum
(
data
)
chunks
:=
split
(
payload
,
limit
)
chunkPaths
:=
make
([]
string
,
0
)
// First we write the new chunks
for
i
,
p
:=
range
chunks
{
path
:=
strings
.
TrimRight
(
c
.
Path
,
"/"
)
+
fmt
.
Sprintf
(
"/tfstate.%x/%d"
,
md5
,
i
)
chunkPaths
=
append
(
chunkPaths
,
path
)
_
,
err
:=
kv
.
Put
(
&
consulapi
.
KVPair
{
Key
:
path
,
Value
:
p
,
},
nil
)
if
err
!=
nil
{
return
err
}
// The payload may be too large to store in a single KV entry in Consul. We
// could try to determine whether it will fit or not before sending the
// request but since we are using the Transaction API and not the KV API,
// it grows by about a 1/3 when it is base64 encoded plus the overhead of
// the fields specific to the Transaction API.
// Rather than trying to calculate the overhead (which could change from
// one version of Consul to another, and between Consul Community Edition
// and Consul Enterprise), we try to send the whole state in one request, if
// it fails because it is too big we then split it in chunks and send each
// chunk separately.
// When splitting in chunks, we make each chunk 524288 bits, which is the
// default max size for raft. If the user changed it, we still may send
// chunks too big and fail but this is not a setting that should be fiddled
// with anyway.
store
:=
func
(
payload
[]
byte
)
error
{
// KV.Put doesn't return the new index, so we use a single operation
// transaction to get the new index with a single request.
txOps
:=
consulapi
.
KVTxnOps
{
&
consulapi
.
KVTxnOp
{
Verb
:
verb
,
Key
:
c
.
Path
,
Value
:
payload
,
Index
:
c
.
modifyIndex
,
},
}
// We update the link to point to the new chunks
payload
,
err
=
json
.
Marshal
(
map
[
string
]
interface
{}{
"current-hash"
:
fmt
.
Sprintf
(
"%x"
,
md5
),
"chunks"
:
chunkPaths
,
})
ok
,
resp
,
_
,
err
:=
kv
.
Txn
(
txOps
,
nil
)
if
err
!=
nil
{
return
err
}
}
// transaction was rolled back
if
!
ok
{
return
fmt
.
Errorf
(
"consul CAS failed with transaction errors: %v"
,
resp
.
Errors
)
}
var
txOps
consulapi
.
KVTxnOps
// KV.Put doesn't return the new index, so we use a single operation
// transaction to get the new index with a single request.
txOps
=
consulapi
.
KVTxnOps
{
&
consulapi
.
KVTxnOp
{
Verb
:
verb
,
Key
:
c
.
Path
,
Value
:
payload
,
Index
:
c
.
modifyIndex
,
},
if
len
(
resp
.
Results
)
!=
1
{
// this probably shouldn't happen
return
fmt
.
Errorf
(
"expected on 1 response value, got: %d"
,
len
(
resp
.
Results
))
}
c
.
modifyIndex
=
resp
.
Results
[
0
]
.
ModifyIndex
// We remove all the old chunks
cleanupOldChunks
()
return
nil
}
ok
,
resp
,
_
,
err
:=
kv
.
Txn
(
txOps
,
nil
)
if
err
!=
nil
{
if
err
=
store
(
payload
);
err
==
nil
{
// The payload was small enough to be stored
return
nil
}
else
if
!
strings
.
Contains
(
err
.
Error
(),
"too large"
)
{
// We failed for some other reason, report this to the user
return
err
}
// transaction was rolled back
if
!
ok
{
return
fmt
.
Errorf
(
"consul CAS failed with transaction errors: %v"
,
resp
.
Errors
)
}
if
len
(
resp
.
Results
)
!=
1
{
// this probably shouldn't happen
return
fmt
.
Errorf
(
"expected on 1 response value, got: %d"
,
len
(
resp
.
Results
))
}
// The payload was too large so we split it in multiple chunks
c
.
modifyIndex
=
resp
.
Results
[
0
]
.
ModifyIndex
md5
:=
md5
.
Sum
(
data
)
chunks
:=
split
(
payload
,
524288
)
chunkPaths
:=
make
([]
string
,
0
)
// We remove all the old chunks
cleanupOldChunks
()
// First we write the new chunks
for
i
,
p
:=
range
chunks
{
path
:=
strings
.
TrimRight
(
c
.
Path
,
"/"
)
+
fmt
.
Sprintf
(
"/tfstate.%x/%d"
,
md5
,
i
)
chunkPaths
=
append
(
chunkPaths
,
path
)
_
,
err
:=
kv
.
Put
(
&
consulapi
.
KVPair
{
Key
:
path
,
Value
:
p
,
},
nil
)
return
nil
if
err
!=
nil
{
return
err
}
}
// Then we update the link to point to the new chunks
payload
,
err
=
json
.
Marshal
(
map
[
string
]
interface
{}{
"current-hash"
:
fmt
.
Sprintf
(
"%x"
,
md5
),
"chunks"
:
chunkPaths
,
})
if
err
!=
nil
{
return
err
}
return
store
(
payload
)
}
func
(
c
*
RemoteClient
)
Delete
()
error
{
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment