github.com/handlerbot/terraform@v0.10.0-beta1.0.20180726153736-26b68d98f9cb/builtin/providers/terraform/data_source_state.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "log" 6 "time" 7 8 "github.com/hashicorp/terraform/backend" 9 backendinit "github.com/hashicorp/terraform/backend/init" 10 "github.com/hashicorp/terraform/config" 11 "github.com/hashicorp/terraform/helper/schema" 12 "github.com/hashicorp/terraform/terraform" 13 ) 14 15 func dataSourceRemoteState() *schema.Resource { 16 return &schema.Resource{ 17 Read: dataSourceRemoteStateRead, 18 19 Schema: map[string]*schema.Schema{ 20 "backend": { 21 Type: schema.TypeString, 22 Required: true, 23 ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) { 24 if vStr, ok := v.(string); ok && vStr == "_local" { 25 ws = append(ws, "Use of the %q backend is now officially "+ 26 "supported as %q. Please update your configuration to ensure "+ 27 "compatibility with future versions of Terraform.", 28 "_local", "local") 29 } 30 31 return 32 }, 33 }, 34 35 "config": { 36 Type: schema.TypeMap, 37 Optional: true, 38 }, 39 40 "defaults": { 41 Type: schema.TypeMap, 42 Optional: true, 43 }, 44 45 "environment": { 46 Type: schema.TypeString, 47 Optional: true, 48 Default: backend.DefaultStateName, 49 Deprecated: "Terraform environments are now called workspaces. Please use the workspace key instead.", 50 }, 51 52 "workspace": { 53 Type: schema.TypeString, 54 Optional: true, 55 Default: backend.DefaultStateName, 56 }, 57 58 "__has_dynamic_attributes": { 59 Type: schema.TypeString, 60 Optional: true, 61 }, 62 }, 63 } 64 } 65 66 func dataSourceRemoteStateRead(d *schema.ResourceData, meta interface{}) error { 67 backendType := d.Get("backend").(string) 68 69 // Get the configuration in a type we want. 70 rawConfig, err := config.NewRawConfig(d.Get("config").(map[string]interface{})) 71 if err != nil { 72 return fmt.Errorf("error initializing backend: %s", err) 73 } 74 75 // Don't break people using the old _local syntax - but note warning above 76 if backendType == "_local" { 77 log.Println(`[INFO] Switching old (unsupported) backend "_local" to "local"`) 78 backendType = "local" 79 } 80 81 // Create the client to access our remote state 82 log.Printf("[DEBUG] Initializing remote state backend: %s", backendType) 83 f := backendinit.Backend(backendType) 84 if f == nil { 85 return fmt.Errorf("Unknown backend type: %s", backendType) 86 } 87 b := f() 88 89 // Configure the backend 90 if err := b.Configure(terraform.NewResourceConfig(rawConfig)); err != nil { 91 return fmt.Errorf("error initializing backend: %s", err) 92 } 93 94 // environment is deprecated in favour of workspace. 95 // If both keys are set workspace should win. 96 name := d.Get("environment").(string) 97 if ws, ok := d.GetOk("workspace"); ok && ws != backend.DefaultStateName { 98 name = ws.(string) 99 } 100 101 state, err := b.State(name) 102 if err != nil { 103 return fmt.Errorf("error loading the remote state: %s", err) 104 } 105 if err := state.RefreshState(); err != nil { 106 return err 107 } 108 d.SetId(time.Now().UTC().String()) 109 110 outputMap := make(map[string]interface{}) 111 112 defaults := d.Get("defaults").(map[string]interface{}) 113 for key, val := range defaults { 114 outputMap[key] = val 115 } 116 117 remoteState := state.State() 118 if remoteState.Empty() { 119 log.Println("[DEBUG] empty remote state") 120 } else { 121 for key, val := range remoteState.RootModule().Outputs { 122 if val.Value != nil { 123 outputMap[key] = val.Value 124 } 125 } 126 } 127 128 mappedOutputs := remoteStateFlatten(outputMap) 129 130 for key, val := range mappedOutputs { 131 d.UnsafeSetFieldRaw(key, val) 132 } 133 134 return nil 135 }