@@ -2,7 +2,6 @@ package controllers
2
2
3
3
import (
4
4
"context"
5
- "encoding/json"
6
5
"fmt"
7
6
"sort"
8
7
"strings"
@@ -75,6 +74,9 @@ func (r *TerraformReconciler) processOutputs(ctx context.Context, runnerClient r
75
74
log := ctrl .LoggerFrom (ctx )
76
75
objectKey := types.NamespacedName {Namespace : terraform .Namespace , Name : terraform .Name }
77
76
77
+ // OutputMeta has
78
+ // 1. type
79
+ // 2. value
78
80
outputs := map [string ]tfexec.OutputMeta {}
79
81
var err error
80
82
terraform , err = r .obtainOutputs (ctx , terraform , tfInstance , runnerClient , revision , & outputs )
@@ -133,81 +135,37 @@ func (r *TerraformReconciler) writeOutput(ctx context.Context, terraform infrav1
133
135
wots := terraform .Spec .WriteOutputsToSecret
134
136
data := map [string ][]byte {}
135
137
136
- // if not specified .spec.writeOutputsToSecret.outputs,
137
- // then it means export all outputs
138
+ var filteredOutputs map [string ]tfexec.OutputMeta
138
139
if len (wots .Outputs ) == 0 {
139
- for output , v := range outputs {
140
- ct , err := ctyjson .UnmarshalType (v .Type )
141
- if err != nil {
142
- return terraform , err
143
- }
144
- // if it's a string, we can embed it directly into Secret's data
145
- switch ct {
146
- case cty .String :
147
- cv , err := ctyjson .Unmarshal (v .Value , ct )
148
- if err != nil {
149
- return terraform , err
150
- }
151
- data [output ] = []byte (cv .AsString ())
152
- // there's no need to unmarshal and convert to []byte
153
- // we'll just pass the []byte directly from OutputMeta Value
154
- case cty .Number , cty .Bool :
155
- data [output ] = v .Value
156
- default :
157
- outputBytes , err := json .Marshal (v .Value )
158
- if err != nil {
159
- return terraform , err
160
- }
161
- data [output ] = outputBytes
162
- }
163
- }
140
+ filteredOutputs = outputs
164
141
} else {
165
- // filter only defined output
166
- // output maybe contain mapping output:mapped_name
167
- for _ , outputMapping := range wots .Outputs {
168
- parts := strings .SplitN (outputMapping , ":" , 2 )
169
- var output string
170
- var mappedTo string
171
- if len (parts ) == 1 {
172
- output = parts [0 ]
173
- mappedTo = parts [0 ]
174
- // no mapping
175
- } else if len (parts ) == 2 {
176
- output = parts [0 ]
177
- mappedTo = parts [1 ]
178
- } else {
179
- log .Error (fmt .Errorf ("invalid mapping format" ), outputMapping )
180
- continue
181
- }
142
+ if result , err := filterOutputs (outputs , wots .Outputs ); err != nil {
143
+ return infrav1 .TerraformNotReady (
144
+ terraform ,
145
+ revision ,
146
+ infrav1 .OutputsWritingFailedReason ,
147
+ err .Error (),
148
+ ), err
149
+ } else {
150
+ filteredOutputs = result
151
+ }
152
+ }
182
153
183
- v , exist := outputs [ output ]
184
- if ! exist {
185
- log . Error ( fmt . Errorf ( "output not found" ), output )
186
- continue
187
- }
154
+ for outputOrAlias , outputMeta := range filteredOutputs {
155
+ ct , err := ctyjson . UnmarshalType ( outputMeta . Type )
156
+ if err != nil {
157
+ return terraform , err
158
+ }
188
159
189
- ct , err := ctyjson .UnmarshalType (v .Type )
160
+ if ct == cty .String {
161
+ cv , err := ctyjson .Unmarshal (outputMeta .Value , ct )
190
162
if err != nil {
191
163
return terraform , err
192
164
}
193
- switch ct {
194
- case cty .String :
195
- cv , err := ctyjson .Unmarshal (v .Value , ct )
196
- if err != nil {
197
- return terraform , err
198
- }
199
- data [mappedTo ] = []byte (cv .AsString ())
200
- // there's no need to unmarshal and convert to []byte
201
- // we'll just pass the []byte directly from OutputMeta Value
202
- case cty .Number , cty .Bool :
203
- data [mappedTo ] = v .Value
204
- default :
205
- outputBytes , err := json .Marshal (v .Value )
206
- if err != nil {
207
- return terraform , err
208
- }
209
- data [mappedTo ] = outputBytes
210
- }
165
+ data [outputOrAlias ] = []byte (cv .AsString ())
166
+ } else {
167
+ data [outputOrAlias ] = outputMeta .Value
168
+ data [outputOrAlias + ".type" ] = outputMeta .Type
211
169
}
212
170
}
213
171
@@ -243,3 +201,41 @@ func (r *TerraformReconciler) writeOutput(ctx context.Context, terraform infrav1
243
201
244
202
return infrav1 .TerraformOutputsWritten (terraform , revision , "Outputs written" ), nil
245
203
}
204
+
205
+ func filterOutputs (outputs map [string ]tfexec.OutputMeta , outputsToWrite []string ) (map [string ]tfexec.OutputMeta , error ) {
206
+ if outputs == nil || outputsToWrite == nil {
207
+ return nil , fmt .Errorf ("input maps or outputsToWrite slice cannot be nil" )
208
+ }
209
+
210
+ filteredOutputs := make (map [string ]tfexec.OutputMeta )
211
+ for _ , outputMapping := range outputsToWrite {
212
+ if len (outputMapping ) == 0 {
213
+ return nil , fmt .Errorf ("output mapping cannot be empty" )
214
+ }
215
+
216
+ // parse output mapping (output[:alias])
217
+ parts := strings .SplitN (outputMapping , ":" , 2 )
218
+ var (
219
+ output string
220
+ alias string
221
+ )
222
+ if len (parts ) == 1 {
223
+ output = parts [0 ]
224
+ alias = parts [0 ]
225
+ } else if len (parts ) == 2 {
226
+ output = parts [0 ]
227
+ alias = parts [1 ]
228
+ } else {
229
+ return nil , fmt .Errorf ("invalid output mapping format: %s" , outputMapping )
230
+ }
231
+
232
+ outputMeta , exist := outputs [output ]
233
+ if ! exist {
234
+ return nil , fmt .Errorf ("output not found: %s" , output )
235
+ }
236
+
237
+ filteredOutputs [alias ] = outputMeta
238
+ }
239
+
240
+ return filteredOutputs , nil
241
+ }
0 commit comments