@@ -30,6 +30,7 @@ const (
3030 tfstateWorkspaceKey = "tfstateWorkspace"
3131 tfstateLockInfoAnnotation = "app.terraform.io/lock-info"
3232 managedByKey = "app.kubernetes.io/managed-by"
33+ etcdDefaultSize = 1048576
3334)
3435
3536type RemoteClient struct {
@@ -42,28 +43,27 @@ type RemoteClient struct {
4243}
4344
4445func (c * RemoteClient ) Get () (payload * remote.Payload , err error ) {
45- secretName , err := c .createSecretName ()
46+ secretList , err := c .getSecrets ()
4647 if err != nil {
4748 return nil , err
4849 }
49- secret , err := c .kubernetesSecretClient .Get (secretName , metav1.GetOptions {})
50- if err != nil {
51- if k8serrors .IsNotFound (err ) {
52- return nil , nil
53- }
54- return nil , err
55- }
5650
57- secretData := getSecretData (secret )
58- stateRaw , ok := secretData [tfstateKey ]
59- if ! ok {
60- // The secret exists but there is no state in it
51+ if len (secretList .Items ) == 0 {
6152 return nil , nil
6253 }
6354
64- stateRawString := stateRaw .(string )
55+ var data []string
56+ for _ , secret := range secretList .Items {
57+ secretData := getSecretData (& secret )
58+ stateRaw , ok := secretData [tfstateKey ]
59+ if ! ok {
60+ // The secret exists but there is no state in it
61+ return nil , nil
62+ }
63+ data = append (data , stateRaw .(string ))
64+ }
6565
66- state , err := uncompressState (stateRawString )
66+ state , err := uncompressState (data )
6767 if err != nil {
6868 return nil , err
6969 }
@@ -77,8 +77,18 @@ func (c *RemoteClient) Get() (payload *remote.Payload, err error) {
7777 return p , nil
7878}
7979
80+ func multiSecret (size []byte ) bool {
81+ // by default etcd can hold up to 1.5Mib data for secret
82+ return len (size ) > etcdDefaultSize
83+ }
84+
85+ func (c * RemoteClient ) getSecrets () (* unstructured.UnstructuredList , error ) {
86+ ls := metav1 .SetAsLabelSelector (c .getLabels ())
87+ return c .kubernetesSecretClient .List (metav1.ListOptions {LabelSelector : metav1 .FormatLabelSelector (ls )})
88+ }
89+
8090func (c * RemoteClient ) Put (data []byte ) error {
81- secretName , err := c .createSecretName ()
91+ secretName , err := c .createSecretName (0 )
8292 if err != nil {
8393 return err
8494 }
@@ -88,46 +98,90 @@ func (c *RemoteClient) Put(data []byte) error {
8898 return err
8999 }
90100
91- secret , err := c .getSecret (secretName )
101+ parts := split (payload , etcdDefaultSize )
102+ existingSecrets , err := c .getSecrets ()
92103 if err != nil {
93- if ! k8serrors .IsNotFound (err ) {
94- return err
95- }
104+ return err
105+ }
96106
97- secret = & unstructured.Unstructured {
98- Object : map [string ]interface {}{
99- "metadata" : metav1.ObjectMeta {
100- Name : secretName ,
101- Namespace : c .namespace ,
102- Labels : c .getLabels (),
103- Annotations : map [string ]string {"encoding" : "gzip" },
104- },
105- },
107+ for idx , data := range parts {
108+ secretName , err := c .createSecretName (idx )
109+ if err != nil {
110+ return err
106111 }
107112
108- secret , err = c .kubernetesSecretClient . Create ( secret , metav1. CreateOptions {} )
113+ secret , err : = c .getSecret ( secretName )
109114 if err != nil {
110- return err
115+ if ! k8serrors .IsNotFound (err ) {
116+ return err
117+ }
118+
119+ secret = c .formatSecret (secretName )
120+
121+ secret , err = c .kubernetesSecretClient .Create (secret , metav1.CreateOptions {})
122+ if err != nil {
123+ return err
124+ }
111125 }
126+
127+ setState (secret , data )
128+ _ , err = c .kubernetesSecretClient .Update (secret , metav1.UpdateOptions {})
112129 }
113130
114- setState (secret , payload )
115- _ , err = c .kubernetesSecretClient .Update (secret , metav1.UpdateOptions {})
131+ // in case new state requires less secrets, cleanup old secrets
132+ secretNum := len (existingSecrets .Items )
133+ newSecretNum := len (parts )
134+ for i := newSecretNum ; i <= secretNum ; i ++ {
135+ c .deleteSecret (fmt .Sprintf ("%s-part%d" , secretName , i ))
136+ }
116137 return err
117138}
118139
140+ func (c * RemoteClient ) formatSecret (name string ) * unstructured.Unstructured {
141+ return & unstructured.Unstructured {
142+ Object : map [string ]interface {}{
143+ "metadata" : metav1.ObjectMeta {
144+ Name : name ,
145+ Namespace : c .namespace ,
146+ Labels : c .getLabels (),
147+ Annotations : map [string ]string {"encoding" : "gzip" },
148+ },
149+ },
150+ }
151+ }
152+
153+ func split (buf []byte , size int ) [][]byte {
154+ var chunk []byte
155+ chunks := make ([][]byte , 0 , len (buf )/ size + 1 )
156+ for len (buf ) >= size {
157+ chunk , buf = buf [:size ], buf [size :]
158+ chunks = append (chunks , chunk )
159+ }
160+ if len (buf ) > 0 {
161+ chunks = append (chunks , buf [:len (buf )])
162+ }
163+ return chunks
164+ }
165+
119166// Delete the state secret
120167func (c * RemoteClient ) Delete () error {
121- secretName , err := c .createSecretName ()
168+ secretList , err := c .getSecrets ()
122169 if err != nil {
123170 return err
124171 }
125172
126- err = c . deleteSecret ( secretName )
127- if err != nil {
128- if ! k8serrors . IsNotFound ( err ) {
173+ for i , _ := range secretList . Items {
174+ secretName , err := c . createSecretName ( i )
175+ if err != nil {
129176 return err
130177 }
178+
179+ err = c .deleteSecret (secretName )
180+ if err != nil {
181+ if ! k8serrors .IsNotFound (err ) {
182+ return err
183+ }
184+ }
131185 }
132186
133187 leaseName , err := c .createLeaseName ()
@@ -317,9 +371,13 @@ func (c *RemoteClient) deleteLease(name string) error {
317371 return c .kubernetesLeaseClient .Delete (name , delOps )
318372}
319373
320- func (c * RemoteClient ) createSecretName () (string , error ) {
374+ func (c * RemoteClient ) createSecretName (idx int ) (string , error ) {
321375 secretName := strings .Join ([]string {tfstateKey , c .workspace , c .nameSuffix }, "-" )
322376
377+ if idx > 0 {
378+ secretName = fmt .Sprintf ("%s-part%d" , secretName , idx )
379+ }
380+
323381 errs := validation .IsDNS1123Subdomain (secretName )
324382 if len (errs ) > 0 {
325383 k8sInfo := `
@@ -333,7 +391,7 @@ The workspace name and key must adhere to Kubernetes naming conventions.`
333391}
334392
335393func (c * RemoteClient ) createLeaseName () (string , error ) {
336- n , err := c .createSecretName ()
394+ n , err := c .createSecretName (0 )
337395 if err != nil {
338396 return "" , err
339397 }
@@ -352,14 +410,18 @@ func compressState(data []byte) ([]byte, error) {
352410 return b .Bytes (), nil
353411}
354412
355- func uncompressState (data string ) ([]byte , error ) {
356- decode , err := base64 .StdEncoding .DecodeString (data )
357- if err != nil {
358- return nil , err
413+ func uncompressState (data []string ) ([]byte , error ) {
414+ var rawData []byte
415+ for _ , chunk := range data {
416+ decode , err := base64 .StdEncoding .DecodeString (chunk )
417+ if err != nil {
418+ return nil , err
419+ }
420+ rawData = append (rawData , decode ... )
359421 }
360422
361423 b := new (bytes.Buffer )
362- gz , err := gzip .NewReader (bytes .NewReader (decode ))
424+ gz , err := gzip .NewReader (bytes .NewReader (rawData ))
363425 if err != nil {
364426 return nil , err
365427 }
0 commit comments