// 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
}
Example #2
0
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
}
Example #4
0
// 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
}
Example #5
0
// 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
}