// Steps returns the ordered list of GraphTransformers that must be executed // to build a complete graph. func (b *ImportGraphBuilder) Steps() []GraphTransformer { // Get the module. If we don't have one, we just use an empty tree // so that the transform still works but does nothing. mod := b.Module if mod == nil { mod = module.NewEmptyTree() } steps := []GraphTransformer{ // Create all our resources from the configuration and state &ConfigTransformerOld{Module: mod}, // Add the import steps &ImportStateTransformer{Targets: b.ImportTargets}, // Provider-related transformations &MissingProviderTransformer{Providers: b.Providers}, &ProviderTransformer{}, &DisableProviderTransformerOld{}, &PruneProviderTransformer{}, // Single root &RootTransformer{}, // Insert nodes to close opened plugin connections &CloseProviderTransformer{}, // Optimize &TransitiveReductionTransformer{}, } return steps }
func testSession(t *testing.T, test testSessionTest) { // Build the TF context ctx, err := terraform.NewContext(&terraform.ContextOpts{ State: test.State, Module: module.NewEmptyTree(), }) if err != nil { t.Fatalf("err: %s", err) } // Build the session s := &Session{ Interpolater: ctx.Interpolater(), } // Test the inputs. We purposely don't use subtests here because // the inputs don't recognize subtests, but a sequence of stateful // operations. for _, input := range test.Inputs { result, err := s.Handle(input.Input) if (err != nil) != input.Error { t.Fatalf("%q: err: %s", input.Input, err) } if err != nil { if input.ErrorContains != "" { if !strings.Contains(err.Error(), input.ErrorContains) { t.Fatalf( "%q: err should contain: %q\n\n%s", input.Input, input.ErrorContains, err) } } continue } if input.Output != "" && result != input.Output { t.Fatalf( "%q: expected:\n\n%s\n\ngot:\n\n%s", input.Input, input.Output, result) } if input.OutputContains != "" && !strings.Contains(result, input.OutputContains) { t.Fatalf( "%q: expected contains:\n\n%s\n\ngot:\n\n%s", input.Input, input.OutputContains, result) } } }
// Steps returns the ordered list of GraphTransformers that must be executed // to build a complete graph. func (b *ImportGraphBuilder) Steps() []GraphTransformer { // Get the module. If we don't have one, we just use an empty tree // so that the transform still works but does nothing. mod := b.Module if mod == nil { mod = module.NewEmptyTree() } // Custom factory for creating providers. providerFactory := func(name string, path []string) GraphNodeProvider { return &NodeApplyableProvider{ NameValue: name, PathValue: path, } } steps := []GraphTransformer{ // Create all our resources from the configuration and state &ConfigTransformerOld{Module: mod}, // Add the import steps &ImportStateTransformer{Targets: b.ImportTargets}, // Provider-related transformations &MissingProviderTransformer{Providers: b.Providers, Factory: providerFactory}, &ProviderTransformer{}, &DisableProviderTransformerOld{}, &PruneProviderTransformer{}, &AttachProviderConfigTransformer{Module: mod}, // This validates that the providers only depend on variables &ImportProviderValidateTransformer{}, // Single root &RootTransformer{}, // Optimize &TransitiveReductionTransformer{}, } return steps }
// Context returns a Terraform Context taking into account the context // options used to initialize this meta configuration. func (m *Meta) Context(copts contextOpts) (*terraform.Context, bool, error) { opts := m.contextOpts() // First try to just read the plan directly from the path given. f, err := os.Open(copts.Path) if err == nil { plan, err := terraform.ReadPlan(f) f.Close() if err == nil { // Setup our state state, statePath, err := StateFromPlan(m.statePath, m.stateOutPath, plan) if err != nil { return nil, false, fmt.Errorf("Error loading plan: %s", err) } // Set our state m.state = state // this is used for printing the saved location later if m.stateOutPath == "" { m.stateOutPath = statePath } if len(m.variables) > 0 { return nil, false, fmt.Errorf( "You can't set variables with the '-var' or '-var-file' flag\n" + "when you're applying a plan file. The variables used when\n" + "the plan was created will be used. If you wish to use different\n" + "variable values, create a new plan file.") } ctx, err := plan.Context(opts) return ctx, true, err } } // Load the statePath if not given if copts.StatePath != "" { m.statePath = copts.StatePath } // Tell the context if we're in a destroy plan / apply opts.Destroy = copts.Destroy // Store the loaded state state, err := m.State() if err != nil { return nil, false, err } // Load the root module var mod *module.Tree if copts.Path != "" { mod, err = module.NewTreeModule("", copts.Path) if err != nil { return nil, false, fmt.Errorf("Error loading config: %s", err) } } else { mod = module.NewEmptyTree() } err = mod.Load(m.moduleStorage(m.DataDir()), copts.GetMode) if err != nil { return nil, false, fmt.Errorf("Error downloading modules: %s", err) } opts.Module = mod opts.Parallelism = copts.Parallelism opts.State = state.State() ctx, err := terraform.NewContext(opts) return ctx, false, err }
// Context returns a Terraform Context taking into account the context // options used to initialize this meta configuration. func (m *Meta) Context(copts contextOpts) (*terraform.Context, bool, error) { opts := m.contextOpts() // First try to just read the plan directly from the path given. f, err := os.Open(copts.Path) if err == nil { plan, err := terraform.ReadPlan(f) f.Close() if err == nil { // Setup our state, force it to use our plan's state stateOpts := m.StateOpts() if plan != nil { stateOpts.ForceState = plan.State } // Get the state result, err := State(stateOpts) if err != nil { return nil, false, fmt.Errorf("Error loading plan: %s", err) } // Set our state m.state = result.State // this is used for printing the saved location later if m.stateOutPath == "" { m.stateOutPath = result.StatePath } if len(m.variables) > 0 { return nil, false, fmt.Errorf( "You can't set variables with the '-var' or '-var-file' flag\n" + "when you're applying a plan file. The variables used when\n" + "the plan was created will be used. If you wish to use different\n" + "variable values, create a new plan file.") } ctx, err := plan.Context(opts) return ctx, true, err } } // Load the statePath if not given if copts.StatePath != "" { m.statePath = copts.StatePath } // Tell the context if we're in a destroy plan / apply opts.Destroy = copts.Destroy // Store the loaded state state, err := m.State() if err != nil { return nil, false, err } // Load the root module var mod *module.Tree if copts.Path != "" { mod, err = module.NewTreeModule("", copts.Path) // Check for the error where we have no config files but // allow that. If that happens, clear the error. if errwrap.ContainsType(err, new(config.ErrNoConfigsFound)) && copts.PathEmptyOk { log.Printf( "[WARN] Empty configuration dir, ignoring: %s", copts.Path) err = nil mod = module.NewEmptyTree() } if err != nil { return nil, false, fmt.Errorf("Error loading config: %s", err) } } else { mod = module.NewEmptyTree() } err = mod.Load(m.moduleStorage(m.DataDir()), copts.GetMode) if err != nil { return nil, false, fmt.Errorf("Error downloading modules: %s", err) } // Validate the module right away if err := mod.Validate(); err != nil { return nil, false, err } opts.Module = mod opts.Parallelism = copts.Parallelism opts.State = state.State() ctx, err := terraform.NewContext(opts) return ctx, false, err }