github.com/cmalfait/terraform@v0.11.12-beta1/helper/resource/testing_import_state.go (about)

     1  package resource
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"reflect"
     7  	"strings"
     8  
     9  	"github.com/davecgh/go-spew/spew"
    10  	"github.com/hashicorp/terraform/terraform"
    11  )
    12  
    13  // testStepImportState runs an imort state test step
    14  func testStepImportState(
    15  	opts terraform.ContextOpts,
    16  	state *terraform.State,
    17  	step TestStep) (*terraform.State, error) {
    18  	// Determine the ID to import
    19  	var importId string
    20  	switch {
    21  	case step.ImportStateIdFunc != nil:
    22  		var err error
    23  		importId, err = step.ImportStateIdFunc(state)
    24  		if err != nil {
    25  			return state, err
    26  		}
    27  	case step.ImportStateId != "":
    28  		importId = step.ImportStateId
    29  	default:
    30  		resource, err := testResource(step, state)
    31  		if err != nil {
    32  			return state, err
    33  		}
    34  		importId = resource.Primary.ID
    35  	}
    36  
    37  	importPrefix := step.ImportStateIdPrefix
    38  	if importPrefix != "" {
    39  		importId = fmt.Sprintf("%s%s", importPrefix, importId)
    40  	}
    41  
    42  	// Setup the context. We initialize with an empty state. We use the
    43  	// full config for provider configurations.
    44  	mod, err := testModule(opts, step)
    45  	if err != nil {
    46  		return state, err
    47  	}
    48  
    49  	opts.Module = mod
    50  	opts.State = terraform.NewState()
    51  	ctx, err := terraform.NewContext(&opts)
    52  	if err != nil {
    53  		return state, err
    54  	}
    55  
    56  	// Do the import!
    57  	newState, err := ctx.Import(&terraform.ImportOpts{
    58  		// Set the module so that any provider config is loaded
    59  		Module: mod,
    60  
    61  		Targets: []*terraform.ImportTarget{
    62  			&terraform.ImportTarget{
    63  				Addr: step.ResourceName,
    64  				ID:   importId,
    65  			},
    66  		},
    67  	})
    68  	if err != nil {
    69  		log.Printf("[ERROR] Test: ImportState failure: %s", err)
    70  		return state, err
    71  	}
    72  
    73  	// Go through the new state and verify
    74  	if step.ImportStateCheck != nil {
    75  		var states []*terraform.InstanceState
    76  		for _, r := range newState.RootModule().Resources {
    77  			if r.Primary != nil {
    78  				states = append(states, r.Primary)
    79  			}
    80  		}
    81  		if err := step.ImportStateCheck(states); err != nil {
    82  			return state, err
    83  		}
    84  	}
    85  
    86  	// Verify that all the states match
    87  	if step.ImportStateVerify {
    88  		new := newState.RootModule().Resources
    89  		old := state.RootModule().Resources
    90  		for _, r := range new {
    91  			// Find the existing resource
    92  			var oldR *terraform.ResourceState
    93  			for _, r2 := range old {
    94  				if r2.Primary != nil && r2.Primary.ID == r.Primary.ID && r2.Type == r.Type {
    95  					oldR = r2
    96  					break
    97  				}
    98  			}
    99  			if oldR == nil {
   100  				return state, fmt.Errorf(
   101  					"Failed state verification, resource with ID %s not found",
   102  					r.Primary.ID)
   103  			}
   104  
   105  			// Compare their attributes
   106  			actual := make(map[string]string)
   107  			for k, v := range r.Primary.Attributes {
   108  				actual[k] = v
   109  			}
   110  			expected := make(map[string]string)
   111  			for k, v := range oldR.Primary.Attributes {
   112  				expected[k] = v
   113  			}
   114  
   115  			// Remove fields we're ignoring
   116  			for _, v := range step.ImportStateVerifyIgnore {
   117  				for k, _ := range actual {
   118  					if strings.HasPrefix(k, v) {
   119  						delete(actual, k)
   120  					}
   121  				}
   122  				for k, _ := range expected {
   123  					if strings.HasPrefix(k, v) {
   124  						delete(expected, k)
   125  					}
   126  				}
   127  			}
   128  
   129  			if !reflect.DeepEqual(actual, expected) {
   130  				// Determine only the different attributes
   131  				for k, v := range expected {
   132  					if av, ok := actual[k]; ok && v == av {
   133  						delete(expected, k)
   134  						delete(actual, k)
   135  					}
   136  				}
   137  
   138  				spewConf := spew.NewDefaultConfig()
   139  				spewConf.SortKeys = true
   140  				return state, fmt.Errorf(
   141  					"ImportStateVerify attributes not equivalent. Difference is shown below. Top is actual, bottom is expected."+
   142  						"\n\n%s\n\n%s",
   143  					spewConf.Sdump(actual), spewConf.Sdump(expected))
   144  			}
   145  		}
   146  	}
   147  
   148  	// Return the old state (non-imported) so we don't change anything.
   149  	return state, nil
   150  }