@@ -2,6 +2,8 @@ package configprovider
2
2
3
3
import (
4
4
"bytes"
5
+ "compress/gzip"
6
+ "encoding/base64"
5
7
"fmt"
6
8
"io"
7
9
"mime"
@@ -22,17 +24,39 @@ const (
22
24
nodeConfigMediaType = "application/" + api .GroupName
23
25
)
24
26
25
- type userDataConfigProvider struct {}
27
+ type userDataProvider interface {
28
+ GetUserData () ([]byte , error )
29
+ }
30
+
31
+ type imdsUserDataProvider struct {}
32
+
33
+ func (p * imdsUserDataProvider ) GetUserData () ([]byte , error ) {
34
+ return imds .GetUserData ()
35
+ }
36
+
37
+ type userDataConfigProvider struct {
38
+ userDataProvider userDataProvider
39
+ }
26
40
27
41
func NewUserDataConfigProvider () ConfigProvider {
28
- return & userDataConfigProvider {}
42
+ return & userDataConfigProvider {
43
+ userDataProvider : & imdsUserDataProvider {},
44
+ }
29
45
}
30
46
31
- func (ics * userDataConfigProvider ) Provide () (* internalapi.NodeConfig , error ) {
32
- userData , err := imds .GetUserData ()
47
+ func (p * userDataConfigProvider ) Provide () (* internalapi.NodeConfig , error ) {
48
+ userData , err := p . userDataProvider .GetUserData ()
33
49
if err != nil {
34
50
return nil , err
35
51
}
52
+ userData , err = decodeIfBase64 (userData )
53
+ if err != nil {
54
+ return nil , fmt .Errorf ("failed to decode user data: %v" , err )
55
+ }
56
+ userData , err = decompressIfGZIP (userData )
57
+ if err != nil {
58
+ return nil , fmt .Errorf ("failed to decompress user data: %v" , err )
59
+ }
36
60
// if the MIME data fails to parse as a multipart document, then fall back
37
61
// to parsing the entire userdata as the node config.
38
62
if multipartReader , err := getMIMEMultipartReader (userData ); err == nil {
@@ -85,6 +109,14 @@ func parseMultipart(userDataReader *multipart.Reader) (*internalapi.NodeConfig,
85
109
if err != nil {
86
110
return nil , err
87
111
}
112
+ nodeConfigPart , err = decodeIfBase64 (nodeConfigPart )
113
+ if err != nil {
114
+ return nil , err
115
+ }
116
+ nodeConfigPart , err = decompressIfGZIP (nodeConfigPart )
117
+ if err != nil {
118
+ return nil , err
119
+ }
88
120
decodedConfig , err := apibridge .DecodeNodeConfig (nodeConfigPart )
89
121
if err != nil {
90
122
return nil , err
@@ -102,6 +134,39 @@ func parseMultipart(userDataReader *multipart.Reader) (*internalapi.NodeConfig,
102
134
}
103
135
return config , nil
104
136
} else {
105
- return nil , fmt .Errorf ("Could not find NodeConfig within UserData" )
137
+ return nil , fmt .Errorf ("could not find NodeConfig within UserData" )
138
+ }
139
+ }
140
+
141
+ func decodeIfBase64 (data []byte ) ([]byte , error ) {
142
+ e := base64 .StdEncoding
143
+ maxDecodedLen := e .DecodedLen (len (data ))
144
+ decodedData := make ([]byte , maxDecodedLen )
145
+ decodedLen , err := e .Decode (decodedData , data )
146
+ if err != nil {
147
+ return data , nil
148
+ }
149
+ return decodedData [:decodedLen ], nil
150
+ }
151
+
152
+ // https://en.wikipedia.org/wiki/Gzip
153
+ const gzipMagicNumber = uint16 (0x1f8b )
154
+
155
+ func decompressIfGZIP (data []byte ) ([]byte , error ) {
156
+ if len (data ) < 2 {
157
+ return data , nil
158
+ }
159
+ preamble := uint16 (data [0 ])<< 8 | uint16 (data [1 ])
160
+ if preamble == gzipMagicNumber {
161
+ reader , err := gzip .NewReader (bytes .NewReader (data ))
162
+ if err != nil {
163
+ return nil , fmt .Errorf ("failed to create GZIP reader: %v" , err )
164
+ }
165
+ if decompressed , err := io .ReadAll (reader ); err != nil {
166
+ return nil , fmt .Errorf ("failed to read from GZIP reader: %v" , err )
167
+ } else {
168
+ return decompressed , nil
169
+ }
106
170
}
171
+ return data , nil
107
172
}
0 commit comments