// Configuring a backend for the first time.
Configuring a backend for the first time.
// Configuring a backend for the first time .
func (m *Meta) backend_C_r_s(c *configs.Backend, cHash int, sMgr *clistate.LocalState) (backend.Backend, tfdiags.Diagnostics) {
	b, configVal, diags := m.backendInitFromConfig(c)
	if diags.HasErrors() {
		return nil, diags
	}
	localB, localBDiags := m.Backend(&BackendOpts{ForceLocal: true})
	if localBDiags.HasErrors() {
		diags = diags.Append(localBDiags)
		return nil, diags
	}
	workspaces, err := localB.Workspaces()
	if err != nil {
		diags = diags.Append(fmt.Errorf(errBackendLocalRead, err))
		return nil, diags
	}
	var localStates []statemgr.Full
	for _, workspace := range workspaces {
		localState, err := localB.StateMgr(workspace)
		if err != nil {
			diags = diags.Append(fmt.Errorf(errBackendLocalRead, err))
			return nil, diags
		}
		if err := localState.RefreshState(); err != nil {
			diags = diags.Append(fmt.Errorf(errBackendLocalRead, err))
			return nil, diags
		}
		if localS := localState.State(); !localS.Empty() {
			log.Printf("[TRACE] Meta.Backend: will need to migrate workspace states because of existing %q workspace", workspace)
			localStates = append(localStates, localState)
		} else {
			log.Printf("[TRACE] Meta.Backend: ignoring local %q workspace because its state is empty", workspace)
		}
	}
	if len(localStates) > 0 {
		err = m.backendMigrateState(&backendMigrateOpts{
			OneType: "local",
			TwoType: c.Type,
			One:     localB,
			Two:     b,
		})
		if err != nil {
			diags = diags.Append(err)
			return nil, diags
		}
		erase := true
		if newLocalB, ok := b.(*backendLocal.Local); ok {
			if localB, ok := localB.(*backendLocal.Local); ok {
				if newLocalB.PathsConflictWith(localB) {
					erase = false
					log.Printf("[TRACE] Meta.Backend: both old and new backends share the same local state paths, so not erasing old state")
				}
			}
		}
		if erase {
			log.Printf("[TRACE] Meta.Backend: removing old state snapshots from old backend")
			for _, localState := range localStates {
				if err := localState.WriteState(nil); err != nil {
					diags = diags.Append(fmt.Errorf(errBackendMigrateLocalDelete, err))
					return nil, diags
				}
				if err := localState.PersistState(); err != nil {
					diags = diags.Append(fmt.Errorf(errBackendMigrateLocalDelete, err))
					return nil, diags
				}
			}
		}
	}
	if m.stateLock {
		stateLocker := clistate.NewLocker(context.Background(), m.stateLockTimeout, m.Ui, m.Colorize())
		if err := stateLocker.Lock(sMgr, "backend from plan"); err != nil {
			diags = diags.Append(fmt.Errorf("Error locking state: %s", err))
			return nil, diags
		}
		defer stateLocker.Unlock(nil)
	}
	configJSON, err := ctyjson.Marshal(configVal, b.ConfigSchema().ImpliedType())
	if err != nil {
		diags = diags.Append(fmt.Errorf("Can't serialize backend configuration as JSON: %s", err))
		return nil, diags
	}
	s := sMgr.State()
	if s == nil {
		s = terraform.NewState()
	}
	s.Backend = &terraform.BackendState{
		Type:      c.Type,
		ConfigRaw: json.RawMessage(configJSON),
		Hash:      uint64(cHash),
	}
	if err := sMgr.WriteState(s); err != nil {
		diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
		return nil, diags
	}
	if err := sMgr.PersistState(); err != nil {
		diags = diags.Append(fmt.Errorf(errBackendWriteSaved, err))
		return nil, diags
	}
	m.Ui.Output(m.Colorize().Color(fmt.Sprintf(
		"[reset][green]\n"+strings.TrimSpace(successBackendSet), s.Backend.Type)))
	return b, diags
}
func ( m * Meta ) backend_C_r_s ( c * configs . Backend , cHash int , sMgr * clistate . LocalState ) ( backend . Backend , tfdiags . Diagnostics ) { b , configVal , diags := m . backendInitFromConfig ( c ) if diags . HasErrors ( ) { return nil , diags } localB , localBDiags := m . Backend ( & BackendOpts { ForceLocal : true } ) if localBDiags . HasErrors ( ) { diags = diags . Append ( localBDiags ) return nil , diags } workspaces , err := localB . Workspaces ( ) if err != nil { diags = diags . Append ( fmt . Errorf ( errBackendLocalRead , err ) ) return nil , diags } var localStates [ ] statemgr . Full for _ , workspace := range workspaces { localState , err := localB . StateMgr ( workspace ) if err != nil { diags = diags . Append ( fmt . Errorf ( errBackendLocalRead , err ) ) return nil , diags } if err := localState . RefreshState ( ) ; err != nil { diags = diags . Append ( fmt . Errorf ( errBackendLocalRead , err ) ) return nil , diags } if localS := localState . State ( ) ; ! localS . Empty ( ) { log . Printf ( " " , workspace ) localStates = append ( localStates , localState ) } else { log . Printf ( " " , workspace ) } } if len ( localStates ) > 0 { err = m . backendMigrateState ( & backendMigrateOpts { OneType : " " , TwoType : c . Type , One : localB , Two : b , } ) if err != nil { diags = diags . Append ( err ) return nil , diags } erase := true if newLocalB , ok := b . ( * backendLocal . Local ) ; ok { if localB , ok := localB . ( * backendLocal . Local ) ; ok { if newLocalB . PathsConflictWith ( localB ) { erase = false log . Printf ( " " ) } } } if erase { log . Printf ( " " ) for _ , localState := range localStates { if err := localState . WriteState ( nil ) ; err != nil { diags = diags . Append ( fmt . Errorf ( errBackendMigrateLocalDelete , err ) ) return nil , diags } if err := localState . PersistState ( ) ; err != nil { diags = diags . Append ( fmt . Errorf ( errBackendMigrateLocalDelete , err ) ) return nil , diags } } } } if m . stateLock { stateLocker := clistate . NewLocker ( context . Background ( ) , m . stateLockTimeout , m . Ui , m . Colorize ( ) ) if err := stateLocker . Lock ( sMgr , " " ) ; err != nil { diags = diags . Append ( fmt . Errorf ( " " , err ) ) return nil , diags } defer stateLocker . Unlock ( nil ) } configJSON , err := ctyjson . Marshal ( configVal , b . ConfigSchema ( ) . ImpliedType ( ) ) if err != nil { diags = diags . Append ( fmt . Errorf ( " " , err ) ) return nil , diags } s := sMgr . State ( ) if s == nil { s = terraform . NewState ( ) } s . Backend = & terraform . BackendState { Type : c . Type , ConfigRaw : json . RawMessage ( configJSON ) , Hash : uint64 ( cHash ) , } if err := sMgr . WriteState ( s ) ; err != nil { diags = diags . Append ( fmt . Errorf ( errBackendWriteSaved , err ) ) return nil , diags } if err := sMgr . PersistState ( ) ; err != nil { diags = diags . Append ( fmt . Errorf ( errBackendWriteSaved , err ) ) return nil , diags } m . Ui . Output ( m . Colorize ( ) . Color ( fmt . Sprintf ( " \n " + strings . TrimSpace ( successBackendSet ) , s . Backend . Type ) ) ) return b , diags }
Configuring a backend for the first time.
Configuring a backend for the first time .
// Get the backend // Grab a purely local backend to get the local state if it exists // We only care about non-empty states. // Perform the migration // we usually remove the local state after migration to prevent // confusion, but adding a default local backend block to the config // can get us here too. Don't delete our state if the old and new paths // are the same. // We always delete the local state, unless that was our new state too. // Store the metadata in our saved state location // By now the backend is successfully configured.