11package types
22
33import (
4+ "encoding/json"
45 "fmt"
56
6- backend "github.com/hashicorp/terraform/backend/init"
7+ "github.com/hashicorp/terraform/addrs"
8+ "github.com/hashicorp/terraform/backend"
9+ binit "github.com/hashicorp/terraform/backend/init"
10+ "github.com/hashicorp/terraform/providers"
11+ "github.com/hashicorp/terraform/states"
12+ "github.com/hashicorp/terraform/states/statemgr"
13+ "github.com/mcuadros/ascode/terraform"
14+ "github.com/qri-io/starlib/util"
715 "go.starlark.net/starlark"
816)
917
1018func init () {
11- backend .Init (nil )
19+ binit .Init (nil )
1220}
1321
14- func BuiltinBackend () starlark.Value {
22+ func BuiltinBackend (pm * terraform. PluginManager ) starlark.Value {
1523 return starlark .NewBuiltin ("backend" , func (_ * starlark.Thread , _ * starlark.Builtin , args starlark.Tuple , kwargs []starlark.Tuple ) (starlark.Value , error ) {
1624 var name starlark.String
1725 switch len (args ) {
@@ -25,7 +33,7 @@ func BuiltinBackend() starlark.Value {
2533 return nil , fmt .Errorf ("unexpected positional arguments count" )
2634 }
2735
28- p , err := MakeBackend (name .GoString ())
36+ p , err := MakeBackend (pm , name .GoString ())
2937 if err != nil {
3038 return nil , err
3139 }
@@ -35,16 +43,251 @@ func BuiltinBackend() starlark.Value {
3543}
3644
3745type Backend struct {
46+ pm * terraform.PluginManager
47+ b backend.Backend
3848 * Resource
3949}
4050
41- func MakeBackend (name string ) (* Backend , error ) {
42- fn := backend .Backend (name )
51+ func MakeBackend (pm * terraform. PluginManager , name string ) (* Backend , error ) {
52+ fn := binit .Backend (name )
4353 if fn == nil {
4454 return nil , fmt .Errorf ("unable to find backend %q" , name )
4555 }
4656
57+ b := fn ()
58+
4759 return & Backend {
48- Resource : MakeResource (name , "" , BackendKind , fn ().ConfigSchema (), nil , nil ),
60+ pm : pm ,
61+ b : b ,
62+ Resource : MakeResource (name , "" , BackendKind , b .ConfigSchema (), nil , nil ),
4963 }, nil
5064}
65+
66+ func (c * Backend ) Attr (name string ) (starlark.Value , error ) {
67+ switch name {
68+ case "state" :
69+ return starlark .NewBuiltin ("state" , c .state ), nil
70+ }
71+
72+ return c .Resource .Attr (name )
73+ }
74+
75+ func (b * Backend ) getStateMgr (workspace string ) (statemgr.Full , error ) {
76+ values , diag := b .b .PrepareConfig (b .values .Cty (b .b .ConfigSchema ()))
77+ if err := diag .Err (); err != nil {
78+ return nil , err
79+ }
80+
81+ diag = b .b .Configure (values )
82+ if err := diag .Err (); err != nil {
83+ return nil , err
84+ }
85+
86+ workspaces , err := b .b .Workspaces ()
87+ if err != nil {
88+ return nil , err
89+ }
90+
91+ var found bool
92+ for _ , w := range workspaces {
93+ if w == workspace {
94+ found = true
95+ break
96+ }
97+ }
98+
99+ if ! found {
100+ return nil , fmt .Errorf ("unable to find %q workspace" , workspace )
101+ }
102+
103+ return b .b .StateMgr (workspace )
104+ }
105+
106+ func (b * Backend ) state (_ * starlark.Thread , _ * starlark.Builtin , args starlark.Tuple , kwargs []starlark.Tuple ) (starlark.Value , error ) {
107+
108+ workspace := "default"
109+ module := ""
110+
111+ err := starlark .UnpackArgs ("state" , args , kwargs , "module?" , & module , "workspace?" , & workspace )
112+ if err != nil {
113+ return nil , err
114+ }
115+
116+ sm , err := b .getStateMgr (workspace )
117+ if err != nil {
118+ return nil , err
119+ }
120+
121+ if err := sm .RefreshState (); err != nil {
122+ return nil , err
123+ }
124+
125+ state := sm .State ()
126+ if state == nil {
127+ return starlark .None , nil
128+ }
129+
130+ return MakeState (b .pm , module , state )
131+
132+ }
133+
134+ type State struct {
135+ * AttrDict
136+ pm * terraform.PluginManager
137+ }
138+
139+ func MakeState (pm * terraform.PluginManager , module string , state * states.State ) (* State , error ) {
140+ var mod * states.Module
141+ for _ , m := range state .Modules {
142+ if m .Addr .String () == module {
143+ mod = m
144+ }
145+ }
146+
147+ if mod == nil {
148+ return nil , fmt .Errorf ("unable to find module with addr %q" , module )
149+ }
150+
151+ s := & State {
152+ AttrDict : & AttrDict {starlark .NewDict (0 )},
153+ pm : pm ,
154+ }
155+ return s , s .initialize (state , mod )
156+ }
157+
158+ func (s * State ) initialize (state * states.State , mod * states.Module ) error {
159+ providers := make (map [string ]* Provider , 0 )
160+ addrs := state .ProviderAddrs ()
161+ for _ , addr := range addrs {
162+ typ := addr .ProviderConfig .Type .Type
163+ p , err := MakeProvider (s .pm , typ , "" , addr .ProviderConfig .Alias )
164+ if err != nil {
165+ return err
166+ }
167+
168+ providers [addr .ProviderConfig .String ()] = p
169+ }
170+
171+ for _ , r := range mod .Resources {
172+ provider := r .ProviderConfig .String ()
173+ if err := s .initializeResource (providers [provider ], r ); err != nil {
174+ return err
175+ }
176+ }
177+
178+ return nil
179+ }
180+
181+ func (s * State ) initializeResource (p * Provider , r * states.Resource ) error {
182+ typ := r .Addr .Type
183+ name := r .Addr .Name
184+
185+ mode := addrsResourceModeString (r .Addr .Mode )
186+
187+ var schema providers.Schema
188+ switch r .Addr .Mode {
189+ case addrs .DataResourceMode :
190+ schema = p .dataSources .schemas [typ ]
191+ case addrs .ManagedResourceMode :
192+ schema = p .resources .schemas [typ ]
193+ default :
194+ return fmt .Errorf ("invalid resource type" )
195+ }
196+
197+ multi := r .EachMode != states .NoEach
198+ for _ , instance := range r .Instances {
199+ r := MakeResource (name , typ , ResourceKind , schema .Block , p , p .Resource )
200+
201+ var val interface {}
202+ if err := json .Unmarshal (instance .Current .AttrsJSON , & val ); err != nil {
203+ return err
204+ }
205+
206+ values , _ := util .Marshal (val )
207+ if err := r .LoadDict (values .(* starlark.Dict )); err != nil {
208+ return err
209+ }
210+
211+ if err := s .set (mode , typ , name , r , multi ); err != nil {
212+ return err
213+ }
214+ }
215+
216+ return nil
217+ }
218+
219+ func addrsResourceModeString (m addrs.ResourceMode ) string {
220+ switch m {
221+ case addrs .ManagedResourceMode :
222+ return "resource"
223+ case addrs .DataResourceMode :
224+ return "data"
225+ }
226+
227+ return ""
228+ }
229+ func (s * State ) set (mode , typ , name string , r * Resource , multi bool ) error {
230+ p := starlark .String (r .provider .name )
231+ m := starlark .String (mode )
232+ t := starlark .String (typ [len (r .provider .name )+ 1 :])
233+ n := starlark .String (name )
234+
235+ if _ , ok , _ := s .Get (p ); ! ok {
236+ s .SetKey (p , NewAttrDict ())
237+ }
238+
239+ providers , _ , _ := s .Get (p )
240+ if _ , ok , _ := providers .(* AttrDict ).Get (m ); ! ok {
241+ providers .(* AttrDict ).SetKey (m , NewAttrDict ())
242+ }
243+
244+ modes , _ , _ := providers .(* AttrDict ).Get (m )
245+ if _ , ok , _ := modes .(* AttrDict ).Get (t ); ! ok {
246+ modes .(* AttrDict ).SetKey (t , NewAttrDict ())
247+ }
248+
249+ resources , _ , _ := modes .(* AttrDict ).Get (t )
250+
251+ if ! multi {
252+ return resources .(* AttrDict ).SetKey (n , r )
253+ }
254+
255+ if _ , ok , _ := resources .(* AttrDict ).Get (n ); ! ok {
256+ resources .(* AttrDict ).SetKey (n , starlark .NewList (nil ))
257+ }
258+
259+ instances , _ , _ := resources .(* AttrDict ).Get (n )
260+ if err := instances .(* starlark.List ).Append (r ); err != nil {
261+ return err
262+ }
263+
264+ return nil
265+ }
266+
267+ type AttrDict struct {
268+ * starlark.Dict
269+ }
270+
271+ func NewAttrDict () * AttrDict {
272+ return & AttrDict {Dict : starlark .NewDict (0 )}
273+ }
274+
275+ // Attr honors the starlark.Attr interface.
276+ func (d * AttrDict ) Attr (name string ) (starlark.Value , error ) {
277+ v , _ , err := d .Get (starlark .String (name ))
278+ if err != nil {
279+ return starlark .None , err
280+ }
281+
282+ return v , nil
283+ }
284+
285+ // AttrNames honors the starlark.HasAttrs interface.
286+ func (d * AttrDict ) AttrNames () []string {
287+ var names []string
288+ for _ , k := range d .Keys () {
289+ names = append (names , k .(starlark.String ).GoString ())
290+ }
291+
292+ return names
293+ }
0 commit comments