github.com/tompao/terraform@v0.6.10-0.20180215233341-e41b29d0961b/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 backend := 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 backend == "_local" { 77 log.Println(`[INFO] Switching old (unsupported) backend "_local" to "local"`) 78 backend = "local" 79 } 80 81 // Create the client to access our remote state 82 log.Printf("[DEBUG] Initializing remote state backend: %s", backend) 83 f := backendinit.Backend(backend) 84 if f == nil { 85 return fmt.Errorf("Unknown backend type: %s", backend) 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 { 98 name = ws.(string) 99 } 100 state, err := b.State(name) 101 if err != nil { 102 return fmt.Errorf("error loading the remote state: %s", err) 103 } 104 if err := state.RefreshState(); err != nil { 105 return err 106 } 107 d.SetId(time.Now().UTC().String()) 108 109 outputMap := make(map[string]interface{}) 110 111 defaults := d.Get("defaults").(map[string]interface{}) 112 for key, val := range defaults { 113 outputMap[key] = val 114 } 115 116 remoteState := state.State() 117 if remoteState.Empty() { 118 log.Println("[DEBUG] empty remote state") 119 } else { 120 for key, val := range remoteState.RootModule().Outputs { 121 outputMap[key] = val.Value 122 } 123 } 124 125 mappedOutputs := remoteStateFlatten(outputMap) 126 127 for key, val := range mappedOutputs { 128 d.UnsafeSetFieldRaw(key, val) 129 } 130 131 return nil 132 }