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